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

@ -22,7 +22,8 @@
#include <grub/symbol.h>
/* Initialize the console system. */
void grub_console_init (void);
void grub_console_init_early (void);
void grub_console_init_lately (void);
/* Finish the console system. */
void grub_console_fini (void);

View file

@ -1,28 +0,0 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2004,2005,2007 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_CONSOLE_MACHINE_HEADER
#define GRUB_CONSOLE_MACHINE_HEADER 1
/* Initialize the console system. */
void grub_console_init (void);
/* Finish the console system. */
void grub_console_fini (void);
#endif /* ! GRUB_CONSOLE_MACHINE_HEADER */

View file

@ -1,28 +0,0 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2004,2005,2007 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_CONSOLE_MACHINE_HEADER
#define GRUB_CONSOLE_MACHINE_HEADER 1
/* Initialize the console system. */
void grub_console_init (void);
/* Finish the console system. */
void grub_console_fini (void);
#endif /* ! GRUB_CONSOLE_MACHINE_HEADER */

View file

@ -23,18 +23,64 @@
#include <grub/types.h>
#include <grub/term.h>
char *EXPORT_FUNC(grub_terminfo_get_current) (void);
grub_err_t EXPORT_FUNC(grub_terminfo_set_current) (const char *);
void EXPORT_FUNC(grub_terminfo_gotoxy) (grub_uint8_t x, grub_uint8_t y,
grub_term_output_t oterm);
void EXPORT_FUNC(grub_terminfo_cls) (grub_term_output_t oterm);
void EXPORT_FUNC(grub_terminfo_reverse_video_on) (grub_term_output_t oterm);
void EXPORT_FUNC(grub_terminfo_reverse_video_off) (grub_term_output_t oterm);
void EXPORT_FUNC(grub_terminfo_cursor_on) (grub_term_output_t oterm);
void EXPORT_FUNC(grub_terminfo_cursor_off) (grub_term_output_t oterm);
char *EXPORT_FUNC(grub_terminfo_get_current) (struct grub_term_output *term);
grub_err_t EXPORT_FUNC(grub_terminfo_set_current) (struct grub_term_output *term,
const char *);
#define GRUB_TERMINFO_READKEY_MAX_LEN 4
void EXPORT_FUNC(grub_terminfo_readkey) (int *keys, int *len, int (*readkey) (void));
struct grub_terminfo_input_state
{
int input_buf[GRUB_TERMINFO_READKEY_MAX_LEN];
int npending;
int (*readkey) (void);
};
struct grub_terminfo_output_state
{
struct grub_term_output *next;
char *name;
char *gotoxy;
char *cls;
char *reverse_video_on;
char *reverse_video_off;
char *cursor_on;
char *cursor_off;
char *setcolor;
grub_uint8_t normal_color;
grub_uint8_t highlight_color;
unsigned int xpos, ypos;
void (*put) (const int c);
};
void EXPORT_FUNC(grub_terminfo_gotoxy) (grub_term_output_t term,
grub_uint8_t x, grub_uint8_t y);
void EXPORT_FUNC(grub_terminfo_cls) (grub_term_output_t term);
grub_uint16_t EXPORT_FUNC (grub_terminfo_getxy) (struct grub_term_output *term);
void EXPORT_FUNC (grub_terminfo_setcursor) (struct grub_term_output *term,
const int on);
void EXPORT_FUNC (grub_terminfo_setcolorstate) (struct grub_term_output *term,
const grub_term_color_state state);
int EXPORT_FUNC (grub_terminfo_checkkey) (struct grub_term_input *term);
grub_err_t EXPORT_FUNC (grub_terminfo_input_init) (struct grub_term_input *term);
int EXPORT_FUNC (grub_terminfo_getkey) (struct grub_term_input *term);
void EXPORT_FUNC (grub_terminfo_putchar) (struct grub_term_output *term,
const struct grub_unicode_glyph *c);
void EXPORT_FUNC (grub_terminfo_getcolor) (struct grub_term_output *term,
grub_uint8_t *normal_color,
grub_uint8_t *highlight_color);
void EXPORT_FUNC (grub_terminfo_setcolor) (struct grub_term_output *term,
grub_uint8_t normal_color,
grub_uint8_t highlight_color);
grub_err_t EXPORT_FUNC (grub_terminfo_output_register) (struct grub_term_output *term,
const char *type);
grub_err_t EXPORT_FUNC (grub_terminfo_output_unregister) (struct grub_term_output *term);
#endif /* ! GRUB_TERMINFO_HEADER */

