merge common serial and ofconsole code into terminfo

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-05-07 15:44:43 +02:00
parent 58664b94b7
commit bf8733749b
9 changed files with 483 additions and 494 deletions

View file

@ -34,25 +34,15 @@
#include <grub/i18n.h>
#include <grub/time.h>
struct terminfo
{
char *name;
char *gotoxy;
char *cls;
char *reverse_video_on;
char *reverse_video_off;
char *cursor_on;
char *cursor_off;
};
static struct terminfo term;
static struct grub_term_output *terminfo_outputs;
/* Get current terminfo name. */
char *
grub_terminfo_get_current (void)
grub_terminfo_get_current (struct grub_term_output *term)
{
return term.name;
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
return data->name;
}
/* Free *PTR and set *PTR to NULL, to prevent double-free. */
@ -63,10 +53,29 @@ grub_terminfo_free (char **ptr)
*ptr = 0;
}
static void
grub_terminfo_all_free (struct grub_term_output *term)
{
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
/* Free previously allocated memory. */
grub_terminfo_free (&data->name);
grub_terminfo_free (&data->gotoxy);
grub_terminfo_free (&data->cls);
grub_terminfo_free (&data->reverse_video_on);
grub_terminfo_free (&data->reverse_video_off);
grub_terminfo_free (&data->cursor_on);
grub_terminfo_free (&data->cursor_off);
}
/* Set current terminfo type. */
grub_err_t
grub_terminfo_set_current (const char *str)
grub_terminfo_set_current (struct grub_term_output *term,
const char *str)
{
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
/* TODO
* Lookup user specified terminfo type. If found, set term variables
* as appropriate. Otherwise return an error.
@ -84,93 +93,290 @@ grub_terminfo_set_current (const char *str)
* 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);
grub_terminfo_all_free (term);
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[?25h");
term.cursor_off = grub_strdup ("\e[?25l");
data->name = grub_strdup ("vt100");
data->gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH");
data->cls = grub_strdup ("\e[H\e[J");
data->reverse_video_on = grub_strdup ("\e[7m");
data->reverse_video_off = grub_strdup ("\e[m");
data->cursor_on = grub_strdup ("\e[?25h");
data->cursor_off = grub_strdup ("\e[?25l");
data->setcolor = NULL;
return grub_errno;
}
if (grub_strcmp ("vt100-color", str) == 0)
{
data->name = grub_strdup ("vt100-color");
data->gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH");
data->cls = grub_strdup ("\e[H\e[J");
data->reverse_video_on = grub_strdup ("\e[7m");
data->reverse_video_off = grub_strdup ("\e[m");
data->cursor_on = grub_strdup ("\e[?25h");
data->cursor_off = grub_strdup ("\e[?25l");
data->setcolor = grub_strdup ("\e[3%p1%dm\e[4%p2%dm");
return grub_errno;
}
if (grub_strcmp ("ieee1275", str) == 0)
{
data->name = grub_strdup ("ieee1275");
data->gotoxy = grub_strdup ("\e[%i%p1%d;%p2%dH");
/* Clear the screen. Using serial console, screen(1) only recognizes the
* ANSI escape sequence. Using video console, Apple Open Firmware
* (version 3.1.1) only recognizes the literal ^L. So use both. */
data->cls = grub_strdup (" \e[2J");
data->reverse_video_on = grub_strdup ("\e[7m");
data->reverse_video_off = grub_strdup ("\e[m");
data->cursor_on = grub_strdup ("\e[?25h");
data->cursor_off = grub_strdup ("\e[?25l");
data->setcolor = grub_strdup ("\e[3%p1%dm\e[4%p2%dm");
return grub_errno;
}
if (grub_strcmp ("dumb", str) == 0)
{
data->name = grub_strdup ("dumb");
data->gotoxy = NULL;
data->cls = NULL;
data->reverse_video_on = NULL;
data->reverse_video_off = NULL;
data->cursor_on = NULL;
data->cursor_off = NULL;
data->setcolor = NULL;
return grub_errno;
}
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown terminfo type");
}
/* Wrapper for grub_putchar to write strings. */
static void
putstr (const char *str, grub_term_output_t oterm)
grub_err_t
grub_terminfo_output_register (struct grub_term_output *term,
const char *type)
{
while (*str)
{
struct grub_unicode_glyph c =
{
.base = *str++,
.variant = 0,
.attributes = 0,
.ncomb = 0,
.combining = 0
};
oterm->putchar (oterm, &c);
}
grub_err_t err;
struct grub_terminfo_output_state *data;
err = grub_terminfo_set_current (term, type);
if (err)
return err;
data = (struct grub_terminfo_output_state *) term->data;
data->next = terminfo_outputs;
terminfo_outputs = term;
data->normal_color = 0x07;
data->highlight_color = 0x70;
return GRUB_ERR_NONE;
}
/* Move the cursor to the given position starting with "0". */
void
grub_terminfo_gotoxy (grub_uint8_t x, grub_uint8_t y, grub_term_output_t oterm)
grub_err_t
grub_terminfo_output_unregister (struct grub_term_output *term)
{
putstr (grub_terminfo_tparm (term.gotoxy, y, x), oterm);
struct grub_term_output **ptr;
for (ptr = &terminfo_outputs; *ptr;
ptr = &((struct grub_terminfo_output_state *) (*ptr)->data)->next)
if (*ptr == term)
{
grub_terminfo_all_free (term);
*ptr = ((struct grub_terminfo_output_state *) (*ptr)->data)->next;
return GRUB_ERR_NONE;
}
return grub_error (GRUB_ERR_BAD_ARGUMENT, "terminal not found");
}
/* Wrapper for grub_putchar to write strings. */
static void
putstr (struct grub_term_output *term, const char *str)
{
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
while (*str)
data->put (*str++);
}
grub_uint16_t
grub_terminfo_getxy (struct grub_term_output *term)
{
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
return ((data->xpos << 8) | data->ypos);
}
void
grub_terminfo_gotoxy (struct grub_term_output *term,
grub_uint8_t x, grub_uint8_t y)
{
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
if (x > grub_term_width (term) || y > grub_term_height (term))
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", x, y);
return;
}
if (data->gotoxy)
putstr (term, grub_terminfo_tparm (data->gotoxy, y, x));
else
{
if ((y == data->ypos) && (x == data->xpos - 1))
data->put ('\b');
}
data->xpos = x;
data->ypos = y;
}
/* Clear the screen. */
void
grub_terminfo_cls (grub_term_output_t oterm)
grub_terminfo_cls (struct grub_term_output *term)
{
putstr (grub_terminfo_tparm (term.cls), oterm);
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
putstr (term, grub_terminfo_tparm (data->cls));
data->xpos = data->ypos = 0;
}
/* Set reverse video mode on. */
void
grub_terminfo_reverse_video_on (grub_term_output_t oterm)
grub_terminfo_setcolor (struct grub_term_output *term,
grub_uint8_t normal_color,
grub_uint8_t highlight_color)
{
putstr (grub_terminfo_tparm (term.reverse_video_on), oterm);
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
/* Discard bright bit. */
data->normal_color = normal_color & 0x77;
data->highlight_color = highlight_color & 0x77;
}
/* Set reverse video mode off. */
void
grub_terminfo_reverse_video_off (grub_term_output_t oterm)
grub_terminfo_getcolor (struct grub_term_output *term,
grub_uint8_t *normal_color,
grub_uint8_t *highlight_color)
{
putstr (grub_terminfo_tparm (term.reverse_video_off), oterm);
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
*normal_color = data->normal_color;
*highlight_color = data->highlight_color;
}
/* Show cursor. */
void
grub_terminfo_cursor_on (grub_term_output_t oterm)
grub_terminfo_setcolorstate (struct grub_term_output *term,
const grub_term_color_state state)
{
putstr (grub_terminfo_tparm (term.cursor_on), oterm);
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
if (data->setcolor)
{
int fg;
int bg;
switch (state)
{
case GRUB_TERM_COLOR_STANDARD:
case GRUB_TERM_COLOR_NORMAL:
fg = data->normal_color & 0x0f;
bg = data->normal_color >> 4;
break;
case GRUB_TERM_COLOR_HIGHLIGHT:
fg = data->highlight_color & 0x0f;
bg = data->highlight_color >> 4;
break;
default:
return;
}
putstr (term, grub_terminfo_tparm (data->setcolor, fg, bg));
return;
}
switch (state)
{
case GRUB_TERM_COLOR_STANDARD:
case GRUB_TERM_COLOR_NORMAL:
putstr (term, grub_terminfo_tparm (data->reverse_video_off));
break;
case GRUB_TERM_COLOR_HIGHLIGHT:
putstr (term, grub_terminfo_tparm (data->reverse_video_on));
break;
default:
break;
}
}
/* Hide cursor. */
void
grub_terminfo_cursor_off (grub_term_output_t oterm)
grub_terminfo_setcursor (struct grub_term_output *term, const int on)
{
putstr (grub_terminfo_tparm (term.cursor_off), oterm);
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
if (on)
putstr (term, grub_terminfo_tparm (data->cursor_on));
else
putstr (term, grub_terminfo_tparm (data->cursor_off));
}
/* The terminfo version of putchar. */
void
grub_terminfo_putchar (struct grub_term_output *term,
const struct grub_unicode_glyph *c)
{
struct grub_terminfo_output_state *data
= (struct grub_terminfo_output_state *) term->data;
/* Keep track of the cursor. */
switch (c->base)
{
case '\a':
break;
case '\b':
case 127:
if (data->xpos > 0)
data->xpos--;
break;
case '\n':
if (data->ypos < grub_term_height (term) - 1)
data->ypos++;
break;
case '\r':
data->xpos = 0;
break;
default:
if (data->xpos + c->estimated_width >= grub_term_width (term) + 1)
{
data->xpos = 0;
if (data->ypos < grub_term_height (term) - 1)
data->ypos++;
data->put ('\r');
data->put ('\n');
}
data->xpos += c->estimated_width;
break;
}
data->put (c->base);
}
#define ANSI_C0 0x9b
void
static void
grub_terminfo_readkey (int *keys, int *len, int (*readkey) (void))
{
int c;
@ -276,21 +482,80 @@ grub_terminfo_readkey (int *keys, int *len, int (*readkey) (void))
#undef CONTINUE_READ
}
/* The terminfo version of checkkey. */
int
grub_terminfo_checkkey (struct grub_term_input *termi)
{
struct grub_terminfo_input_state *data
= (struct grub_terminfo_input_state *) (termi->data);
if (data->npending)
return data->input_buf[0];
grub_terminfo_readkey (data->input_buf, &data->npending, data->readkey);
if (data->npending)
return data->input_buf[0];
return -1;
}
/* The terminfo version of getkey. */
int
grub_terminfo_getkey (struct grub_term_input *termi)
{
struct grub_terminfo_input_state *data
= (struct grub_terminfo_input_state *) (termi->data);
int ret;
while (! data->npending)
grub_terminfo_readkey (data->input_buf, &data->npending, data->readkey);
ret = data->input_buf[0];
data->npending--;
grub_memmove (data->input_buf, data->input_buf + 1, data->npending);
return ret;
}
grub_err_t
grub_terminfo_input_init (struct grub_term_input *termi)
{
struct grub_terminfo_input_state *data
= (struct grub_terminfo_input_state *) (termi->data);
data->npending = 0;
return GRUB_ERR_NONE;
}
/* GRUB Command. */
static grub_err_t
grub_cmd_terminfo (grub_command_t cmd __attribute__ ((unused)),
int argc, char **args)
{
struct grub_term_output *cur;
if (argc == 0)
{
grub_printf ("Current terminfo type: %s\n", grub_terminfo_get_current());
return GRUB_ERR_NONE;
}
else if (argc != 1)
{
grub_printf ("Current terminfo types: \n");
for (cur = terminfo_outputs; cur;
cur = ((struct grub_terminfo_output_state *) cur->data)->next)
grub_printf ("%s: %s\n", cur->name,
grub_terminfo_get_current(cur));
return GRUB_ERR_NONE;
}
if (argc == 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "too few parameters");
if (argc != 2)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many parameters");
else
return grub_terminfo_set_current (args[0]);
for (cur = terminfo_outputs; cur;
cur = ((struct grub_terminfo_output_state *) cur->data)->next)
if (grub_strcmp (args[0], cur->name) == 0)
return grub_terminfo_set_current (cur, args[1]);
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"no terminal %s found or it's not handled by terminfo",
args[0]);
}
static grub_command_t cmd;
@ -298,8 +563,7 @@ static grub_command_t cmd;
GRUB_MOD_INIT(terminfo)
{
cmd = grub_register_command ("terminfo", grub_cmd_terminfo,
N_("[TERM]"), N_("Set terminfo type."));
grub_terminfo_set_current ("vt100");
N_("[TERM TYPE]"), N_("Set terminfo type of TERM to TYPE."));
}
GRUB_MOD_FINI(terminfo)