]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
terminal modules autoloading
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 25 Dec 2009 02:37:20 +0000 (03:37 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 25 Dec 2009 02:37:20 +0000 (03:37 +0100)
Makefile.in
commands/terminal.c
genmk.rb
genterminallist.sh [new file with mode: 0644]
include/grub/normal.h
include/grub/term.h
normal/main.c
normal/term.c

index b28b660da59a1b815b8c810baa4e8942c6e06161..413c6a59dde23783bd2b5ed93e0a4651495c135f 100644 (file)
@@ -169,7 +169,7 @@ endif
 ### General targets.
 
 CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA) po/*.mo
-pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst
+pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst
 moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep.awk
        cat $(DEFSYMFILES) /dev/null \
          | $(AWK) -f $(srcdir)/genmoddep.awk $(UNDSYMFILES) > $@ \
@@ -187,6 +187,9 @@ partmap.lst: $(PARTMAPFILES)
 handler.lst: $(HANDLERFILES)
        cat $^ /dev/null | sort > $@
 
+terminal.lst: $(TERMINALFILES)
+       cat $^ /dev/null | sort > $@
+
 parttool.lst: $(PARTTOOLFILES)
        cat $^ /dev/null | sort | uniq > $@
 
index a667825f46076b7a74db72ea821a9b4d0f8ff77c..5befecd318037b5b98e0c1c6c45e9c79c14d7532 100644 (file)
 #include <grub/i18n.h>
 #include <grub/misc.h>
 
+struct grub_term_autoload *grub_term_input_autoload = NULL;
+struct grub_term_autoload *grub_term_output_autoload = NULL;
+
 grub_err_t
 grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)),
                         int argc, char **args)
 {
   int i;
   grub_term_input_t term;
+  struct grub_term_autoload *aut;
 
   if (argc == 0)
     {
@@ -39,6 +43,20 @@ grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)),
       grub_puts_ (N_ ("Available input terminals:"));
       FOR_DISABLED_TERM_INPUTS(term)
        grub_printf ("%s ", term->name);
+      /* This is quadratic but we don't expect mode than 30 terminal
+        modules ever.  */
+      for (aut = grub_term_input_autoload; aut; aut = aut->next)
+       {
+         FOR_DISABLED_TERM_INPUTS(term)
+           if (grub_strcmp (term->name, aut->name) == 0)
+             break;
+         if (!term)
+           FOR_ACTIVE_TERM_INPUTS(term)
+             if (grub_strcmp (term->name, aut->name) == 0)
+               break;
+         if (!term)
+           grub_printf ("%s ", aut->name);
+       }
       grub_printf ("\n");
       return GRUB_ERR_NONE;
     }
@@ -53,16 +71,36 @@ grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)),
 
   for (; i < argc; i++)
     {
-      FOR_DISABLED_TERM_INPUTS(term)
-       if (grub_strcmp (args[i], term->name) == 0)
-         break;
-      if (term == 0)
-       FOR_ACTIVE_TERM_INPUTS(term)
-         if (grub_strcmp (args[i], term->name) == 0)
+      int again = 0;
+      while (1)
+       {
+         FOR_DISABLED_TERM_INPUTS(term)
+           if (grub_strcmp (args[i], term->name) == 0)
+             break;
+         if (term == 0)
+           FOR_ACTIVE_TERM_INPUTS(term)
+             if (grub_strcmp (args[i], term->name) == 0)
+               break;
+         if (term)
            break;
-      if (term == 0)
-       return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n",
-                          args[i]);
+         if (again)
+           return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n",
+                              args[i]);
+         for (aut = grub_term_input_autoload; aut; aut = aut->next)
+           if (grub_strcmp (args[i], aut->name) == 0)
+             {
+               grub_dl_t mod;
+               mod = grub_dl_load (aut->modname);
+               if (mod)
+                 grub_dl_ref (mod);
+               grub_errno = GRUB_ERR_NONE;
+               break;
+             }
+         if (!aut)
+           return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n",
+                              args[i]);
+         again = 1;
+       }
     }
 
   if (grub_strcmp (args[0], "--append") == 0)
@@ -151,6 +189,7 @@ grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)),
 {
   int i;
   grub_term_output_t term;
+  struct grub_term_autoload *aut;
 
   if (argc == 0)
     {
@@ -161,6 +200,20 @@ grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)),
       grub_puts_ (N_ ("Available output terminals:"));
       FOR_DISABLED_TERM_OUTPUTS(term)
        grub_printf ("%s ", term->name);
