grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[rfc] User definable terminfo support


From: Omniflux
Subject: [rfc] User definable terminfo support
Date: Tue, 03 Jan 2006 15:20:03 -0700
User-agent: Mozilla Thunderbird 1.0.7 (Windows/20050923)

This code is incomplete, but I want to get some feedback from you, Marco, to ensure I am going down the correct path.

Is there a reason there is not a way to unregister an env. variable hook, or is it just not yet coded?

Should there be code in the grub_register_variable_hook function to prevent overwriting an existing hook or should there be support for multiple hooks (how would ordering be handled though?)?

Thanks!

--
Omniflux
--- grub2.cvs/term/terminfo.c   2005-11-13 08:47:09.000000000 -0700
+++ grub2/term/terminfo.c       2006-01-03 14:45:43.000000000 -0700
@@ -26,6 +26,7 @@
 #include <grub/types.h>
 #include <grub/misc.h>
 #include <grub/mm.h>
+#include <grub/env.h>
 #include <grub/err.h>
 #include <grub/dl.h>
 #include <grub/normal.h>
@@ -33,10 +34,10 @@
 #include <grub/terminfo.h>
 #include <grub/tparm.h>
 
+/* A terminfo definition.  */
 struct terminfo
 {
   char *name;
-
   char *gotoxy;
   char *cls;
   char *reverse_video_on;
@@ -44,67 +45,203 @@
   char *cursor_on;
   char *cursor_off;
 };
+typedef struct terminfo terminfo_t;
 
-static struct terminfo term;
+/* The current terminfo definition.  */
+static terminfo_t *terminfo_definition;
 
-/* Get current terminfo name.  */
-char *
-grub_terminfo_get_current (void)
+/* Unset terminfo definition.  */
+static void
+unset_definition (void)
 {
-  return term.name;
+  grub_free (terminfo_definition->name);
+  grub_free (terminfo_definition->gotoxy);
+  grub_free (terminfo_definition->cls);
+  grub_free (terminfo_definition->reverse_video_on);
+  grub_free (terminfo_definition->reverse_video_off);
+  grub_free (terminfo_definition->cursor_on);
+  grub_free (terminfo_definition->cursor_off);
+
+  grub_memset (terminfo_definition, 0, sizeof (terminfo_t));
 }
 
-/* Free *PTR and set *PTR to NULL, to prevent double-free.  */
+/* Set terminfo definition.  */
 static void
-grub_terminfo_free (char **ptr)
+set_definition (const char *name, const char *definition)
+{
+  unset_definition ();
+
+  /* terminfo definition variable set to "".  */
+  if (grub_strcmp (definition, "") == 0 )
+      return;
+
+  /* Parse new definition and save as terminal_definition.  */
+  /* FIXME: Write a parser. :)  */
+  terminfo_definition->name = grub_strdup (name);
+}
+
+/* Write hook for the terminfo environment variable.  */
+static char *
+set_definition_hook (struct grub_env_var *var, const char *val)
 {
-  grub_free (*ptr);
-  *ptr = 0;
+  set_definition (var->name, val);
+  return grub_strdup (val);
 }
 