View file

@ -28,7 +28,7 @@
#include <grub/env.h>
#include <grub/misc.h>
#include <grub/time.h>
#include <grub/machine/console.h>
#include <grub/ieee1275/console.h>
#include <grub/machine/kernel.h>
#include <grub/cpu/kernel.h>
#include <grub/ieee1275/ofdisk.h>
@ -225,11 +225,12 @@ grub_machine_init (void)
grub_ieee1275_init ();
grub_console_init ();
grub_console_init_early ();
#ifdef __i386__
grub_get_extended_memory ();
#endif
grub_claim_heap ();
grub_console_init_lately ();
grub_ofdisk_init ();
/* Process commandline. */

View file

@ -23,7 +23,7 @@
#include <grub/mm.h>
#include <grub/time.h>
#include <grub/terminfo.h>
#include <grub/machine/console.h>
#include <grub/ieee1275/console.h>
#include <grub/ieee1275/ieee1275.h>
static grub_ieee1275_ihandle_t stdout_ihandle;
@ -32,12 +32,6 @@ static grub_ieee1275_ihandle_t stdin_ihandle;
static grub_uint8_t grub_ofconsole_width;
static grub_uint8_t grub_ofconsole_height;
static int grub_curr_x;
static int grub_curr_y;
static int grub_keybuf[GRUB_TERMINFO_READKEY_MAX_LEN];
static int grub_buflen;
struct color
{
int red;
@ -58,102 +52,14 @@ static struct color colors[] =
{0xFE, 0xFE, 0xFE} // 7 = white
};
static grub_uint8_t grub_ofconsole_normal_color = 0x7;
static grub_uint8_t grub_ofconsole_highlight_color = 0x70;
/* Write control characters to the console. */
static void
grub_ofconsole_writeesc (const char *str)
put (const int c)
{
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_ANSI))
return;
char chr = c;
while (*str)
{
char chr = *(str++);
grub_ieee1275_write (stdout_ihandle, &chr, 1, 0);
}
}
static void
grub_ofconsole_putchar (struct grub_term_output *term __attribute__ ((unused)),
const struct grub_unicode_glyph *c)
{
char chr;
chr = c->base;
if (chr == '\n')
{
grub_curr_y++;
grub_curr_x = 0;
}
else if (chr == '\r')
{
grub_curr_x = 0;
}
else
{
grub_curr_x++;
if (grub_curr_x >= grub_ofconsole_width)
{
chr = '\n';
grub_ieee1275_write (stdout_ihandle, &chr, 1, 0);
chr = '\r';
grub_ieee1275_write (stdout_ihandle, &chr, 1, 0);
grub_curr_y++;
grub_curr_x = 1;
}
}
grub_ieee1275_write (stdout_ihandle, &chr, 1, 0);
}
static void
grub_ofconsole_setcolorstate (struct grub_term_output *term __attribute__ ((unused)),
grub_term_color_state state)
{
char setcol[256];
int fg;
int bg;
switch (state)
{
case GRUB_TERM_COLOR_STANDARD:
case GRUB_TERM_COLOR_NORMAL:
fg = grub_ofconsole_normal_color & 0x0f;
bg = grub_ofconsole_normal_color >> 4;
break;
case GRUB_TERM_COLOR_HIGHLIGHT:
fg = grub_ofconsole_highlight_color & 0x0f;
bg = grub_ofconsole_highlight_color >> 4;
break;
default:
return;
}
grub_snprintf (setcol, sizeof (setcol), "\e[3%dm\e[4%dm", fg, bg);
grub_ofconsole_writeesc (setcol);
}
static void
grub_ofconsole_setcolor (struct grub_term_output *term __attribute__ ((unused)),
grub_uint8_t normal_color,
grub_uint8_t highlight_color)
{
/* Discard bright bit. */
grub_ofconsole_normal_color = normal_color & 0x77;
grub_ofconsole_highlight_color = highlight_color & 0x77;
}
static void
grub_ofconsole_getcolor (struct grub_term_output *term __attribute__ ((unused)),
grub_uint8_t *normal_color, grub_uint8_t *highlight_color)
{
*normal_color = grub_ofconsole_normal_color;
*highlight_color = grub_ofconsole_highlight_color;
}
static int
readkey (void)
{
@ -166,39 +72,6 @@ readkey (void)
return -1;
}
static int
grub_ofconsole_checkkey (struct grub_term_input *term __attribute__ ((unused)))
{
if (grub_buflen)
return grub_keybuf[0];
grub_terminfo_readkey (grub_keybuf, &grub_buflen, readkey);
if (grub_buflen)
return grub_keybuf[0];
return -1;
}
static int
grub_ofconsole_getkey (struct grub_term_input *term __attribute__ ((unused)))
{
int ret;
while (! grub_buflen)
grub_terminfo_readkey (grub_keybuf, &grub_buflen, readkey);
ret = grub_keybuf[0];
grub_buflen--;
grub_memmove (grub_keybuf, grub_keybuf + 1, grub_buflen);
return ret;
}
static grub_uint16_t
grub_ofconsole_getxy (struct grub_term_output *term __attribute__ ((unused)))
{
return (grub_curr_x << 8) | grub_curr_y;
}
static void
grub_ofconsole_dimensions (void)
{
@ -241,44 +114,6 @@ grub_ofconsole_getwh (struct grub_term_output *term __attribute__ ((unused)))
return (grub_ofconsole_width << 8) | grub_ofconsole_height;
}
static void
grub_ofconsole_gotoxy (struct grub_term_output *term __attribute__ ((unused)),
grub_uint8_t x, grub_uint8_t y)
{
if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_ANSI))
{
char s[256];
grub_curr_x = x;
grub_curr_y = y;
grub_snprintf (s, sizeof (s), "\e[%d;%dH", y + 1, x + 1);
grub_ofconsole_writeesc (s);
}
else
{
if ((y == grub_curr_y) && (x == grub_curr_x - 1))
{
char chr;
chr = '\b';
grub_ieee1275_write (stdout_ihandle, &chr, 1, 0);
}
grub_curr_x = x;
grub_curr_y = y;
}
}
static void
grub_ofconsole_cls (struct grub_term_output *term)
{
/* 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. */
grub_ofconsole_writeesc (" \e[2J");
grub_ofconsole_gotoxy (term, 0, 0);
}
static void
grub_ofconsole_setcursor (struct grub_term_output *term __attribute__ ((unused)),
int on)
@ -290,14 +125,8 @@ grub_ofconsole_setcursor (struct grub_term_output *term __attribute__ ((unused))
grub_ieee1275_interpret ("cursor-off", 0);
}
static void
grub_ofconsole_refresh (struct grub_term_output *term __attribute__ ((unused)))
{
/* Do nothing, the current console state is ok. */
}
static grub_err_t
grub_ofconsole_init_input (struct grub_term_input *term __attribute__ ((unused)))
grub_ofconsole_init_input (struct grub_term_input *term)
{
grub_ssize_t actual;
@ -306,7 +135,7 @@ grub_ofconsole_init_input (struct grub_term_input *term __attribute__ ((unused))
|| actual != sizeof stdin_ihandle)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot find stdin");
return 0;
return grub_terminfo_input_init (term);
}
static grub_err_t
@ -334,7 +163,7 @@ grub_ofconsole_init_output (struct grub_term_output *term)
colors[col].green, colors[col].blue);
/* Set the right fg and bg colors. */
grub_ofconsole_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
grub_terminfo_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
}
grub_ofconsole_dimensions ();
@ -343,41 +172,73 @@ grub_ofconsole_init_output (struct grub_term_output *term)
}
struct grub_terminfo_input_state grub_ofconsole_terminfo_input =
{
.readkey = readkey
};
struct grub_terminfo_output_state grub_ofconsole_terminfo_output =
{
.put = put
};
static struct grub_term_input grub_ofconsole_term_input =
{
.name = "ofconsole",
.init = grub_ofconsole_init_input,
.checkkey = grub_ofconsole_checkkey,
.getkey = grub_ofconsole_getkey,
.checkkey = grub_terminfo_checkkey,
.getkey = grub_terminfo_getkey,
.data = &grub_ofconsole_terminfo_input
};
static struct grub_term_output grub_ofconsole_term_output =
{
.name = "ofconsole",
.init = grub_ofconsole_init_output,
.putchar = grub_ofconsole_putchar,
.getxy = grub_ofconsole_getxy,
.putchar = grub_terminfo_putchar,
.getxy = grub_terminfo_getxy,
.getwh = grub_ofconsole_getwh,
.gotoxy = grub_ofconsole_gotoxy,
.cls = grub_ofconsole_cls,
.setcolorstate = grub_ofconsole_setcolorstate,
.setcolor = grub_ofconsole_setcolor,
.getcolor = grub_ofconsole_getcolor,
.gotoxy = grub_terminfo_gotoxy,
.cls = grub_terminfo_cls,
.setcolorstate = grub_terminfo_setcolorstate,
.setcolor = grub_terminfo_setcolor,
.getcolor = grub_terminfo_getcolor,
.setcursor = grub_ofconsole_setcursor,
.refresh = grub_ofconsole_refresh,
.flags = GRUB_TERM_CODE_TYPE_ASCII
.flags = GRUB_TERM_CODE_TYPE_ASCII,
.data = &grub_ofconsole_terminfo_output
};
void grub_terminfo_fini (void);
void grub_terminfo_init (void);
void
grub_console_init (void)
grub_console_init_early (void)
{
grub_term_register_input ("ofconsole", &grub_ofconsole_term_input);
grub_term_register_output ("ofconsole", &grub_ofconsole_term_output);
}
void
grub_console_init_lately (void)
{
const char *type;
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_ANSI))
type = "dumb";
else
type = "ieee1275";
grub_terminfo_init ();
grub_terminfo_output_register (&grub_ofconsole_term_output, type);
}
void
grub_console_fini (void)
{
grub_term_unregister_input (&grub_ofconsole_term_input);
grub_term_unregister_output (&grub_ofconsole_term_output);
grub_terminfo_output_unregister (&grub_ofconsole_term_output);
grub_terminfo_fini ();
}

