--- 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 #include #include +#include #include #include #include @@ -33,10 +34,10 @@ #include #include +/* 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); }