From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1ErPI4-0008ES-08 for mharc-grub-devel@gnu.org; Tue, 27 Dec 2005 19:35:40 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1ErPHy-0008E1-Tv for grub-devel@gnu.org; Tue, 27 Dec 2005 19:35:35 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1ErPHw-0008Dg-97 for grub-devel@gnu.org; Tue, 27 Dec 2005 19:35:33 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1ErPHv-0008Dc-Mr for grub-devel@gnu.org; Tue, 27 Dec 2005 19:35:31 -0500 Received: from [208.186.28.7] (helo=mail.nebonet.com) by monty-python.gnu.org with esmtp (Exim 4.34) id 1ErPI0-0006Uw-Cd for grub-devel@gnu.org; Tue, 27 Dec 2005 19:35:36 -0500 Received: from localhost (scanner.nebonet.com [208.186.28.8]) by mail.nebonet.com (Postfix) with ESMTP id A754C19DC6B for ; Tue, 27 Dec 2005 17:34:09 -0700 (MST) Received: from mail.nebonet.com ([208.186.28.7]) by localhost (scanner.nebonet.com [208.186.28.8]) (amavisd-new, port 10024) with LMTP id 02613-01-5 for ; Tue, 27 Dec 2005 17:34:09 -0700 (MST) Received: from [10.0.1.114] (f4s.dsl.xmission.com [166.70.40.38]) by mail.nebonet.com (Postfix) with ESMTP id 7EC8E19DA4B for ; Tue, 27 Dec 2005 17:34:07 -0700 (MST) Message-ID: <43B1DD7E.5090905@omniflux.com> Date: Tue, 27 Dec 2005 17:34:06 -0700 From: Omniflux User-Agent: Mozilla Thunderbird 1.0.7 (Windows/20050923) X-Accept-Language: en-us, en MIME-Version: 1.0 To: The development of GRUB 2 Content-Type: multipart/mixed; boundary="------------040007000704080509070909" X-Virus-Scanned: by amavisd-new-20030616-p10 (Debian) at nebonet.com Subject: [PATCH] User definable terminfo support X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 28 Dec 2005 00:35:36 -0000 This is a multi-part message in MIME format. --------------040007000704080509070909 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Attached are three patches.... enable-serial-module.diff * conf/i386-pc.rmk (pkgdata_MODULES): Add serial.mod. strcasecmp.diff * kern/misc.c (grub_strcasecmp): New function. * include/grub/misc.h (grub_strcasecmp): New function prototype. terminfo-definition-support.diff * term/terminfo.c: Replaced static vt100 definition with user definable definition support. * include/grub/terminfo.h (grub_terminfo_get_current): Removed. (grub_terminfo_set_current): Likewise As with the previous serial patch, some code here is based on the terminfo support from GRUB Legacy. Any mistakes, however, are mine. :) I would appreciate comments and suggestions, especially for the short parameter selection for the reverse video and cursor options. I tried not using a short parameter, but state[x].set does not get set in that case, or I tried incorrectly. Also can someone point me to instructions for creating a menu so that I may test other then the command line? Thanks! -- Omniflux --------------040007000704080509070909 Content-Type: text/plain; name="terminfo-definition-support.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="terminfo-definition-support.diff" diff -uNr grub2.cvs/include/grub/terminfo.h grub2/include/grub/terminfo.h --- grub2.cvs/include/grub/terminfo.h 2005-09-03 10:54:26.000000000 -0600 +++ grub2/include/grub/terminfo.h 2005-12-27 16:57:57.000000000 -0700 @@ -23,9 +23,6 @@ #include #include -char *grub_terminfo_get_current (void); -grub_err_t grub_terminfo_set_current (const char *); - void grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y); void grub_terminfo_cls (void); void grub_terminfo_reverse_video_on (void); diff -uNr grub2.cvs/term/terminfo.c grub2/term/terminfo.c --- grub2.cvs/term/terminfo.c 2005-11-13 08:47:09.000000000 -0700 +++ grub2/term/terminfo.c 2005-12-27 16:57:57.000000000 -0700 @@ -33,78 +33,244 @@ #include #include +/* A terminfo definition. */ struct terminfo { char *name; - char *gotoxy; char *cls; char *reverse_video_on; char *reverse_video_off; char *cursor_on; char *cursor_off; + + struct terminfo *next; }; +typedef struct terminfo terminfo_t; + +/* The list of terminfo definitions. */ +static terminfo_t *terminfo_list; + +/* The current terminfo definition. */ +static terminfo_t *cur_terminfo; + +/* Argument options. */ +static const struct grub_arg_option options[] = +{ + {"add", 'a', 0, "Add a definition", 0, 0}, + {"modify", 'm', 0, "Modify a definition", 0, 0}, + {"delete", 'd', 0, "Delete a definition", 0, 0}, + {"view", 'v', 0, "View a definition", 0, 0}, + {"cursor-address", 'p', 0, "Sequence to position cursor", 0, ARG_TYPE_STRING}, + {"clear-screen", 'c', 0, "Sequence to clear screen", 0, ARG_TYPE_STRING}, + {"reverse-on", 'w', 0, "Sequence to enable reverse video mode", 0, ARG_TYPE_STRING}, + {"reverse-off", 'x', 0, "Sequence to disable reverse video mode", 0, ARG_TYPE_STRING}, + {"cursor-on", 'y', 0, "Sequence to enable cursor", 0, ARG_TYPE_STRING}, + {"cursor-off", 'z', 0, "Sequence to disable cursor", 0, ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} +}; + +/* Add new terminfo definition to list. */ +static grub_err_t +add_definition (terminfo_t *ti) +{ + terminfo_t *p; -static struct terminfo term; + for (p = terminfo_list; p; p = p->next) + if (grub_strcasecmp (p->name, ti->name) == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "terminfo definition name already exists."); -/* Get current terminfo name. */ -char * -grub_terminfo_get_current (void) + ti->next = terminfo_list; + terminfo_list = ti; + + return GRUB_ERR_NONE; +} + +/* Delete terminfo definition from list. */ +static void +delete_definition (terminfo_t *ti) { - return term.name; + terminfo_t *p, *q; + + for (p = 0, q = terminfo_list; q; p = q, q = q->next) + if (q == ti) + { + if (p) + p->next = q->next; + else + terminfo_list = q->next; + + grub_free (q->name); + grub_free (q->gotoxy); + grub_free (q->cls); + grub_free (q->reverse_video_on); + grub_free (q->reverse_video_off); + grub_free (q->cursor_on); + grub_free (q->cursor_off); + grub_free (q); + + break; + } } -/* Free *PTR and set *PTR to NULL, to prevent double-free. */ +/* Iterate through terminfo definitions. */ static void -grub_terminfo_free (char **ptr) +iterate_definitions (int (*hook) (terminfo_t *ti)) { - grub_free (*ptr); - *ptr = 0; + terminfo_t *p; + + for (p = terminfo_list; p; p = p->next) + if (hook (p)) + break; +} + +/* Escape a string. */ +static char * +escape_string (const char *in) +{ + char *q, *new_string; + + new_string = (char *) grub_malloc (grub_strlen (in) * 4 + 1); /* Max escaped string size is 4x. */ + + for (q = new_string; *in; in++, q++) + { + switch (*in) + { + case '\a': /* Common escape sequences. */ + *q++ = '\\'; + *q = 'a'; + break; + case '\b': + *q++ = '\\'; + *q = 'b'; + break; + case '\e': + *q++ = '\\'; + *q = 'e'; + break; + case '\f': + *q++ = '\\'; + *q = 'f'; + break; + case '\n': + *q++ = '\\'; + *q = 'n'; + break; + case '\r': + *q++ = '\\'; + *q = 'r'; + break; + case '\t': + *q++ = '\\'; + *q = 't'; + break; + case '\v': + *q++ = '\\'; + *q = 'v'; + break; + case '\\': + *q++ = '\\'; + *q = '\\'; + break; + case 32 ... 91: /* Typeable character. Leave as is. */ + case 93 ... 126: + *q = *in; + break; + default: /* Convert to octal sequence. */ + *q++ = '\\'; + *q++ = ((*in >> 8) & 7) + '0'; + *q++ = ((*in >> 4) & 7) + '0'; + *q = ((*in >> 0) & 7) + '0'; + } + } + + *q = 0; + return grub_realloc (new_string, grub_strlen (new_string) + 1); /* Shrink alloc. */ } -/* 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) - { - 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; +/* Unescape a string. */ +static char * +unescape_string (const char *in) +{ + char *q, *new_string; + + new_string = (char *) grub_malloc (grub_strlen (in) + 1); /* New string will be <= current string. */ + + for (q = new_string; *in; in++, q++) + { + switch (*in) + { + case '\\': /* Escape sequence. */ + in++; + if (*in >= '0' && *in <= '3') /* Looks like the begining of an octal. */ + { + *q = *in - '0'; + in++; + if (*in >= '0' && *in <= '7') /* Middle of an octal. */ + { + *q = (*q << 3) | (*in - '0'); + in++; + if (*in >= '0' && *in <= '7') /* End of an octal. */ + { + *q = (*q << 3) | (*in - '0'); + break; + } + in--; /* Was not an octal; rewind. */ + } + in -= 2; /* Was not an octal; rewind. */ + q--; /* Nothing to put here; rewind. */ + break; + } + switch (*in) /* Does not look like an octal. */ + { + 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 't': /* Tab. */ + *q = '\t'; + break; + + case 'v': /* Vertical Tab. */ + *q = '\v'; + break; + + case '\\': /* Backslash. */ + *q = '\\'; + break; + + default: /* Anything else. */ + *q = *in; + } + break; + + default: /* Does not need any interpretation. */ + *q = *in; + } } - - return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminfo type."); + *q = 0; + return grub_realloc (new_string, grub_strlen (new_string) + 1); /* Shrink alloc. */ } /* Wrapper for grub_putchar to write strings. */ @@ -119,70 +285,273 @@ void grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y) { - putstr (grub_terminfo_tparm (term.gotoxy, y, x)); + putstr (grub_terminfo_tparm (cur_terminfo->gotoxy, y, x)); } /* Clear the screen. */ void grub_terminfo_cls (void) { - putstr (grub_terminfo_tparm (term.cls)); + putstr (grub_terminfo_tparm (cur_terminfo->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 (cur_terminfo->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 (cur_terminfo->reverse_video_off)); } /* Show cursor. */ void grub_terminfo_cursor_on (void) { - putstr (grub_terminfo_tparm (term.cursor_on)); + putstr (grub_terminfo_tparm (cur_terminfo->cursor_on)); } /* Hide cursor. */ void grub_terminfo_cursor_off (void) { - putstr (grub_terminfo_tparm (term.cursor_off)); + putstr (grub_terminfo_tparm (cur_terminfo->cursor_off)); } /* GRUB Command. */ static grub_err_t -grub_cmd_terminfo (struct grub_arg_list *state __attribute__ ((unused)), - int argc, char **args) +grub_cmd_terminfo (struct grub_arg_list *state, int argc, char **args) { + int i; + char *p; + terminfo_t *ti = 0; + + auto int print_terminfo (terminfo_t *); + auto int find_terminfo (terminfo_t *); + + int print_terminfo (terminfo_t *t) + { + grub_printf (" %s", t->name); + return 0; + } + + int find_terminfo (terminfo_t *t) + { + if (grub_strcasecmp (t->name, args[0]) == 0) + { + ti = t; + return 1; + } + + return 0; + } + + i = state[0].set + state[1].set + state[2].set + state[3].set; + + if (i > 1) + return grub_error (GRUB_ERR_INVALID_COMMAND, "add, modify, delete and view are exclusive operations."); + if (argc == 0) - { - grub_printf ("Current terminfo type: %s\n", grub_terminfo_get_current()); - return GRUB_ERR_NONE; - } - else if (argc != 1) + { + if (i == 0) + { + grub_printf ("Available terminfo definition(s):"); + iterate_definitions (print_terminfo); + grub_putchar ('\n'); + grub_printf ("Current terminfo definition: %s\n", cur_terminfo->name); + + return GRUB_ERR_NONE; + } + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, "terminfo definition name must be specified."); + } + + if (argc > 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many parameters."); + + iterate_definitions (find_terminfo); + if ((! ti) && (! state[0].set)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such terminfo definition."); + + if (ti && state[0].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "terminfo definition name already exists"); + + if (i == 0) + cur_terminfo = ti; else - return grub_terminfo_set_current (args[0]); + { + if (state[0].set) /* Add new definition. */ + { + if (! state[4].set) + return grub_error (GRUB_ERR_INVALID_COMMAND, "Missing mandatory option for `cursor-address'."); + + p = unescape_string (state[4].arg); /* Cursor address. */ + if (! *p) + { + grub_free (p); + return grub_error (GRUB_ERR_INVALID_COMMAND, "option `cursor-address' must not be blank."); + } + + ti = (terminfo_t *) grub_malloc (sizeof (terminfo_t)); + if (! ti) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new definition."); + grub_memset (ti, 0, sizeof (terminfo_t)); + + ti->name = grub_strdup (args[0]); + + ti->gotoxy = p; + + if (state[5].set) /* Clear screen. */ + ti->cls = unescape_string (state[5].arg); + else + ti->cls = grub_strdup (""); + + if (state[6].set) /* Reverse video on. */ + ti->reverse_video_on = unescape_string (state[6].arg); + else + ti->reverse_video_on = grub_strdup (""); + + if (state[7].set) /* Reverse video off. */ + ti->reverse_video_off = unescape_string (state[7].arg); + else + ti->reverse_video_off = grub_strdup (""); + + if (state[8].set) /* Cursor on. */ + ti->cursor_on = unescape_string (state[8].arg); + else + ti->cursor_on = grub_strdup (""); + + if (state[9].set) /* Cursor off. */ + ti->cursor_off = unescape_string (state[9].arg); + else + ti->cursor_off = grub_strdup (""); + + add_definition (ti); + } + else if (state[1].set) /* Modify definition. */ + { + if (state[4].set) + { + p = unescape_string (state[4].arg); + if (! *p) + { + grub_free (p); + return grub_error (GRUB_ERR_INVALID_COMMAND, "option `cursor-address' must not be blank."); + } + + grub_free (ti->gotoxy); + ti->gotoxy = p; + } + + if (state[5].set) + { + grub_free (ti->cls); + ti->cls = unescape_string (state[5].arg); + } + + if (state[6].set) + { + grub_free (ti->reverse_video_on); + ti->reverse_video_on = unescape_string (state[6].arg); + } + + if (state[7].set) + { + grub_free (ti->reverse_video_off); + ti->reverse_video_off = unescape_string (state[7].arg); + } + + if (state[8].set) + { + grub_free (ti->cursor_on); + ti->cursor_on = unescape_string (state[8].arg); + } + + if (state[9].set) + { + grub_free (ti->cursor_off); + ti->cursor_off = unescape_string (state[9].arg); + } + } + else if (state[2].set) /* Delete definition. */ + { + if (cur_terminfo == ti) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot delete in use definition."); + + delete_definition (ti); + } + else if (state[3].set) /* View definition. */ + { + grub_printf ("Terminfo definition: %s\n", ti->name); + + p = escape_string (ti->gotoxy); + grub_printf ("Cursor address: %s\n", p); + grub_free (p); + + p = escape_string (ti->cls); + grub_printf ("Clear screen: %s\n", p); + grub_free (p); + + p = escape_string (ti->reverse_video_on); + grub_printf ("Reverse video on: %s\n", p); + grub_free (p); + + p = escape_string (ti->reverse_video_off); + grub_printf ("Reverse video off: %s\n", p); + grub_free (p); + + p = escape_string (ti->cursor_on); + grub_printf ("Cursor on: %s\n", p); + grub_free (p); + + p = escape_string (ti->cursor_off); + grub_printf ("Cursor off: %s\n", p); + grub_free (p); + } + } + + return GRUB_ERR_NONE; +} + +static void +setup_defaults (void) +{ + terminfo_t *ti; + + ti = (terminfo_t *) grub_malloc (sizeof (terminfo_t)); + /* Do I need to test if malloc succeeded here? What do I do if it did not? */ + + /* Default terminal definition vt100. */ + ti->name = grub_strdup ("vt100"); + ti->gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH"); + ti->cls = grub_strdup ("\e[H\e[J"); + ti->reverse_video_on = grub_strdup ("\e[7m"); + ti->reverse_video_off = grub_strdup ("\e[m"); + ti->cursor_on = grub_strdup ("\e[?25l"); + ti->cursor_off = grub_strdup ("\e[?25h"); + ti->next = 0; + + add_definition (ti); + cur_terminfo = ti; } GRUB_MOD_INIT(terminfo) { (void) mod; /* To stop warning. */ + setup_defaults (); grub_register_command ("terminfo", grub_cmd_terminfo, GRUB_COMMAND_FLAG_BOTH, - "terminfo [TERM]", "Set terminfo type.", 0); - grub_terminfo_set_current ("vt100"); + "terminfo [TERMTYPE [-a|-m|-d|-v [ARGS...]]]", "Select or define terminfo definition(s). Escape sequences must be double quoted.", options); } GRUB_MOD_FINI(terminfo) { grub_unregister_command ("terminfo"); + while (terminfo_list) + delete_definition (terminfo_list); } --------------040007000704080509070909 Content-Type: text/plain; name="enable-serial-module.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="enable-serial-module.diff" diff -uNr grub2.cvs/conf/i386-pc.rmk grub2/conf/i386-pc.rmk --- grub2.cvs/conf/i386-pc.rmk 2005-12-25 08:59:50.000000000 -0700 +++ grub2/conf/i386-pc.rmk 2005-12-27 16:56:54.000000000 -0700 @@ -115,7 +115,7 @@ # Modules. pkgdata_MODULES = _chain.mod _linux.mod linux.mod normal.mod vga.mod \ _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ - vbe.mod vesafb.mod vbetest.mod vbeinfo.mod play.mod + vbe.mod vesafb.mod vbetest.mod vbeinfo.mod play.mod serial.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c --------------040007000704080509070909 Content-Type: text/plain; name="strcasecmp.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="strcasecmp.diff" diff -uNr grub2.cvs/include/grub/misc.h grub2/include/grub/misc.h --- grub2.cvs/include/grub/misc.h 2005-10-24 04:23:46.000000000 -0600 +++ grub2/include/grub/misc.h 2005-12-27 16:57:45.000000000 -0700 @@ -44,6 +44,7 @@ int EXPORT_FUNC(grub_memcmp) (const void *s1, const void *s2, grub_size_t n); int EXPORT_FUNC(grub_strcmp) (const char *s1, const char *s2); int EXPORT_FUNC(grub_strncmp) (const char *s1, const char *s2, grub_size_t n); +int EXPORT_FUNC(grub_strcasecmp) (const char *s1, const char *s2); int EXPORT_FUNC(grub_strncasecmp) (const char *s1, const char *s2, int c); char *EXPORT_FUNC(grub_strchr) (const char *s, int c); char *EXPORT_FUNC(grub_strrchr) (const char *s, int c); diff -uNr grub2.cvs/kern/misc.c grub2/kern/misc.c --- grub2.cvs/kern/misc.c 2005-10-27 21:14:33.000000000 -0600 +++ grub2/kern/misc.c 2005-12-27 16:57:45.000000000 -0700 @@ -209,6 +209,21 @@ } int +grub_strcasecmp (const char *s1, const char *s2) +{ + while (grub_tolower (*s1) && grub_tolower (*s2)) + { + if (grub_tolower (*s1) != grub_tolower (*s2)) + return (int) grub_tolower (*s1) - (int) grub_tolower (*s2); + + s1++; + s2++; + } + + return (int) *s1 - (int) *s2; +} + +int grub_strncasecmp (const char *s1, const char *s2, int c) { int p = 1; --------------040007000704080509070909--