View file

@ -27,19 +27,8 @@
#include <grub/extcmd.h>
#include <grub/i18n.h>
#define TEXT_WIDTH 80
#define TEXT_HEIGHT 24
static unsigned int xpos, ypos;
static unsigned int keep_track = 1;
static unsigned int registered = 0;
/* An input buffer. */
static int input_buf[GRUB_TERMINFO_READKEY_MAX_LEN];
static int npending = 0;
static struct grub_term_output grub_serial_term_output;
/* Argument options. */
static const struct grub_arg_option options[] =
{
@ -152,35 +141,6 @@ serial_get_divisor (unsigned int speed)
return 0;
}
/* The serial version of checkkey. */
static int
grub_serial_checkkey (struct grub_term_input *term __attribute__ ((unused)))
{
if (npending)
return input_buf[0];
grub_terminfo_readkey (input_buf, &npending, serial_hw_fetch);
if (npending)
return input_buf[0];
return -1;
}
/* The serial version of getkey. */
static int
grub_serial_getkey (struct grub_term_input *term __attribute__ ((unused)))
{
int ret;
while (! npending)
grub_terminfo_readkey (input_buf, &npending, serial_hw_fetch);
ret = input_buf[0];
npending--;
grub_memmove (input_buf, input_buf + 1, npending);
return ret;
}
/* Initialize a serial device. PORT is the port number for a serial device.
SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600,
19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used
@ -219,150 +179,56 @@ serial_hw_init (void)
#endif
/* Drain the input buffer. */
while (grub_serial_checkkey (0) != -1)
(void) grub_serial_getkey (0);
while (serial_hw_fetch () != -1);
/* FIXME: should check if the serial terminal was found. */
return GRUB_ERR_NONE;
}
/* The serial version of putchar. */
static void
grub_serial_putchar (struct grub_term_output *term __attribute__ ((unused)),
const struct grub_unicode_glyph *c)
{
/* Keep track of the cursor. */
if (keep_track)
{
switch (c->base)
{
case '\a':
break;
case '\b':
case 127:
if (xpos > 0)
xpos--;
break;
case '\n':
if (ypos < TEXT_HEIGHT - 1)
ypos++;
break;
case '\r':
xpos = 0;
break;
default:
if ((c->base & 0xC0) == 0x80)
break;
if (xpos + c->estimated_width >= TEXT_WIDTH + 1)
{
xpos = 0;
if (ypos < TEXT_HEIGHT - 1)
ypos++;
serial_hw_put ('\r');
serial_hw_put ('\n');
}
xpos += c->estimated_width;
break;
}
}
serial_hw_put (c->base);
}
static grub_uint16_t
grub_serial_getwh (struct grub_term_output *term __attribute__ ((unused)))
{
const grub_uint8_t TEXT_WIDTH = 80;
const grub_uint8_t TEXT_HEIGHT = 24;
return (TEXT_WIDTH << 8) | TEXT_HEIGHT;
}
static grub_uint16_t
grub_serial_getxy (struct grub_term_output *term __attribute__ ((unused)))
struct grub_terminfo_input_state grub_serial_terminfo_input =
{
return ((xpos << 8) | ypos);
}
.readkey = serial_hw_fetch
};
static void
grub_serial_gotoxy (struct grub_term_output *term __attribute__ ((unused)),
grub_uint8_t x, grub_uint8_t y)
struct grub_terminfo_output_state grub_serial_terminfo_output =
{
if (x > TEXT_WIDTH || y > TEXT_HEIGHT)
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "invalid point (%u,%u)", x, y);
}
else
{
keep_track = 0;
grub_terminfo_gotoxy (x, y, &grub_serial_term_output);
keep_track = 1;
xpos = x;
ypos = y;
}
}
static void
grub_serial_cls (struct grub_term_output *term __attribute__ ((unused)))
{
keep_track = 0;
grub_terminfo_cls (&grub_serial_term_output);
keep_track = 1;
xpos = ypos = 0;
}
static void
grub_serial_setcolorstate (struct grub_term_output *term __attribute__ ((unused)),
const grub_term_color_state state)
{
keep_track = 0;
switch (state)
{
case GRUB_TERM_COLOR_STANDARD:
case GRUB_TERM_COLOR_NORMAL:
grub_terminfo_reverse_video_off (&grub_serial_term_output);
break;
case GRUB_TERM_COLOR_HIGHLIGHT:
grub_terminfo_reverse_video_on (&grub_serial_term_output);
break;
default:
break;
}
keep_track = 1;
}
static void
grub_serial_setcursor (struct grub_term_output *term __attribute__ ((unused)),
const int on)
{
if (on)
grub_terminfo_cursor_on (&grub_serial_term_output);
else
grub_terminfo_cursor_off (&grub_serial_term_output);
}
.put = serial_hw_put,
.normal_color = 0x7,
.highlight_color = 0x70
};
static struct grub_term_input grub_serial_term_input =
{
.name = "serial",
.checkkey = grub_serial_checkkey,
.getkey = grub_serial_getkey,
.init = grub_terminfo_input_init,
.checkkey = grub_terminfo_checkkey,
.getkey = grub_terminfo_getkey,
.data = &grub_serial_terminfo_input
};
static struct grub_term_output grub_serial_term_output =
{
.name = "serial",
.putchar = grub_serial_putchar,
.putchar = grub_terminfo_putchar,
.getwh = grub_serial_getwh,
.getxy = grub_serial_getxy,
.gotoxy = grub_serial_gotoxy,
.cls = grub_serial_cls,
.setcolorstate = grub_serial_setcolorstate,
.setcursor = grub_serial_setcursor,
.getxy = grub_terminfo_getxy,
.gotoxy = grub_terminfo_gotoxy,
.cls = grub_terminfo_cls,
.setcolorstate = grub_terminfo_setcolorstate,
.setcolor = grub_terminfo_setcolor,
.getcolor = grub_terminfo_getcolor,
.setcursor = grub_terminfo_setcursor,
.flags = GRUB_TERM_CODE_TYPE_ASCII,
.data = &grub_serial_terminfo_output
};
@ -466,6 +332,7 @@ grub_cmd_serial (grub_extcmd_t cmd,
{
grub_term_register_input ("serial", &grub_serial_term_input);
grub_term_register_output ("serial", &grub_serial_term_output);
grub_terminfo_output_register (&grub_serial_term_output, "vt100");
registered = 1;
}
}
@ -482,6 +349,7 @@ grub_cmd_serial (grub_extcmd_t cmd,
/* If unable to restore settings, unregister terminal. */
grub_term_unregister_input (&grub_serial_term_input);
grub_term_unregister_output (&grub_serial_term_output);
grub_terminfo_output_unregister (&grub_serial_term_output);
registered = 0;
}
}
@ -518,5 +386,6 @@ GRUB_MOD_FINI(serial)
{
grub_term_unregister_input (&grub_serial_term_input);
grub_term_unregister_output (&grub_serial_term_output);
grub_terminfo_output_unregister (&grub_serial_term_output);
}
}

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;
}
/* Hide cursor. */
void
grub_terminfo_cursor_off (grub_term_output_t oterm)
putstr (term, grub_terminfo_tparm (data->setcolor, fg, bg));
return;
}
switch (state)
{
putstr (grub_terminfo_tparm (term.cursor_off), oterm);
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;
}
}
void
grub_terminfo_setcursor (struct grub_term_output *term, const int on)
{
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());
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;
}
else if (argc != 1)
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)

View file

@ -751,6 +751,9 @@ grub_terminfo_tparm (const char *string, ...)
va_list ap;
char *result;
if (!string)
return "";
va_start (ap, string);
result = tparam_internal (string, ap);
va_end (ap);