-/* Set current terminfo type.  */
-grub_err_t
-grub_terminfo_set_current (const char *str)
-{
-  /* TODO
-   * Lookup user specified terminfo type. If found, set term variables
-   * as appropriate. Otherwise return an error.
-   *
-   * How should this be done?
-   *  a. A static table included in this module.
-   *     - I do not like this idea.
-   *  b. A table stored in the configuration directory.
-   *     - Users must convert their terminfo settings if we have not already.
-   *  c. Look for terminfo files in the configuration directory.
-   *     - /usr/share/terminfo is 6.3M on my system.
-   *     - /usr/share/terminfo is not on most users boot partition.
-   *     + Copying the terminfo files you want to use to the grub
-   *       configuration directory is easier then (b).
-   *  d. Your idea here.
-   */
-
-  /* Free previously allocated memory.  */
-  grub_terminfo_free (&term.name);
-  grub_terminfo_free (&term.gotoxy);
-  grub_terminfo_free (&term.cls);
-  grub_terminfo_free (&term.reverse_video_on);
-  grub_terminfo_free (&term.reverse_video_off);
-  grub_terminfo_free (&term.cursor_on);
-  grub_terminfo_free (&term.cursor_off);
-  
-  if (grub_strcmp ("vt100", str) == 0)
+/* Select terminfo definition.  */
+static void
+select_definition (const char *name)
+{
+  /* If definition name changed to same value.  */
+  if (grub_strcmp (terminfo_definition->name, name) == 0)
+    return;
+
+  /* FIXME: Unregister old env. hook.  */
+
+  /* TERM variable set to "".  */
+  if (grub_strcmp (name, "") == 0 )
+      unset_definition ();
+  else
     {
-      term.name              = grub_strdup ("vt100");
-      term.gotoxy            = grub_strdup ("\e[%i%p1%d;%p2%dH");
-      term.cls               = grub_strdup ("\e[H\e[J");
-      term.reverse_video_on  = grub_strdup ("\e[7m");
-      term.reverse_video_off = grub_strdup ("\e[m");
-      term.cursor_on         = grub_strdup ("\e[?25l");
-      term.cursor_off        = grub_strdup ("\e[?25h");
-      return grub_errno;
+      grub_register_variable_hook (name, 0, set_definition_hook);
+      set_definition (name, grub_env_get (name));
     }
-  
-  return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminfo type.");
+}
+
+/* Write hook for the environment variable "TERM".  */
+static char *
+select_definition_hook (struct grub_env_var *var __attribute__ ((unused)),
+                        const char *val)
+{
+  select_definition (val);
+  return grub_strdup (val);
+}
+
+/* Unescape a string.  */
+static char *
+unescape_string (const char *in)
+{
+  char *q;
+  char *new_string;
+
+  /* New string length will be <= current string length.  */
+  new_string = (char *) grub_malloc (grub_strlen (in) + 1);
+
+  for (q = new_string; *in; in++, q++)
+    {
+      switch (*in)
+        {
+          /* Looks like a control character.  */
+          case '^':
+            in++;
+            /* If alpha.  */
+            if ((*in >= 'A' && *in <= 'Z') || (*in >= 'a' && *in <= 'z'))
+              {
+                *q = *in;
+                /* Turn off bits to convert to control character.  */
+                *q &= ~(0x20|0x40);
+              }
+            else       /* It was not a control character.  */
+              q--;     /* Rewind.  */
+            break;
+          /* Looks like an escape sequence.  */
+          case '\\':
+            in++;
+            /* Looks like the begining of an octal.  */
+            if (*in >= '0' && *in <= '3')
+              {
+                *q = *in - '0';
+                in++;
+                /* If middle of an octal.  */
+                if (*in >= '0' && *in <= '7')
+                  {
+                   *q = (*q << 3) | (*in - '0');
+                   in++;
+                   /* If end of an octal.  */
+                   if (*in >= '0' && *in <= '7')
+                     {
+                       *q = (*q << 3) | (*in - '0'); 
+                       break;
+                     }
+                   /* Was not an octal; rewind.  */
+                   in--;
+                  }
+                /* Was not an octal; rewind.  */
+                in -= 2;
+                /* If user entered "\0" but not an octal then use '\200'.  */
+                if (*in == '0')
+                  *q = '\200';
+                else
+                  /* Nothing to put here; rewind.  */
+                  q--;
+                break;
+              }
+            /* Does not look like an octal.  */
+            switch (*in)
+              {
+                case 'a':      /* Alert.  */
+                 *q = '\a';
+                 break;
+
+                case 'b':      /* Backspace.  */
+                  *q = '\b';
+                  break;
+
+                case 'e':      /* Escape.  */
+                case 'E':
+                  *q = '\e';
+                  break;
+
+                case 'f':      /* Form Feed.  */
+                  *q = '\f';
+                  break;
+
+                case 'n':      /* Newline.  */
+                  *q = '\n';
+                  break;
+
+                case 'r':      /* Carriage Return.  */
+                  *q = '\r';
+                  break;
+
+                case 's':      /* Space.  */
+                  *q = ' ';
+                  break;
+
+                case 't':      /* Tab.  */
+                  *q = '\t';
+                  break;
+
+                case 'v':      /* Vertical Tab.  */
+                  *q = '\v';
+                  break;
+
+                case '\\':     /* Backslash.  */
+                  *q = '\\';
+                  break;
+
+                case '^':      /* Caret.  */
+                  *q = '^';
+                  break;
+
+                case ',':      /* Comma.  */
+                  *q = ',';
+                  break;
+
+                default:       /* Anything else.  */
+                  *q = *in;
+              }
+            break;
+
+          /* Does not need any interpretation.  */
+          default:
+            *q = *in;
+        }
+    }
+  *q = 0;
+
+  /* Shrink alloc before returning.  */
+  return grub_realloc (new_string, grub_strlen (new_string) + 1);
 }
 
 /* Wrapper for grub_putchar to write strings.  */
@@ -119,70 +256,60 @@
 void
 grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y)
 {
-  putstr (grub_terminfo_tparm (term.gotoxy, y, x));
+  putstr (grub_terminfo_tparm (terminfo_definition->gotoxy, y, x));
 }
 
 /* Clear the screen.  */
 void
 grub_terminfo_cls (void)
 {
-  putstr (grub_terminfo_tparm (term.cls));
+  putstr (grub_terminfo_tparm (terminfo_definition->cls));
 }
 
 /* Set reverse video mode on.  */
 void
 grub_terminfo_reverse_video_on (void)
 {
-  putstr (grub_terminfo_tparm (term.reverse_video_on));
+  putstr (grub_terminfo_tparm (terminfo_definition->reverse_video_on));
 }
 
 /* Set reverse video mode off.  */
 void
 grub_terminfo_reverse_video_off (void)
 {
-  putstr (grub_terminfo_tparm (term.reverse_video_off));
+  putstr (grub_terminfo_tparm (terminfo_definition->reverse_video_off));
 }
 
 /* Show cursor.  */
 void
 grub_terminfo_cursor_on (void)
 {
-  putstr (grub_terminfo_tparm (term.cursor_on));
+  putstr (grub_terminfo_tparm (terminfo_definition->cursor_on));
 }
 
 /* Hide cursor.  */
 void
 grub_terminfo_cursor_off (void)
 {
-  putstr (grub_terminfo_tparm (term.cursor_off));
-}
-
-/* GRUB Command.  */
-
-static grub_err_t
-grub_cmd_terminfo (struct grub_arg_list *state __attribute__ ((unused)),
-               int argc, char **args)
-{
-  if (argc == 0)
-  {
-    grub_printf ("Current terminfo type: %s\n", grub_terminfo_get_current());
-    return GRUB_ERR_NONE;
-  }
-  else if (argc != 1)
-    return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many parameters.");
-  else
-    return grub_terminfo_set_current (args[0]);
+  putstr (grub_terminfo_tparm (terminfo_definition->cursor_off));
 }
 
 GRUB_MOD_INIT(terminfo)
 {
   (void) mod;                  /* To stop warning. */
-  grub_register_command ("terminfo", grub_cmd_terminfo, GRUB_COMMAND_FLAG_BOTH,
-                        "terminfo [TERM]", "Set terminfo type.", 0);
-  grub_terminfo_set_current ("vt100");
+
+  terminfo_definition = (terminfo_t *) grub_malloc (sizeof (terminfo_t));
+  /* FIXME: If failed, unload module?  */
+
+  grub_register_variable_hook ("TERM", 0, select_definition_hook);
+  /* FIXME: If failed, unload module?  */
+
+  select_definition (grub_env_get ("TERM"));
 }
 
 GRUB_MOD_FINI(terminfo)
 {
-  grub_unregister_command ("terminfo");
+  /* FIXME: Unregister env hook.  */
+  unset_definition ();
+  grub_free (terminfo_definition);
 }

reply via email to

[Prev in Thread] Current Thread [Next in Thread]