+      /* This is quadratic but we don't expect mode than 30 terminal
+        modules ever.  */
+      for (aut = grub_term_output_autoload; aut; aut = aut->next)
+       {
+         FOR_DISABLED_TERM_OUTPUTS(term)
+           if (grub_strcmp (term->name, aut->name) == 0)
+             break;
+         if (!term)
+           FOR_ACTIVE_TERM_OUTPUTS(term)
+             if (grub_strcmp (term->name, aut->name) == 0)
+               break;
+         if (!term)
+           grub_printf ("%s ", aut->name);
+       }
       grub_printf ("\n");
       return GRUB_ERR_NONE;
     }
@@ -175,16 +228,36 @@ grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)),
 
   for (; i < argc; i++)
     {
-      FOR_DISABLED_TERM_OUTPUTS(term)
-       if (grub_strcmp (args[i], term->name) == 0)
-         break;
-      if (term == 0)
-       FOR_ACTIVE_TERM_OUTPUTS(term)
-         if (grub_strcmp (args[i], term->name) == 0)
+      int again = 0;
+      while (1)
+       {
+         FOR_DISABLED_TERM_OUTPUTS(term)
+           if (grub_strcmp (args[i], term->name) == 0)
+             break;
+         if (term == 0)
+           FOR_ACTIVE_TERM_OUTPUTS(term)
+             if (grub_strcmp (args[i], term->name) == 0)
+               break;
+         if (term)
            break;
-      if (term == 0)
-       return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n",
-                          args[i]);
+         if (again)
+           return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n",
+                              args[i]);
+         for (aut = grub_term_output_autoload; aut; aut = aut->next)
+           if (grub_strcmp (args[i], aut->name) == 0)
+             {
+               grub_dl_t mod;
+               mod = grub_dl_load (aut->modname);
+               if (mod)
+                 grub_dl_ref (mod);
+               grub_errno = GRUB_ERR_NONE;
+               break;
+             }
+         if (!aut)
+           return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminal '%s'\n",
+                              args[i]);
+         again = 1;
+       }
     }
 
   if (grub_strcmp (args[0], "--append") == 0)
index b3dbe867811d36347d7567039ebb84d496284d8c..43eaef150155729d627502a7e6dff4143dc9c7c1 100644 (file)
--- a/genmk.rb
+++ b/genmk.rb
@@ -192,6 +192,7 @@ endif
       fs = 'fs-' + obj.suffix('lst')
       partmap = 'partmap-' + obj.suffix('lst')
       handler = 'handler-' + obj.suffix('lst')
+      terminal = 'terminal-' + obj.suffix('lst')
       parttool = 'parttool-' + obj.suffix('lst')
       video = 'video-' + obj.suffix('lst')
       dep = deps[i]
@@ -213,6 +214,7 @@ FSFILES += #{fs}
 PARTTOOLFILES += #{parttool}
 PARTMAPFILES += #{partmap}
 HANDLERFILES += #{handler}
+TERMINALFILES += #{terminal}
 VIDEOFILES += #{video}
 
 #{command}: #{src} $(#{src}_DEPENDENCIES) gencmdlist.sh
@@ -240,6 +242,11 @@ VIDEOFILES += #{video}
          $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
          | sh $(srcdir)/genhandlerlist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1)
 
+#{terminal}: #{src} $(#{src}_DEPENDENCIES) genterminlist.sh
+       set -e; \
+         $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
+         | sh $(srcdir)/genterminallist.sh #{symbolic_name} > $@ || (rm -f $@; exit 1)
+
 #{video}: #{src} $(#{src}_DEPENDENCIES) genvideolist.sh
        set -e; \
          $(TARGET_CC) -I#{dir} -I$(srcdir)/#{dir} $(TARGET_CPPFLAGS) #{extra_flags} $(TARGET_#{flag}) $(#{prefix}_#{flag}) -E $< \
diff --git a/genterminallist.sh b/genterminallist.sh
new file mode 100644 (file)
index 0000000..eb0de0c
--- /dev/null
@@ -0,0 +1,22 @@
+#! /bin/sh
+#
+# Copyright (C) 2009  Free Software Foundation, Inc.
+#
+# This script is free software; the author
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# Read source code from stdin and detect command names.
+
+module=$1
+
+grep -v "^#" | sed -n \
+ -e "/grub_term_register_input *( *\"/{s/.*( *\"\([^\"]*\)\".*/i\1: $module/;p;}" \
+ -e "/grub_term_register_input_active *( *\"/{s/.*( *\"\([^\"]*\)\".*/i\1: $module/;p;}" \
+ -e "/grub_term_register_output *( *\"/{s/.*( *\"\([^\"]*\)\".*/o\1: $module/;p;}" \
+ -e "/grub_term_register_output_active *( *\"/{s/.*( *\"\([^\"]*\)\".*/o\1: $module/;p;}"
index 91457fc09a80ba5e6fa78bde562887c6ec5f8d12..af8e00a71740aa67db775f8c0a6aaf494a2c2500 100644 (file)
@@ -103,6 +103,8 @@ void read_fs_list (void);
 
 void read_crypto_list (void);
 
