[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] User definable terminfo support
From: |
Omniflux |
Subject: |
[PATCH] User definable terminfo support |
Date: |
Tue, 27 Dec 2005 17:34:06 -0700 |
User-agent: |
Mozilla Thunderbird 1.0.7 (Windows/20050923) |
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
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 <grub/err.h>
#include <grub/types.h>
-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 <grub/terminfo.h>
#include <grub/tparm.h>
+/* 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);
}
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
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;
- [PATCH] User definable terminfo support,
Omniflux <=