All of lore.kernel.org
 help / color / mirror / Atom feed
* [rfc] User definable terminfo support
@ 2006-01-03 22:20 Omniflux
  2006-01-03 22:59 ` Marco Gerards
  2006-01-03 23:09 ` Marco Gerards
  0 siblings, 2 replies; 5+ messages in thread
From: Omniflux @ 2006-01-03 22:20 UTC (permalink / raw)
  To: grub-devel

[-- Attachment #1: Type: text/plain, Size: 442 bytes --]

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

[-- Attachment #2: terminfo.diff --]
[-- Type: text/plain, Size: 10526 bytes --]

--- 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);
 }

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [rfc] User definable terminfo support
  2006-01-03 22:20 [rfc] User definable terminfo support Omniflux
@ 2006-01-03 22:59 ` Marco Gerards
  2006-01-03 23:09 ` Marco Gerards
  1 sibling, 0 replies; 5+ messages in thread
From: Marco Gerards @ 2006-01-03 22:59 UTC (permalink / raw)
  To: The development of GRUB 2

Omniflux <omniflux+lists@omniflux.com> writes:

> 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?

You could write to null pointers.  The last hooks passed to the
grub_register_variable_hook function are the once used.

> 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?)?

You just need one hook, that's for TERM.  I think it is safe to assume
that the terminfo stuff is the only user.  When registering you should
get the hook, when you unregister you should remove the hook
(otherwise it can point to a non-existing function).

--
Marco




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [rfc] User definable terminfo support
  2006-01-03 22:20 [rfc] User definable terminfo support Omniflux
  2006-01-03 22:59 ` Marco Gerards
@ 2006-01-03 23:09 ` Marco Gerards
  2006-01-03 23:23   ` Omniflux
  1 sibling, 1 reply; 5+ messages in thread
From: Marco Gerards @ 2006-01-03 23:09 UTC (permalink / raw)
  To: The development of GRUB 2

Omniflux <omniflux+lists@omniflux.com> writes:

Hi,

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

Hopefully my understanding of the code is correct so the comments are
sane :)

> -/* 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);
>  }

Why do you have a hook for variables?

For example, when I do:

set vt100=...  

It's ok that is does not take effect until you change TERM, IMO.

So what happens is:

1)  VT100 is set
2)  TERM is set
2a) The hook is executed
2b) VT100 is read by the hook.
2c) The contents of VT100 is read and parsed.
2d) From this point of the VT100 stuff can be used and the hook
    returns.

Does this make sense and does it fit well in the design of the
terminfo code?

> +/* 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);
> +}

Perhaps you can even return 0 when the definition was not valid.  In
that case TERM is set to 0, IIRC?

Thanks,
Marco




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [rfc] User definable terminfo support
  2006-01-03 23:09 ` Marco Gerards
@ 2006-01-03 23:23   ` Omniflux
  2006-01-03 23:59     ` Marco Gerards
  0 siblings, 1 reply; 5+ messages in thread
From: Omniflux @ 2006-01-03 23:23 UTC (permalink / raw)
  To: The development of GRUB 2

Marco Gerards wrote:
> Why do you have a hook for variables?
> 
> For example, when I do:
> 
> set vt100=...  
> 
> It's ok that is does not take effect until you change TERM, IMO.
> 
> So what happens is:
> 
> 1)  VT100 is set
> 2)  TERM is set
> 2a) The hook is executed
> 2b) VT100 is read by the hook.
> 2c) The contents of VT100 is read and parsed.
> 2d) From this point of the VT100 stuff can be used and the hook
>     returns.
> 

What if the user notices a typo in VT100 and changes it. Wouldn't they 
expect the update to be immediate, and not have to reassign TERM its 
current value?

-- 
Omniflux



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [rfc] User definable terminfo support
  2006-01-03 23:23   ` Omniflux
@ 2006-01-03 23:59     ` Marco Gerards
  0 siblings, 0 replies; 5+ messages in thread
From: Marco Gerards @ 2006-01-03 23:59 UTC (permalink / raw)
  To: The development of GRUB 2

Omniflux <omniflux+lists@omniflux.com> writes:

> Marco Gerards wrote:
>> Why do you have a hook for variables?
>> For example, when I do:
>> set vt100=...  It's ok that is does not take effect until you change
>> TERM, IMO.
>> So what happens is:
>> 1)  VT100 is set
>> 2)  TERM is set
>> 2a) The hook is executed
>> 2b) VT100 is read by the hook.
>> 2c) The contents of VT100 is read and parsed.
>> 2d) From this point of the VT100 stuff can be used and the hook
>>     returns.
>>
>
> What if the user notices a typo in VT100 and changes it. Wouldn't they
> expect the update to be immediate, and not have to reassign TERM its
> current value?

It does not happen that often, I think.  But if you'd like using hooks
for the variables TERM is pointing to, it's fine for me.  But I assume
you figured out it is way more complex. :-)

--
Marco




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2006-01-04  0:01 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-01-03 22:20 [rfc] User definable terminfo support Omniflux
2006-01-03 22:59 ` Marco Gerards
2006-01-03 23:09 ` Marco Gerards
2006-01-03 23:23   ` Omniflux
2006-01-03 23:59     ` Marco Gerards

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.