+void read_terminal_list (void);
+
 void grub_set_more (int onoff);
 
 #ifdef GRUB_UTIL
index e8cf727beb39fc3cc5347a1891f66da8fe8d2cca..922ccb2d2b09450865482d77b684e46620e101b6 100644 (file)
@@ -395,6 +395,16 @@ grub_term_getcolor (struct grub_term_output *term,
 
 extern void (*EXPORT_VAR (grub_newline_hook)) (void);
 
+struct grub_term_autoload
+{
+  struct grub_term_autoload *next;
+  char *name;
+  char *modname;
+};
+
+extern struct grub_term_autoload *grub_term_input_autoload;
+extern struct grub_term_autoload *grub_term_output_autoload;
+
 /* For convenience.  */
 #define GRUB_TERM_ASCII_CHAR(c)        ((c) & 0xff)
 
index b4af09be994bb406438e71a1605a07759103b53b..3ee4d295dda5daa55f79a501ee2570676b5a7056 100644 (file)
@@ -443,6 +443,7 @@ grub_normal_execute (const char *config, int nested, int batch)
   read_fs_list ();
   read_handler_list ();
   read_crypto_list ();
+  read_terminal_list ();
   grub_command_execute ("parser.grub", 0, 0);
 
   reader_nested = nested;
index 5a8e9cffc815667a9451998cacc6e6ac69c7e5fe..b099ae84c6d1267f1355b38b0cd666a1e6ddd1a1 100644 (file)
 #include <grub/term.h>
 #include <grub/misc.h>
 #include <grub/mm.h>
+#include <grub/file.h>
+#include <grub/dl.h>
+#include <grub/env.h>
+#include <grub/normal.h>
 
 /* The amount of lines counted by the pager.  */
 static unsigned grub_more_lines;
@@ -127,3 +131,122 @@ grub_term_restore_pos (grub_uint16_t *pos)
     ptr++;
   }
 }
+
+static void 
+grub_terminal_autoload_free (void)
+{
+  struct grub_term_autoload *cur, *next;
+  unsigned i;
+  for (i = 0; i < 2; i++)
+    for (cur = i ? grub_term_input_autoload : grub_term_output_autoload;
+        cur; cur = next)
+      {
+       next = cur->next;
+       grub_free (cur->name);
+       grub_free (cur->modname);
+       grub_free (cur);
+      }
+  grub_term_input_autoload = NULL;
+  grub_term_output_autoload = NULL;
+}
+
+
+/* Read the file terminal.lst for auto-loading.  */
+void
+read_terminal_list (void)
+{
+  const char *prefix;
+  char *filename;
+  grub_file_t file;
+  char *buf = NULL;
+
+  prefix = grub_env_get ("prefix");
+  if (!prefix)
+    {
+      grub_errno = GRUB_ERR_NONE;
+      return;
+    }
+  
+  filename = grub_malloc (grub_strlen (prefix) + sizeof ("/crypto.lst"));
+  if (!filename)
+    {
+      grub_errno = GRUB_ERR_NONE;
+      return;
+    }
+
+  grub_sprintf (filename, "%s/terminal.lst", prefix);
+  file = grub_file_open (filename);
+  if (!file)
+    {
+      grub_errno = GRUB_ERR_NONE;
+      return;
+    }
+
+  /* Override previous terminal.lst.  */
+  grub_terminal_autoload_free ();
+
+  for (;; grub_free (buf))
+    {
+      char *p, *name;
+      struct grub_term_autoload *cur;
+      struct grub_term_autoload **target = NULL;
+      
+      buf = grub_file_getline (file);
+       
+      if (! buf)
+       break;
+
+      switch (buf[0])
+       {
+       case 'i':
+         target = &grub_term_input_autoload;
+         break;
+
+       case 'o':
+         target = &grub_term_output_autoload;
+         break;
+       }
+      if (!target)
+       continue;
+      
+      name = buf + 1;
+            
+      p = grub_strchr (name, ':');
+      if (! p)
+       continue;
+      
+      *p = '\0';
+      while (*++p == ' ')
+       ;
+
+      cur = grub_malloc (sizeof (*cur));
+      if (!cur)
+       {
+         grub_errno = GRUB_ERR_NONE;
+         continue;
+       }
+      
+      cur->name = grub_strdup (name);
+      if (! name)
+       {
+         grub_errno = GRUB_ERR_NONE;
+         grub_free (cur);
+         continue;
+       }
+       
+      cur->modname = grub_strdup (p);
+      if (! cur->modname)
+       {
+         grub_errno = GRUB_ERR_NONE;
+         grub_free (cur);
+         grub_free (cur->name);
+         continue;
+       }
+      cur->next = *target;
+      *target = cur;
+    }
+  
+  grub_file_close (file);
+
+  grub_errno = GRUB_ERR_NONE;
+}