Core changes hopefully finished

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2009-12-24 15:34:33 +01:00
parent e48625a306
commit 2e71383172
23 changed files with 1493 additions and 947 deletions

View file

@ -41,7 +41,7 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc,
int desclen = grub_strlen (cmd->summary); int desclen = grub_strlen (cmd->summary);
for (cur = grub_term_outputs; cur; cur = cur->next) for (cur = grub_term_outputs; cur; cur = cur->next)
{ {
if (!(cur->flags & GRUB_TERM_ACTIVE)) if (!grub_term_is_active (cur))
continue; continue;
int width = grub_term_width(cur); int width = grub_term_width(cur);
char description[width / 2]; char description[width / 2];

View file

@ -112,4 +112,10 @@ grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src,
/* Convert UCS-4 to UTF-8. */ /* Convert UCS-4 to UTF-8. */
char *grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size); char *grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size);
int
grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize);
int grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
grub_uint32_t **last_position);
#endif #endif

View file

@ -27,17 +27,18 @@
struct grub_menu_viewer struct grub_menu_viewer
{ {
/* The menu viewer name. */
const char *name;
grub_err_t (*show_menu) (grub_menu_t menu, int nested);
struct grub_menu_viewer *next; struct grub_menu_viewer *next;
void *data;
void (*set_chosen_entry) (int entry, void *data);
void (*print_timeout) (int timeout, void *data);
void (*clear_timeout) (void *data);
void (*fini) (void *fini);
}; };
typedef struct grub_menu_viewer *grub_menu_viewer_t;
void grub_menu_viewer_register (grub_menu_viewer_t viewer); void grub_menu_register_viewer (struct grub_menu_viewer *viewer);
grub_err_t grub_menu_viewer_show_menu (grub_menu_t menu, int nested); grub_err_t grub_menu_register_viewer_init (void (*callback) (int entry,
grub_menu_t menu,
int nested));
#endif /* GRUB_MENU_VIEWER_HEADER */ #endif /* GRUB_MENU_VIEWER_HEADER */

View file

@ -183,7 +183,7 @@ int EXPORT_FUNC(grub_sprintf) (char *str, const char *fmt, ...) __attribute__ ((
int EXPORT_FUNC(grub_vsprintf) (char *str, const char *fmt, va_list args); int EXPORT_FUNC(grub_vsprintf) (char *str, const char *fmt, va_list args);
void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn));
void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn));
grub_ssize_t EXPORT_FUNC(grub_utf8_to_ucs4) (grub_uint32_t *dest, grub_size_t EXPORT_FUNC(grub_utf8_to_ucs4) (grub_uint32_t *dest,
grub_size_t destsize, grub_size_t destsize,
const grub_uint8_t *src, const grub_uint8_t *src,
grub_size_t srcsize, grub_size_t srcsize,

View file

@ -51,15 +51,16 @@ extern struct grub_menu_viewer grub_normal_text_menu_viewer;
/* Defined in `main.c'. */ /* Defined in `main.c'. */
void grub_enter_normal_mode (const char *config); void grub_enter_normal_mode (const char *config);
void grub_normal_execute (const char *config, int nested, int batch); void grub_normal_execute (const char *config, int nested, int batch);
void grub_menu_init_page (int nested, int edit,
struct grub_term_output *term);
void grub_normal_init_page (struct grub_term_output *term); void grub_normal_init_page (struct grub_term_output *term);
void grub_menu_init_page (int nested, int edit);
grub_err_t grub_normal_add_menu_entry (int argc, const char **args, grub_err_t grub_normal_add_menu_entry (int argc, const char **args,
const char *sourcecode); const char *sourcecode);
char *grub_file_getline (grub_file_t file); char *grub_file_getline (grub_file_t file);
void grub_cmdline_run (int nested); void grub_cmdline_run (int nested);
/* Defined in `cmdline.c'. */ /* Defined in `cmdline.c'. */
char *grub_cmdline_get (const char *prompt, unsigned max_len); char *grub_cmdline_get (const char *prompt);
grub_err_t grub_set_history (int newsize); grub_err_t grub_set_history (int newsize);
/* Defined in `completion.c'. */ /* Defined in `completion.c'. */
@ -76,14 +77,19 @@ void grub_parse_color_name_pair (grub_uint8_t *ret, const char *name);
/* Defined in `menu_text.c'. */ /* Defined in `menu_text.c'. */
void grub_wait_after_message (void); void grub_wait_after_message (void);
int grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
grub_uint32_t **last_position);
void grub_print_ucs4 (const grub_uint32_t * str, void grub_print_ucs4 (const grub_uint32_t * str,
const grub_uint32_t * last_position); const grub_uint32_t * last_position,
struct grub_term_output *term);
grub_ssize_t grub_getstringwidth (grub_uint32_t * str, grub_ssize_t grub_getstringwidth (grub_uint32_t * str,
const grub_uint32_t * last_position); const grub_uint32_t * last_position,
struct grub_term_output *term);
void grub_print_message_indented (const char *msg, int margin_left, void grub_print_message_indented (const char *msg, int margin_left,
int margin_right); int margin_right,
struct grub_term_output *term);
void
grub_menu_text_register_instances (int entry, grub_menu_t menu, int nested);
grub_err_t
grub_show_menu (grub_menu_t menu, int nested);
/* Defined in `handler.c'. */ /* Defined in `handler.c'. */
void read_handler_list (void); void read_handler_list (void);

View file

@ -111,37 +111,12 @@ grub_term_color_state;
/* The X position of the left border. */ /* The X position of the left border. */
#define GRUB_TERM_LEFT_BORDER_X GRUB_TERM_MARGIN #define GRUB_TERM_LEFT_BORDER_X GRUB_TERM_MARGIN
/* The width of the border. */
#define GRUB_TERM_BORDER_WIDTH (GRUB_TERM_WIDTH \
- GRUB_TERM_MARGIN * 3 \
- GRUB_TERM_SCROLL_WIDTH)
/* The number of lines of messages at the bottom. */ /* The number of lines of messages at the bottom. */
#define GRUB_TERM_MESSAGE_HEIGHT 8 #define GRUB_TERM_MESSAGE_HEIGHT 8
/* The height of the border. */
#define GRUB_TERM_BORDER_HEIGHT (GRUB_TERM_HEIGHT \
- GRUB_TERM_TOP_BORDER_Y \
- GRUB_TERM_MESSAGE_HEIGHT)
/* The number of entries shown at a time. */
#define GRUB_TERM_NUM_ENTRIES (GRUB_TERM_BORDER_HEIGHT - 2)
/* The Y position of the first entry. */ /* The Y position of the first entry. */
#define GRUB_TERM_FIRST_ENTRY_Y (GRUB_TERM_TOP_BORDER_Y + 1) #define GRUB_TERM_FIRST_ENTRY_Y (GRUB_TERM_TOP_BORDER_Y + 1)
/* The max column number of an entry. The last "-1" is for a
continuation marker. */
#define GRUB_TERM_ENTRY_WIDTH (GRUB_TERM_BORDER_WIDTH - 2 \
- GRUB_TERM_MARGIN * 2 - 1)
/* The standard X position of the cursor. */
#define GRUB_TERM_CURSOR_X (GRUB_TERM_LEFT_BORDER_X \
+ GRUB_TERM_BORDER_WIDTH \
- GRUB_TERM_MARGIN \
- 1)
struct grub_term_input struct grub_term_input
{ {
/* The next terminal. */ /* The next terminal. */
@ -277,16 +252,123 @@ void grub_puts_terminal (const char *str, struct grub_term_output *term);
grub_uint16_t *grub_term_save_pos (void); grub_uint16_t *grub_term_save_pos (void);
void grub_term_restore_pos (grub_uint16_t *pos); void grub_term_restore_pos (grub_uint16_t *pos);
static inline int grub_term_width (struct grub_term_output *term) static inline unsigned grub_term_width (struct grub_term_output *term)
{ {
return ((term->getwh()&0xFF00)>>8); return ((term->getwh()&0xFF00)>>8);
} }
static inline int grub_term_height (struct grub_term_output *term) static inline unsigned grub_term_height (struct grub_term_output *term)
{ {
return (term->getwh()&0xFF); return (term->getwh()&0xFF);
} }
/* The width of the border. */
static inline unsigned
grub_term_border_width (struct grub_term_output *term)
{
return grub_term_width (term) - GRUB_TERM_MARGIN * 3 - GRUB_TERM_SCROLL_WIDTH;
}
/* The max column number of an entry. The last "-1" is for a
continuation marker. */
static inline int
grub_term_entry_width (struct grub_term_output *term)
{
return grub_term_border_width (term) - 2 - GRUB_TERM_MARGIN * 2 - 1;
}
/* The height of the border. */
static inline unsigned
grub_term_border_height (struct grub_term_output *term)
{
return grub_term_height (term) - GRUB_TERM_TOP_BORDER_Y
- GRUB_TERM_MESSAGE_HEIGHT;
}
/* The number of entries shown at a time. */
static inline int
grub_term_num_entries (struct grub_term_output *term)
{
return grub_term_border_height (term) - 2;
}
static inline int
grub_term_cursor_x (struct grub_term_output *term)
{
return (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
- GRUB_TERM_MARGIN - 1);
}
static inline grub_uint16_t
grub_term_getxy (struct grub_term_output *term)
{
return term->getxy ();
}
static inline void
grub_term_refresh (struct grub_term_output *term)
{
if (term->refresh)
term->refresh ();
}
static inline void
grub_term_gotoxy (struct grub_term_output *term, grub_uint8_t x, grub_uint8_t y)
{
term->gotoxy (x, y);
}
static inline void
grub_term_setcolorstate (struct grub_term_output *term,
grub_term_color_state state)
{
if (term->setcolorstate)
term->setcolorstate (state);
}
/* Set the normal color and the highlight color. The format of each
color is VGA's. */
static inline void
grub_term_setcolor (struct grub_term_output *term,
grub_uint8_t normal_color, grub_uint8_t highlight_color)
{
if (term->setcolor)
term->setcolor (normal_color, highlight_color);
}
/* Turn on/off the cursor. */
static inline void
grub_term_setcursor (struct grub_term_output *term, int on)
{
if (term->setcursor)
term->setcursor (on);
}
static inline int
grub_term_is_active (struct grub_term_output *term)
{
return !!(term->flags & GRUB_TERM_ACTIVE);
}
static inline grub_ssize_t
grub_term_getcharwidth (struct grub_term_output *term, grub_uint32_t c)
{
if (term->getcharwidth)
return term->getcharwidth (c);
else
return 1;
}
static inline void
grub_term_getcolor (struct grub_term_output *term,
grub_uint8_t *normal_color, grub_uint8_t *highlight_color)
{
term->getcolor (normal_color, highlight_color);
}
extern void (*EXPORT_VAR (grub_newline_hook)) (void);
/* For convenience. */ /* For convenience. */
#define GRUB_TERM_ASCII_CHAR(c) ((c) & 0xff) #define GRUB_TERM_ASCII_CHAR(c) ((c) & 0xff)

View file

@ -882,10 +882,10 @@ grub_sprintf (char *str, const char *fmt, ...)
/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE /* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE
bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string. bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string.
Return the number of characters converted. DEST must be able to hold Return the number of characters converted. DEST must be able to hold
at least DESTSIZE characters. If an invalid sequence is found, return -1. at least DESTSIZE characters.
If SRCEND is not NULL, then *SRCEND is set to the next byte after the If SRCEND is not NULL, then *SRCEND is set to the next byte after the
last byte used in SRC. */ last byte used in SRC. */
grub_ssize_t grub_size_t
grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
const grub_uint8_t *src, grub_size_t srcsize, const grub_uint8_t *src, grub_size_t srcsize,
const grub_uint8_t **srcend) const grub_uint8_t **srcend)
@ -907,7 +907,8 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
if ((c & 0xc0) != 0x80) if ((c & 0xc0) != 0x80)
{ {
/* invalid */ /* invalid */
return -1; code = '?';
count = 0;
} }
else else
{ {
@ -949,7 +950,11 @@ grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize,
code = c & 0x01; code = c & 0x01;
} }
else else
return -1; {
/* invalid */
code = '?';
count = 0;
}
} }
if (count == 0) if (count == 0)

View file

@ -31,13 +31,15 @@ struct grub_handler_class grub_term_input_class =
struct grub_term_output *grub_term_outputs; struct grub_term_output *grub_term_outputs;
void (*grub_newline_hook) (void) = NULL;
/* Put a Unicode character. */ /* Put a Unicode character. */
void void
grub_putcode (grub_uint32_t code, struct grub_term_output *term) grub_putcode (grub_uint32_t code, struct grub_term_output *term)
{ {
int height; int height;
height = term->getwh () & 255; height = grub_term_height (term);
if (code == '\t' && term->getxy) if (code == '\t' && term->getxy)
{ {
@ -50,6 +52,8 @@ grub_putcode (grub_uint32_t code, struct grub_term_output *term)
return; return;
} }
if (code == '\n')
(term->putchar) ('\r');
(term->putchar) (code); (term->putchar) (code);
} }
@ -68,7 +72,7 @@ grub_putchar (int c)
{ {
struct grub_term_output *term = (struct grub_term_output *) item; struct grub_term_output *term = (struct grub_term_output *) item;
if (term->flags & GRUB_TERM_ACTIVE) if (grub_term_is_active (term))
grub_putcode (code, term); grub_putcode (code, term);
return 0; return 0;
@ -77,14 +81,13 @@ grub_putchar (int c)
buf[size++] = c; buf[size++] = c;
ret = grub_utf8_to_ucs4 (&code, 1, buf, size, 0); ret = grub_utf8_to_ucs4 (&code, 1, buf, size, 0);
if (ret < 0)
code = '?';
if (ret != 0) if (ret != 0)
{ {
size = 0; size = 0;
grub_list_iterate (GRUB_AS_LIST (grub_term_outputs), do_putcode); grub_list_iterate (GRUB_AS_LIST (grub_term_outputs), do_putcode);
} }
if (ret == '\n' && grub_newline_hook)
grub_newline_hook ();
} }
int int
@ -116,7 +119,7 @@ grub_cls (void)
{ {
struct grub_term_output *term = (struct grub_term_output *) item; struct grub_term_output *term = (struct grub_term_output *) item;
if (!(term->flags & GRUB_TERM_ACTIVE)) if (! grub_term_is_active (term))
return 0; return 0;
if ((term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug"))) if ((term->flags & GRUB_TERM_DUMB) || (grub_env_get ("debug")))
@ -141,11 +144,10 @@ grub_setcolorstate (grub_term_color_state state)
{ {
struct grub_term_output *term = (struct grub_term_output *) item; struct grub_term_output *term = (struct grub_term_output *) item;
if (!(term->flags & GRUB_TERM_ACTIVE)) if (! grub_term_is_active (term))
return 0; return 0;
if (term->setcolorstate) grub_term_setcolorstate (term, state);
(term->setcolorstate) (state);
return 0; return 0;
} }
@ -161,11 +163,10 @@ grub_refresh (void)
{ {
struct grub_term_output *term = (struct grub_term_output *) item; struct grub_term_output *term = (struct grub_term_output *) item;
if (!(term->flags & GRUB_TERM_ACTIVE)) if (!grub_term_is_active (term))
return 0; return 0;
if (term->refresh) grub_term_refresh (term);
(term->refresh) ();
return 0; return 0;
} }

View file

@ -24,6 +24,8 @@
last byte used in SRC. */ last byte used in SRC. */
#include <grub/charset.h> #include <grub/charset.h>
#include <grub/mm.h>
#include <grub/misc.h>
grub_ssize_t grub_ssize_t
grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize,
@ -176,5 +178,92 @@ grub_ucs4_to_utf8_alloc (grub_uint32_t *src, grub_size_t size)
} }
*dest = 0; *dest = 0;
return ret; return (char *) ret;
}
int
grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize)
{
grub_uint32_t code = 0;
int count = 0;
while (srcsize)
{
grub_uint32_t c = *src++;
if (srcsize != (grub_size_t)-1)
srcsize--;
if (count)
{
if ((c & 0xc0) != 0x80)
{
/* invalid */
return 0;
}
else
{
code <<= 6;
code |= (c & 0x3f);
count--;
}
}
else
{
if (c == 0)
break;
if ((c & 0x80) == 0x00)
code = c;
else if ((c & 0xe0) == 0xc0)
{
count = 1;
code = c & 0x1f;
}
else if ((c & 0xf0) == 0xe0)
{
count = 2;
code = c & 0x0f;
}
else if ((c & 0xf8) == 0xf0)
{
count = 3;
code = c & 0x07;
}
else if ((c & 0xfc) == 0xf8)
{
count = 4;
code = c & 0x03;
}
else if ((c & 0xfe) == 0xfc)
{
count = 5;
code = c & 0x01;
}
else
return 0;
}
}
return 1;
}
int
grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
grub_uint32_t **last_position)
{
grub_size_t msg_len = grub_strlen (msg);
*unicode_msg = grub_malloc (grub_strlen (msg) * sizeof (grub_uint32_t));
if (!*unicode_msg)
{
grub_printf ("utf8_to_ucs4 ERROR1: %s", msg);
return -1;
}
msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len,
(grub_uint8_t *) msg, -1, 0);
*last_position = *unicode_msg + msg_len;
return msg_len;
} }

View file

@ -154,6 +154,49 @@ is_authenticated (const char *userlist)
return grub_list_iterate (GRUB_AS_LIST (users), hook); return grub_list_iterate (GRUB_AS_LIST (users), hook);
} }
static int
grub_username_get (char buf[], unsigned buf_size)
{
unsigned cur_len = 0;
int key;
while (1)
{
key = GRUB_TERM_ASCII_CHAR (grub_getkey ());
if (key == '\n' || key == '\r')
break;
if (key == '\e')
{
cur_len = 0;
break;
}
if (key == '\b')
{
cur_len--;
grub_printf ("\b");
continue;
}
if (!grub_isprint (key))
continue;
if (cur_len + 2 < buf_size)
{
buf[cur_len++] = key;
grub_putchar (key);
}
}
grub_memset (buf + cur_len, 0, buf_size - cur_len);
grub_putchar ('\n');
grub_refresh ();
return (key != '\e');
}
grub_err_t grub_err_t
grub_auth_check_authentication (const char *userlist) grub_auth_check_authentication (const char *userlist)
{ {
@ -187,11 +230,12 @@ grub_auth_check_authentication (const char *userlist)
return GRUB_ERR_NONE; return GRUB_ERR_NONE;
} }
if (!grub_cmdline_get (N_("Enter username:"), login, sizeof (login) - 1, grub_puts_ (N_("Enter username: "));
0, 0, 0))
if (!grub_username_get (login, sizeof (login) - 1))
goto access_denied; goto access_denied;
grub_printf ("Enter password: "); grub_puts_ (N_("Enter password: "));
if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN)) if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN))
goto access_denied; goto access_denied;

View file

@ -27,6 +27,7 @@
#include <grub/file.h> #include <grub/file.h>
#include <grub/env.h> #include <grub/env.h>
#include <grub/i18n.h> #include <grub/i18n.h>
#include <grub/charset.h>
static grub_uint32_t *kill_buf; static grub_uint32_t *kill_buf;
@ -211,11 +212,12 @@ struct cmdline_term
otherwise return command line. */ otherwise return command line. */
/* FIXME: The dumb interface is not supported yet. */ /* FIXME: The dumb interface is not supported yet. */
char * char *
grub_cmdline_get (const char *prompt, unsigned max_len) grub_cmdline_get (const char *prompt)
{ {
grub_size_t lpos, llen; grub_size_t lpos, llen;
grub_size_t plen; grub_size_t plen;
grub_uint32_t buf[max_len]; grub_uint32_t *buf;
grub_size_t max_len = 256;
int key; int key;
int histpos = 0; int histpos = 0;
auto void cl_insert (const grub_uint32_t *str); auto void cl_insert (const grub_uint32_t *str);
@ -226,13 +228,14 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
auto void cl_set_pos_all (void); auto void cl_set_pos_all (void);
const char *prompt_translated = _(prompt); const char *prompt_translated = _(prompt);
struct cmdline_term *cl_terms; struct cmdline_term *cl_terms;
char *ret;
unsigned nterms; unsigned nterms;
void cl_set_pos (struct cmdline_term *cl_term) void cl_set_pos (struct cmdline_term *cl_term)
{ {
cl_term->xpos = (plen + lpos) % (cl_term->width - 1); cl_term->xpos = (plen + lpos) % (cl_term->width - 1);
cl_term->ypos = cl_term->ystart + (plen + lpos) / (cl_term->width - 1); cl_term->ypos = cl_term->ystart + (plen + lpos) / (cl_term->width - 1);
cl_term->term->gotoxy (cl_term->xpos, cl_term->ypos); grub_term_gotoxy (cl_term->term, cl_term->xpos, cl_term->ypos);
} }
void cl_set_pos_all () void cl_set_pos_all ()
@ -246,7 +249,7 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
{ {
grub_uint32_t *p; grub_uint32_t *p;
for (p = buf + pos; *p; p++) for (p = buf + pos; p < buf + llen; p++)
{ {
if (cl_term->xpos++ > cl_term->width - 2) if (cl_term->xpos++ > cl_term->width - 2)
{ {
@ -277,14 +280,30 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
{ {
grub_size_t len = strlen_ucs4 (str); grub_size_t len = strlen_ucs4 (str);
if (len + llen >= max_len)
{
grub_uint32_t *nbuf;
max_len *= 2;
nbuf = grub_realloc (buf, sizeof (grub_uint32_t) * max_len);
if (nbuf)
buf = nbuf;
else
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
max_len /= 2;
}
}
if (len + llen < max_len) if (len + llen < max_len)
{ {
grub_memmove (buf + lpos + len, buf + lpos, llen - lpos + 1); grub_memmove (buf + lpos + len, buf + lpos,
grub_memmove (buf + lpos, str, len); (llen - lpos + 1) * sizeof (grub_uint32_t));
grub_memmove (buf + lpos, str, len * sizeof (grub_uint32_t));
llen += len; llen += len;
lpos += len; lpos += len;
cl_print_all (lpos - len, echo_char); cl_print_all (lpos - len, 0);
cl_set_pos_all (); cl_set_pos_all ();
} }
@ -305,7 +324,7 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
grub_memmove (buf + lpos, buf + lpos + len, llen - lpos + 1); grub_memmove (buf + lpos, buf + lpos + len, llen - lpos + 1);
llen -= len; llen -= len;
cl_print_all (lpos, echo_char); cl_print_all (lpos, 0);
cl_set_pos_all (); cl_set_pos_all ();
} }
@ -315,7 +334,7 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
void init_clterm (struct cmdline_term *cl_term_cur) void init_clterm (struct cmdline_term *cl_term_cur)
{ {
cl_term_cur->xpos = plen; cl_term_cur->xpos = plen;
cl_term_cur->ypos = (cl_term_cur->term->getxy () & 0xFF); cl_term_cur->ypos = (grub_term_getxy (cl_term_cur->term) & 0xFF);
cl_term_cur->ystart = cl_term_cur->ypos; cl_term_cur->ystart = cl_term_cur->ypos;
cl_term_cur->width = grub_term_width (cl_term_cur->term); cl_term_cur->width = grub_term_width (cl_term_cur->term);
cl_term_cur->height = grub_term_height (cl_term_cur->term); cl_term_cur->height = grub_term_height (cl_term_cur->term);
@ -328,6 +347,10 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
init_clterm (&cl_terms[i]); init_clterm (&cl_terms[i]);
} }
buf = grub_malloc (max_len * sizeof (grub_uint32_t));
if (!buf)
return 0;
plen = grub_strlen (prompt_translated); plen = grub_strlen (prompt_translated);
lpos = llen = 0; lpos = llen = 0;
buf[0] = '\0'; buf[0] = '\0';
@ -341,15 +364,15 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
struct grub_term_output *cur; struct grub_term_output *cur;
nterms = 0; nterms = 0;
for (cur = grub_term_outputs; cur; cur = cur->next) for (cur = grub_term_outputs; cur; cur = cur->next)
if (cur->flags & GRUB_TERM_ACTIVE) if (grub_term_is_active (cur))
nterms++; nterms++;
cl_terms = grub_malloc (sizeof (cl_terms[0]) * nterms); cl_terms = grub_malloc (sizeof (cl_terms[0]) * nterms);
if (!cl_terms) if (!cl_terms)
return grub_errno; return 0;
cl_term_cur = cl_terms; cl_term_cur = cl_terms;
for (cur = grub_term_outputs; cur; cur = cur->next) for (cur = grub_term_outputs; cur; cur = cur->next)
if (cur->flags & GRUB_TERM_ACTIVE) if (grub_term_is_active (cur))
{ {
cl_term_cur->term = cur; cl_term_cur->term = cur;
init_clterm (cl_term_cur); init_clterm (cl_term_cur);
@ -357,7 +380,7 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
} }
} }
if (history && hist_used == 0) if (hist_used == 0)
grub_history_add (buf); grub_history_add (buf);
while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r') while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r')
@ -394,17 +417,38 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
{ {
grub_uint32_t *insert; grub_uint32_t *insert;
int restore; int restore;
char *bufu8, *insertu8;
grub_size_t insertlen;
grub_size_t t;
/* Backup the next character and make it 0 so it will
be easy to use string functions. */
char backup = buf[lpos];
buf[lpos] = '\0'; buf[lpos] = '\0';
bufu8 = grub_ucs4_to_utf8_alloc (buf, lpos);
if (!bufu8)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
break;
}
insert = grub_normal_do_completion (buf, &restore, insertu8 = grub_normal_do_completion (bufu8, &restore,
print_completion); print_completion);
/* Restore the original string. */ grub_free (bufu8);
buf[lpos] = backup; insertlen = grub_strlen (bufu8);
insert = grub_malloc ((insertlen + 1) * sizeof (grub_uint32_t));
if (!insert)
{
grub_free (insertu8);
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
break;
}
t = grub_utf8_to_ucs4 (insert, insertlen,
(grub_uint8_t *) insertu8,
insertlen, 0);
insert[t] = 0;
grub_free (insertu8);
if (restore) if (restore)
{ {
@ -429,7 +473,11 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
grub_free (kill_buf); grub_free (kill_buf);
kill_buf = strdup_ucs4 (buf + lpos); kill_buf = strdup_ucs4 (buf + lpos);
if (grub_errno)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
}
cl_delete (llen - lpos); cl_delete (llen - lpos);
} }
@ -481,7 +529,11 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
grub_free (kill_buf); grub_free (kill_buf);
kill_buf = grub_malloc (n + 1); kill_buf = grub_malloc (n + 1);
if (grub_errno)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
}
if (kill_buf) if (kill_buf)
{ {
grub_memcpy (kill_buf, buf, n); grub_memcpy (kill_buf, buf, n);
@ -538,8 +590,6 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
while (buf[lpos] == ' ') while (buf[lpos] == ' ')
lpos++; lpos++;
if (history)
{
histpos = 0; histpos = 0;
if (strlen_ucs4 (buf) > 0) if (strlen_ucs4 (buf) > 0)
{ {
@ -547,7 +597,8 @@ grub_cmdline_get (const char *prompt, unsigned max_len)
grub_history_replace (histpos, buf); grub_history_replace (histpos, buf);
grub_history_add (empty); grub_history_add (empty);
} }
}
return grub_ucs4_to_utf8_alloc (buf + lpos, llen - lpos + 1); ret = grub_ucs4_to_utf8_alloc (buf + lpos, llen - lpos + 1);
grub_free (buf);
return ret;
} }

View file

@ -112,16 +112,14 @@ set_colors (void)
for (term = grub_term_outputs; term; term = term->next) for (term = grub_term_outputs; term; term = term->next)
{ {
if (! (term->flags & GRUB_TERM_ACTIVE)) if (! grub_term_is_active (term))
continue; continue;
/* Reloads terminal `normal' and `highlight' colors. */ /* Reloads terminal `normal' and `highlight' colors. */
if (term->setcolor) grub_term_setcolor (term, color_normal, color_highlight);
term->setcolor (color_normal, color_highlight);
/* Propagates `normal' color to terminal current color. */ /* Propagates `normal' color to terminal current color. */
if (term->setcolorstate) grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
term->setcolorstate (GRUB_TERM_COLOR_NORMAL);
} }
} }

View file

@ -30,6 +30,7 @@
#include <grub/menu_viewer.h> #include <grub/menu_viewer.h>
#include <grub/auth.h> #include <grub/auth.h>
#include <grub/i18n.h> #include <grub/i18n.h>
#include <grub/charset.h>
#define GRUB_DEFAULT_HISTORY_SIZE 50 #define GRUB_DEFAULT_HISTORY_SIZE 50
@ -420,11 +421,11 @@ grub_normal_init_page (struct grub_term_output *term)
return; return;
} }
posx = grub_getstringwidth (unicode_msg, last_position); posx = grub_getstringwidth (unicode_msg, last_position, term);
posx = (grub_term_width (term) - posx) / 2; posx = (grub_term_width (term) - posx) / 2;
term->gotoxy (posx, 1); grub_term_gotoxy (term, posx, 1);
grub_print_ucs4 (unicode_msg, last_position); grub_print_ucs4 (unicode_msg, last_position, term);
grub_printf("\n\n"); grub_printf("\n\n");
grub_free (unicode_msg); grub_free (unicode_msg);
} }
@ -458,7 +459,7 @@ grub_normal_execute (const char *config, int nested, int batch)
{ {
if (menu && menu->size) if (menu && menu->size)
{ {
grub_menu_viewer_show_menu (menu, nested); grub_show_menu (menu, nested);
if (nested) if (nested)
free_menu (menu); free_menu (menu);
} }
@ -470,20 +471,19 @@ void
grub_enter_normal_mode (const char *config) grub_enter_normal_mode (const char *config)
{ {
grub_normal_execute (config, 0, 0); grub_normal_execute (config, 0, 0);
grub_cmdline_run (1);
} }
/* Enter normal mode from rescue mode. */ /* Enter normal mode from rescue mode. */
static grub_err_t static grub_err_t
grub_cmd_normal (struct grub_command *cmd, grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
int argc, char *argv[]) int argc, char *argv[])
{ {
grub_unregister_command (cmd);
if (argc == 0) if (argc == 0)
{ {
/* Guess the config filename. It is necessary to make CONFIG static, /* Guess the config filename. It is necessary to make CONFIG static,
so that it won't get broken by longjmp. */ so that it won't get broken by longjmp. */
static char *config; char *config;
const char *prefix; const char *prefix;
prefix = grub_env_get ("prefix"); prefix = grub_env_get ("prefix");
@ -525,10 +525,9 @@ grub_normal_reader_init (void)
if (! (term->flags & GRUB_TERM_ACTIVE)) if (! (term->flags & GRUB_TERM_ACTIVE))
continue; continue;
grub_normal_init_page (term); grub_normal_init_page (term);
if (term->setcursor) grub_term_setcursor (term, 1);
term->setcursor (1);
grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN); grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term);
grub_puts ("\n"); grub_puts ("\n");
} }
grub_free (msg_formatted); grub_free (msg_formatted);
@ -536,7 +535,6 @@ grub_normal_reader_init (void)
return 0; return 0;
} }
static char cmdline[GRUB_MAX_CMDLINE];
static grub_err_t static grub_err_t
grub_normal_read_line (char **line, int cont) grub_normal_read_line (char **line, int cont)
@ -548,18 +546,18 @@ grub_normal_read_line (char **line, int cont)
while (1) while (1)
{ {
cmdline[0] = 0; *line = grub_cmdline_get (prompt);
if (grub_cmdline_get (prompt, cmdline, sizeof (cmdline), 0, 1, 1)) if (*line)
break; break;
if ((reader_nested) || (cont)) if ((reader_nested) || (cont))
{ {
grub_free (*line);
*line = 0; *line = 0;
return grub_errno; return grub_errno;
} }
} }
*line = grub_strdup (cmdline);
return 0; return 0;
} }
@ -591,7 +589,7 @@ grub_cmdline_run (int nested)
grub_normal_read_line (&line, 0); grub_normal_read_line (&line, 0);
if (! line) if (! line)
continue; break;
grub_parser_get_current ()->parse_line (line, grub_normal_read_line); grub_parser_get_current ()->parse_line (line, grub_normal_read_line);
grub_free (line); grub_free (line);
@ -612,15 +610,20 @@ GRUB_MOD_INIT(normal)
if (mod) if (mod)
grub_dl_ref (mod); grub_dl_ref (mod);
grub_menu_viewer_register (&grub_normal_text_menu_viewer);
grub_set_history (GRUB_DEFAULT_HISTORY_SIZE); grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
grub_menu_register_viewer_init (grub_menu_text_register_instances);
if (grub_errno)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
}
grub_register_variable_hook ("pager", 0, grub_env_write_pager); grub_register_variable_hook ("pager", 0, grub_env_write_pager);
/* Register a command "normal" for the rescue mode. */ /* Register a command "normal" for the rescue mode. */
grub_register_command_prio ("normal", grub_cmd_normal, grub_register_command ("normal", grub_cmd_normal,
0, "Enter normal mode", 0); 0, "Enter normal mode");
/* Reload terminal colors when these variables are written to. */ /* Reload terminal colors when these variables are written to. */
grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal); grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);

View file

@ -27,6 +27,30 @@
#include <grub/command.h> #include <grub/command.h>
#include <grub/parser.h> #include <grub/parser.h>
#include <grub/auth.h> #include <grub/auth.h>
#include <grub/i18n.h>
/* Time to delay after displaying an error message about a default/fallback
entry failing to boot. */
#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500
struct menu_run_callback
{
struct menu_run_callback *next;
void (*hook) (int entry, grub_menu_t menu, int nested);
};
struct menu_run_callback *callbacks = NULL;
/* Wait until the user pushes any key so that the user
can see what happened. */
void
grub_wait_after_message (void)
{
grub_putchar ('\n');
grub_printf_ (N_("Press any key to continue..."));
(void) grub_getkey ();
grub_putchar ('\n');
}
/* Get a menu entry by its index in the entry list. */ /* Get a menu entry by its index in the entry list. */
grub_menu_entry_t grub_menu_entry_t
@ -178,3 +202,364 @@ grub_menu_execute_with_fallback (grub_menu_t menu,
callback->notify_failure (callback_data); callback->notify_failure (callback_data);
} }
static struct grub_menu_viewer *viewers;
static void
menu_set_chosen_entry (int entry)
{
struct grub_menu_viewer *cur;
for (cur = viewers; cur; cur = cur->next)
cur->set_chosen_entry (entry, cur->data);
}
static void
menu_print_timeout (int timeout)
{
struct grub_menu_viewer *cur;
for (cur = viewers; cur; cur = cur->next)
cur->print_timeout (timeout, cur->data);
}
static void
menu_fini (void)
{
struct grub_menu_viewer *cur, *next;
for (cur = viewers; cur; cur = next)
{
next = cur->next;
cur->fini (cur->data);
grub_free (cur);
}
viewers = NULL;
}
static void
menu_init (int entry, grub_menu_t menu, int nested)
{
struct menu_run_callback *cb;
for (cb = callbacks; cb; cb = cb->next)
cb->hook (entry, menu, nested);
}
static void
clear_timeout (void)
{
struct grub_menu_viewer *cur;
for (cur = viewers; cur; cur = cur->next)
cur->clear_timeout (cur->data);
}
void
grub_menu_register_viewer (struct grub_menu_viewer *viewer)
{
viewer->next = viewers;
viewers = viewer;
}
grub_err_t
grub_menu_register_viewer_init (void (*callback) (int entry, grub_menu_t menu,
int nested))
{
struct menu_run_callback *cb;
cb = grub_malloc (sizeof (*cb));
if (!cb)
return grub_errno;
cb->hook = callback;
cb->next = callbacks;
callbacks = cb;
return GRUB_ERR_NONE;
}
/* Get the entry number from the variable NAME. */
static int
get_entry_number (const char *name)
{
char *val;
int entry;
val = grub_env_get (name);
if (! val)
return -1;
grub_error_push ();
entry = (int) grub_strtoul (val, 0, 0);
if (grub_errno != GRUB_ERR_NONE)
{
grub_errno = GRUB_ERR_NONE;
entry = -1;
}
grub_error_pop ();
return entry;
}
#define GRUB_MENU_PAGE_SIZE 10
/* Show the menu and handle menu entry selection. Returns the menu entry
index that should be executed or -1 if no entry should be executed (e.g.,
Esc pressed to exit a sub-menu or switching menu viewers).
If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu
entry to be executed is a result of an automatic default selection because
of the timeout. */
static int
run_menu (grub_menu_t menu, int nested, int *auto_boot)
{
grub_uint64_t saved_time;
int default_entry, current_entry;
int timeout;
default_entry = get_entry_number ("default");
/* If DEFAULT_ENTRY is not within the menu entries, fall back to
the first entry. */
if (default_entry < 0 || default_entry >= menu->size)
default_entry = 0;
/* If timeout is 0, drawing is pointless (and ugly). */
if (grub_menu_get_timeout () == 0)
{
*auto_boot = 1;
return default_entry;
}
current_entry = default_entry;
/* Initialize the time. */
saved_time = grub_get_time_ms ();
refresh:
menu_init (current_entry, menu, nested);
timeout = grub_menu_get_timeout ();
if (timeout > 0)
menu_print_timeout (timeout);
while (1)
{
int c;
timeout = grub_menu_get_timeout ();
if (timeout > 0)
{
grub_uint64_t current_time;
current_time = grub_get_time_ms ();
if (current_time - saved_time >= 1000)
{
timeout--;
grub_menu_set_timeout (timeout);
saved_time = current_time;
menu_print_timeout (timeout);
}
}
if (timeout == 0)
{
grub_env_unset ("timeout");
*auto_boot = 1;
menu_fini ();
return default_entry;
}
if (grub_checkkey () >= 0 || timeout < 0)
{
c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
if (timeout >= 0)
{
grub_env_unset ("timeout");
grub_env_unset ("fallback");
clear_timeout ();
}
switch (c)
{
case GRUB_TERM_HOME:
current_entry = 0;
menu_set_chosen_entry (current_entry);
break;
case GRUB_TERM_END:
current_entry = menu->size - 1;
menu_set_chosen_entry (current_entry);
break;
case GRUB_TERM_UP:
case '^':
current_entry--;
menu_set_chosen_entry (current_entry);
break;
case GRUB_TERM_DOWN:
case 'v':
current_entry++;
menu_set_chosen_entry (current_entry);
break;
case GRUB_TERM_PPAGE:
if (current_entry < GRUB_MENU_PAGE_SIZE)
current_entry = 0;
else
current_entry -= GRUB_MENU_PAGE_SIZE;
menu_set_chosen_entry (current_entry);
break;
case GRUB_TERM_NPAGE:
if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size)
current_entry = 0;
else
current_entry += GRUB_MENU_PAGE_SIZE;
menu_set_chosen_entry (current_entry);
break;
case '\n':
case '\r':
case 6:
menu_fini ();
*auto_boot = 0;
return current_entry;
case '\e':
if (nested)
{
menu_fini ();
return -1;
}
break;
case 'c':
grub_cmdline_run (1);
goto refresh;
case 'e':
{
grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry);
if (e)
grub_menu_entry_run (e);
}
goto refresh;
default:
break;
}
}
}
/* Never reach here. */
return -1;
}
/* Callback invoked immediately before a menu entry is executed. */
static void
notify_booting (grub_menu_entry_t entry,
void *userdata __attribute__((unused)))
{
grub_printf (" ");
grub_printf_ (N_("Booting \'%s\'"), entry->title);
grub_printf ("\n\n");
}
/* Callback invoked when a default menu entry executed because of a timeout
has failed and an attempt will be made to execute the next fallback
entry, ENTRY. */
static void
notify_fallback (grub_menu_entry_t entry,
void *userdata __attribute__((unused)))
{
grub_printf ("\n ");
grub_printf_ (N_("Falling back to \'%s\'"), entry->title);
grub_printf ("\n\n");
grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS);
}
/* Callback invoked when a menu entry has failed and there is no remaining
fallback entry to attempt. */
static void
notify_execution_failure (void *userdata __attribute__((unused)))
{
if (grub_errno != GRUB_ERR_NONE)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
}
grub_printf ("\n ");
grub_printf_ (N_("Failed to boot default entries.\n"));
grub_wait_after_message ();
}
/* Callbacks used by the text menu to provide user feedback when menu entries
are executed. */
static struct grub_menu_execute_callback execution_callback =
{
.notify_booting = notify_booting,
.notify_fallback = notify_fallback,
.notify_failure = notify_execution_failure
};
static grub_err_t
show_menu (grub_menu_t menu, int nested)
{
while (1)
{
int boot_entry;
grub_menu_entry_t e;
int auto_boot;
boot_entry = run_menu (menu, nested, &auto_boot);
if (boot_entry < 0)
break;
e = grub_menu_get_entry (menu, boot_entry);
if (! e)
continue; /* Menu is empty. */
grub_cls ();
if (auto_boot)
{
grub_menu_execute_with_fallback (menu, e, &execution_callback, 0);
}
else
{
grub_errno = GRUB_ERR_NONE;
grub_menu_execute_entry (e);
if (grub_errno != GRUB_ERR_NONE)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
grub_wait_after_message ();
}
}
}
return GRUB_ERR_NONE;
}
grub_err_t
grub_show_menu (grub_menu_t menu, int nested)
{
grub_err_t err1, err2;
while (1)
{
err1 = show_menu (menu, nested);
grub_print_error ();
err2 = grub_auth_check_authentication (NULL);
if (err2)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
continue;
}
break;
}
return err1;
}

File diff suppressed because it is too large Load diff

View file

@ -26,96 +26,66 @@
#include <grub/env.h> #include <grub/env.h>
#include <grub/menu_viewer.h> #include <grub/menu_viewer.h>
#include <grub/i18n.h> #include <grub/i18n.h>
#include <grub/charset.h>
/* Time to delay after displaying an error message about a default/fallback
entry failing to boot. */
#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500
static grub_uint8_t grub_color_menu_normal; static grub_uint8_t grub_color_menu_normal;
static grub_uint8_t grub_color_menu_highlight; static grub_uint8_t grub_color_menu_highlight;
/* Wait until the user pushes any key so that the user struct menu_viewer_data
can see what happened. */
void
grub_wait_after_message (void)
{ {
grub_putchar ('\n'); int first, offset;
grub_printf_ (N_("Press any key to continue...")); grub_menu_t menu;
(void) grub_getkey (); struct grub_term_output *term;
grub_putchar ('\n'); };
}
static void static void
print_spaces (int number_spaces) print_spaces (int number_spaces, struct grub_term_output *term)
{ {
int i; int i;
for (i = 0; i < number_spaces; i++) for (i = 0; i < number_spaces; i++)
grub_putchar (' '); grub_putcode (' ', term);
} }
void void
grub_print_ucs4 (const grub_uint32_t * str, grub_print_ucs4 (const grub_uint32_t * str,
const grub_uint32_t * last_position) const grub_uint32_t * last_position,
struct grub_term_output *term)
{ {
while (str < last_position) while (str < last_position)
{ {
grub_putcode (*str); grub_putcode (*str, term);
str++; str++;
} }
} }
int
grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg,
grub_uint32_t **last_position)
{
grub_ssize_t msg_len = grub_strlen (msg);
*unicode_msg = grub_malloc (grub_strlen (msg) * sizeof (grub_uint32_t));
if (!*unicode_msg)
{
grub_printf ("utf8_to_ucs4 ERROR1: %s", msg);
return -1;
}
msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len,
(grub_uint8_t *) msg, -1, 0);
*last_position = *unicode_msg + msg_len;
if (msg_len < 0)
{
grub_printf ("utf8_to_ucs4 ERROR2: %s", msg);
grub_free (*unicode_msg);
}
return msg_len;
}
grub_ssize_t grub_ssize_t
grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position) grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position,
struct grub_term_output *term)
{ {
grub_ssize_t width = 0; grub_ssize_t width = 0;
while (str < last_position) while (str < last_position)
{ {
width += grub_getcharwidth (*str); width += grub_term_getcharwidth (term, *str);
str++; str++;
} }
return width; return width;
} }
void void
grub_print_message_indented (const char *msg, int margin_left, int margin_right) grub_print_message_indented (const char *msg, int margin_left, int margin_right,
struct grub_term_output *term)
{ {
int line_len; int line_len;
line_len = GRUB_TERM_WIDTH - grub_getcharwidth ('m') *
(margin_left + margin_right);
grub_uint32_t *unicode_msg; grub_uint32_t *unicode_msg;
grub_uint32_t *last_position; grub_uint32_t *last_position;
int msg_len; int msg_len;
line_len = grub_term_width (term) - grub_term_getcharwidth (term, 'm') *
(margin_left + margin_right);
msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position); msg_len = grub_utf8_to_ucs4_alloc (msg, &unicode_msg, &last_position);
if (msg_len < 0) if (msg_len < 0)
@ -132,11 +102,12 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right)
while (current_position < last_position) while (current_position < last_position)
{ {
if (! first_loop) if (! first_loop)
grub_putchar ('\n'); grub_putcode ('\n', term);
next_new_line = (grub_uint32_t *) last_position; next_new_line = (grub_uint32_t *) last_position;
while (grub_getstringwidth (current_position, next_new_line) > line_len while (grub_getstringwidth (current_position, next_new_line,term)
> line_len
|| (*next_new_line != ' ' && next_new_line > current_position && || (*next_new_line != ' ' && next_new_line > current_position &&
next_new_line != last_position)) next_new_line != last_position))
{ {
@ -149,8 +120,8 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right)
(grub_uint32_t *) last_position : next_new_line + line_len; (grub_uint32_t *) last_position : next_new_line + line_len;
} }
print_spaces (margin_left); print_spaces (margin_left, term);
grub_print_ucs4 (current_position, next_new_line); grub_print_ucs4 (current_position, next_new_line, term);
next_new_line++; next_new_line++;
current_position = next_new_line; current_position = next_new_line;
@ -161,52 +132,54 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right)
static void static void
draw_border (void) draw_border (struct grub_term_output *term)
{ {
unsigned i; unsigned i;
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y); grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y);
grub_putcode (GRUB_TERM_DISP_UL); grub_putcode (GRUB_TERM_DISP_UL, term);
for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++) for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++)
grub_putcode (GRUB_TERM_DISP_HLINE); grub_putcode (GRUB_TERM_DISP_HLINE, term);
grub_putcode (GRUB_TERM_DISP_UR); grub_putcode (GRUB_TERM_DISP_UR, term);
for (i = 0; i < (unsigned) GRUB_TERM_NUM_ENTRIES; i++) for (i = 0; i < (unsigned) grub_term_num_entries (term); i++)
{ {
grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1); grub_term_gotoxy (term, GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y + i + 1);
grub_putcode (GRUB_TERM_DISP_VLINE); grub_putcode (GRUB_TERM_DISP_VLINE, term);
grub_gotoxy (GRUB_TERM_MARGIN + GRUB_TERM_BORDER_WIDTH - 1, grub_term_gotoxy (term, GRUB_TERM_MARGIN + grub_term_border_width (term)
- 1,
GRUB_TERM_TOP_BORDER_Y + i + 1); GRUB_TERM_TOP_BORDER_Y + i + 1);
grub_putcode (GRUB_TERM_DISP_VLINE); grub_putcode (GRUB_TERM_DISP_VLINE, term);
} }
grub_gotoxy (GRUB_TERM_MARGIN, grub_term_gotoxy (term, GRUB_TERM_MARGIN,
GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES + 1); GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term) + 1);
grub_putcode (GRUB_TERM_DISP_LL); grub_putcode (GRUB_TERM_DISP_LL, term);
for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++) for (i = 0; i < (unsigned) grub_term_border_width (term) - 2; i++)
grub_putcode (GRUB_TERM_DISP_HLINE); grub_putcode (GRUB_TERM_DISP_HLINE, term);
grub_putcode (GRUB_TERM_DISP_LR); grub_putcode (GRUB_TERM_DISP_LR, term);
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
grub_gotoxy (GRUB_TERM_MARGIN, grub_term_gotoxy (term, GRUB_TERM_MARGIN,
(GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES (GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term)
+ GRUB_TERM_MARGIN + 1)); + GRUB_TERM_MARGIN + 1));
} }
static void static void
print_message (int nested, int edit) print_message (int nested, int edit, struct grub_term_output *term)
{ {
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
if (edit) if (edit)
{ {
grub_putchar ('\n'); grub_putcode ('\n', term);
grub_print_message_indented (_("Minimum Emacs-like screen editing is \ grub_print_message_indented (_("Minimum Emacs-like screen editing is \
supported. TAB lists completions. Press Ctrl-x to boot, Ctrl-c for a \ supported. TAB lists completions. Press Ctrl-x to boot, Ctrl-c for a \
command-line or ESC to return menu."), STANDARD_MARGIN, STANDARD_MARGIN); command-line or ESC to return menu."), STANDARD_MARGIN, STANDARD_MARGIN,
term);
} }
else else
{ {
@ -218,12 +191,14 @@ entry is highlighted.\n");
grub_sprintf (msg_translated, msg, (grub_uint32_t) GRUB_TERM_DISP_UP, grub_sprintf (msg_translated, msg, (grub_uint32_t) GRUB_TERM_DISP_UP,
(grub_uint32_t) GRUB_TERM_DISP_DOWN); (grub_uint32_t) GRUB_TERM_DISP_DOWN);
grub_putchar ('\n'); grub_putchar ('\n');
grub_print_message_indented (msg_translated, STANDARD_MARGIN, STANDARD_MARGIN); grub_print_message_indented (msg_translated, STANDARD_MARGIN,
STANDARD_MARGIN, term);
grub_free (msg_translated); grub_free (msg_translated);
grub_print_message_indented (_("Press enter to boot the selected OS, \ grub_print_message_indented (_("Press enter to boot the selected OS, \
\'e\' to edit the commands before booting or \'c\' for a command-line.\n"), STANDARD_MARGIN, STANDARD_MARGIN); \'e\' to edit the commands before booting or \'c\' for a command-line.\n"),
STANDARD_MARGIN, STANDARD_MARGIN, term);
if (nested) if (nested)
{ {
@ -234,7 +209,8 @@ entry is highlighted.\n");
} }
static void static void
print_entry (int y, int highlight, grub_menu_entry_t entry) print_entry (int y, int highlight, grub_menu_entry_t entry,
struct grub_term_output *term)
{ {
int x; int x;
const char *title; const char *title;
@ -260,482 +236,248 @@ print_entry (int y, int highlight, grub_menu_entry_t entry)
return; return;
} }
grub_getcolor (&old_color_normal, &old_color_highlight); grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
grub_setcolor (grub_color_menu_normal, grub_color_menu_highlight); grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
grub_setcolorstate (highlight grub_term_setcolorstate (term, highlight
? GRUB_TERM_COLOR_HIGHLIGHT ? GRUB_TERM_COLOR_HIGHLIGHT
: GRUB_TERM_COLOR_NORMAL); : GRUB_TERM_COLOR_NORMAL);
grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y); grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0; for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
x < GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH - GRUB_TERM_MARGIN; x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
- GRUB_TERM_MARGIN);
i++) i++)
{ {
if (i < len if (i < len
&& x <= (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH && x <= (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
- GRUB_TERM_MARGIN - 1)) - GRUB_TERM_MARGIN - 1))
{ {
grub_ssize_t width; grub_ssize_t width;
width = grub_getcharwidth (unicode_title[i]); width = grub_term_getcharwidth (term, unicode_title[i]);
if (x + width > (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH if (x + width > (int) (GRUB_TERM_LEFT_BORDER_X
+ grub_term_border_width (term)
- GRUB_TERM_MARGIN - 1)) - GRUB_TERM_MARGIN - 1))
grub_putcode (GRUB_TERM_DISP_RIGHT); grub_putcode (GRUB_TERM_DISP_RIGHT, term);
else else
grub_putcode (unicode_title[i]); grub_putcode (unicode_title[i], term);
x += width; x += width;
} }
else else
{ {
grub_putchar (' '); grub_putcode (' ', term);
x++; x++;
} }
} }
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
grub_putchar (' '); grub_putcode (' ', term);
grub_gotoxy (GRUB_TERM_CURSOR_X, y); grub_term_gotoxy (term, grub_term_cursor_x (term), y);
grub_setcolor (old_color_normal, old_color_highlight); grub_term_setcolor (term, old_color_normal, old_color_highlight);
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
grub_free (unicode_title); grub_free (unicode_title);
} }
static void static void
print_entries (grub_menu_t menu, int first, int offset) print_entries (grub_menu_t menu, int first, int offset,
struct grub_term_output *term)
{ {
grub_menu_entry_t e; grub_menu_entry_t e;
int i; int i;
grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, grub_term_gotoxy (term,
GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term),
GRUB_TERM_FIRST_ENTRY_Y); GRUB_TERM_FIRST_ENTRY_Y);
if (first) if (first)
grub_putcode (GRUB_TERM_DISP_UP); grub_putcode (GRUB_TERM_DISP_UP, term);
else else
grub_putchar (' '); grub_putcode (' ', term);
e = grub_menu_get_entry (menu, first); e = grub_menu_get_entry (menu, first);
for (i = 0; i < GRUB_TERM_NUM_ENTRIES; i++) for (i = 0; i < grub_term_num_entries (term); i++)
{ {
print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e); print_entry (GRUB_TERM_FIRST_ENTRY_Y + i, offset == i, e, term);
if (e) if (e)
e = e->next; e = e->next;
} }
grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH, grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X
GRUB_TERM_TOP_BORDER_Y + GRUB_TERM_NUM_ENTRIES); + grub_term_border_width (term),
GRUB_TERM_TOP_BORDER_Y + grub_term_num_entries (term));
if (e) if (e)
grub_putcode (GRUB_TERM_DISP_DOWN); grub_putcode (GRUB_TERM_DISP_DOWN, term);
else else
grub_putchar (' '); grub_putcode (' ', term);
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset); grub_term_gotoxy (term, grub_term_cursor_x (term),
GRUB_TERM_FIRST_ENTRY_Y + offset);
} }
/* Initialize the screen. If NESTED is non-zero, assume that this menu /* Initialize the screen. If NESTED is non-zero, assume that this menu
is run from another menu or a command-line. If EDIT is non-zero, show is run from another menu or a command-line. If EDIT is non-zero, show
a message for the menu entry editor. */ a message for the menu entry editor. */
void void
grub_menu_init_page (int nested, int edit) grub_menu_init_page (int nested, int edit,
struct grub_term_output *term)
{ {
grub_uint8_t old_color_normal, old_color_highlight; grub_uint8_t old_color_normal, old_color_highlight;
grub_getcolor (&old_color_normal, &old_color_highlight); grub_term_getcolor (term, &old_color_normal, &old_color_highlight);
/* By default, use the same colors for the menu. */ /* By default, use the same colors for the menu. */
grub_color_menu_normal = old_color_normal; grub_color_menu_normal = old_color_normal;
grub_color_menu_highlight = old_color_highlight; grub_color_menu_highlight = old_color_highlight;
/* Then give user a chance to replace them. */ /* Then give user a chance to replace them. */
grub_parse_color_name_pair (&grub_color_menu_normal, grub_env_get ("menu_color_normal")); grub_parse_color_name_pair (&grub_color_menu_normal,
grub_parse_color_name_pair (&grub_color_menu_highlight, grub_env_get ("menu_color_highlight")); grub_env_get ("menu_color_normal"));
grub_parse_color_name_pair (&grub_color_menu_highlight,
grub_env_get ("menu_color_highlight"));
grub_normal_init_page (); grub_normal_init_page (term);
grub_setcolor (grub_color_menu_normal, grub_color_menu_highlight); grub_term_setcolor (term, grub_color_menu_normal, grub_color_menu_highlight);
draw_border (); draw_border (term);
grub_setcolor (old_color_normal, old_color_highlight); grub_term_setcolor (term, old_color_normal, old_color_highlight);
print_message (nested, edit); print_message (nested, edit, term);
}
/* Get the entry number from the variable NAME. */
static int
get_entry_number (const char *name)
{
char *val;
int entry;
val = grub_env_get (name);
if (! val)
return -1;
grub_error_push ();
entry = (int) grub_strtoul (val, 0, 0);
if (grub_errno != GRUB_ERR_NONE)
{
grub_errno = GRUB_ERR_NONE;
entry = -1;
}
grub_error_pop ();
return entry;
} }
static void static void
print_timeout (int timeout, int offset) menu_text_print_timeout (int timeout, void *dataptr)
{ {
const char *msg = const char *msg =
_("The highlighted entry will be booted automatically in %ds."); _("The highlighted entry will be booted automatically in %ds.");
struct menu_viewer_data *data = dataptr;
char *msg_translated;
int posx;
grub_gotoxy (0, GRUB_TERM_HEIGHT - 3); grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
char *msg_translated = msg_translated = grub_malloc (sizeof (char) * grub_strlen (msg) + 5);
grub_malloc (sizeof (char) * grub_strlen (msg) + 5); if (!msg_translated)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
return;
}
grub_sprintf (msg_translated, msg, timeout); grub_sprintf (msg_translated, msg, timeout);
grub_print_message_indented (msg_translated, 3, 0); grub_print_message_indented (msg_translated, 3, 0, data->term);
int posx; posx = grub_term_getxy (data->term) >> 8;
posx = grub_getxy() >> 8; print_spaces (grub_term_width (data->term) - posx - 1, data->term);
print_spaces (GRUB_TERM_WIDTH - posx - 1);
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset); grub_term_gotoxy (data->term,
grub_refresh (); grub_term_cursor_x (data->term),
GRUB_TERM_FIRST_ENTRY_Y + data->offset);
grub_term_refresh (data->term);
} }
/* Show the menu and handle menu entry selection. Returns the menu entry static void
index that should be executed or -1 if no entry should be executed (e.g., menu_text_set_chosen_entry (int entry, void *dataptr)
Esc pressed to exit a sub-menu or switching menu viewers).
If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu
entry to be executed is a result of an automatic default selection because
of the timeout. */
static int
run_menu (grub_menu_t menu, int nested, int *auto_boot)
{ {
int first, offset; struct menu_viewer_data *data = dataptr;
grub_uint64_t saved_time; int oldoffset = data->offset;
int default_entry; int complete_redraw = 0;
int timeout; data->offset = entry - data->first;
if (data->offset > grub_term_num_entries (data->term) - 1)
first = 0;
default_entry = get_entry_number ("default");
/* If DEFAULT_ENTRY is not within the menu entries, fall back to
the first entry. */
if (default_entry < 0 || default_entry >= menu->size)
default_entry = 0;
/* If timeout is 0, drawing is pointless (and ugly). */
if (grub_menu_get_timeout () == 0)
{ {
*auto_boot = 1; data->first = data->offset - (grub_term_num_entries (data->term) - 1);
return default_entry; data->offset = grub_term_num_entries (data->term) - 1;
complete_redraw = 1;
} }
if (data->offset < 0)
offset = default_entry;
if (offset > GRUB_TERM_NUM_ENTRIES - 1)
{ {
first = offset - (GRUB_TERM_NUM_ENTRIES - 1); data->offset = 0;
offset = GRUB_TERM_NUM_ENTRIES - 1; data->first = entry;
} complete_redraw = 1;
/* Initialize the time. */
saved_time = grub_get_time_ms ();
refresh:
grub_setcursor (0);
grub_menu_init_page (nested, 0);
print_entries (menu, first, offset);
grub_refresh ();
timeout = grub_menu_get_timeout ();
if (timeout > 0)
print_timeout (timeout, offset);
while (1)
{
int c;
timeout = grub_menu_get_timeout ();
if (timeout > 0)
{
grub_uint64_t current_time;
current_time = grub_get_time_ms ();
if (current_time - saved_time >= 1000)
{
timeout--;
grub_menu_set_timeout (timeout);
saved_time = current_time;
print_timeout (timeout, offset);
}
}
if (timeout == 0)
{
grub_env_unset ("timeout");
*auto_boot = 1;
return default_entry;
}
if (grub_checkkey () >= 0 || timeout < 0)
{
c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
if (timeout >= 0)
{
grub_gotoxy (0, GRUB_TERM_HEIGHT - 3);
print_spaces (GRUB_TERM_WIDTH - 1);
grub_env_unset ("timeout");
grub_env_unset ("fallback");
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
}
switch (c)
{
case GRUB_TERM_HOME:
first = 0;
offset = 0;
print_entries (menu, first, offset);
break;
case GRUB_TERM_END:
offset = menu->size - 1;
if (offset > GRUB_TERM_NUM_ENTRIES - 1)
{
first = offset - (GRUB_TERM_NUM_ENTRIES - 1);
offset = GRUB_TERM_NUM_ENTRIES - 1;
}
print_entries (menu, first, offset);
break;
case GRUB_TERM_UP:
case '^':
if (offset > 0)
{
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
grub_menu_get_entry (menu, first + offset));
offset--;
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
grub_menu_get_entry (menu, first + offset));
}
else if (first > 0)
{
first--;
print_entries (menu, first, offset);
}
break;
case GRUB_TERM_DOWN:
case 'v':
if (menu->size > first + offset + 1)
{
if (offset < GRUB_TERM_NUM_ENTRIES - 1)
{
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 0,
grub_menu_get_entry (menu, first + offset));
offset++;
print_entry (GRUB_TERM_FIRST_ENTRY_Y + offset, 1,
grub_menu_get_entry (menu, first + offset));
} }
if (complete_redraw)
print_entries (data->menu, data->first, data->offset, data->term);
else else
{ {
first++; print_entry (GRUB_TERM_FIRST_ENTRY_Y + oldoffset, 0,
print_entries (menu, first, offset); grub_menu_get_entry (data->menu, data->first + oldoffset),
data->term);
print_entry (GRUB_TERM_FIRST_ENTRY_Y + data->offset, 1,
grub_menu_get_entry (data->menu, data->first + data->offset),
data->term);
} }
} grub_term_refresh (data->term);
break;
case GRUB_TERM_PPAGE:
if (first == 0)
{
offset = 0;
}
else
{
first -= GRUB_TERM_NUM_ENTRIES;
if (first < 0)
{
offset += first;
first = 0;
}
}
print_entries (menu, first, offset);
break;
case GRUB_TERM_NPAGE:
if (offset == 0)
{
offset += GRUB_TERM_NUM_ENTRIES - 1;
if (first + offset >= menu->size)
{
offset = menu->size - first - 1;
}
}
else
{
first += GRUB_TERM_NUM_ENTRIES;
if (first + offset >= menu->size)
{
first -= GRUB_TERM_NUM_ENTRIES;
offset += GRUB_TERM_NUM_ENTRIES;
if (offset > menu->size - 1 ||
offset > GRUB_TERM_NUM_ENTRIES - 1)
{
offset = menu->size - first - 1;
}
if (offset > GRUB_TERM_NUM_ENTRIES)
{
first += offset - GRUB_TERM_NUM_ENTRIES + 1;
offset = GRUB_TERM_NUM_ENTRIES - 1;
}
}
}
print_entries (menu, first, offset);
break;
case '\n':
case '\r':
case 6:
grub_setcursor (1);
*auto_boot = 0;
return first + offset;
case '\e':
if (nested)
{
grub_setcursor (1);
return -1;
}
break;
case 'c':
grub_cmdline_run (1);
goto refresh;
case 'e':
{
grub_menu_entry_t e = grub_menu_get_entry (menu, first + offset);
if (e)
grub_menu_entry_run (e);
}
goto refresh;
default:
break;
}
grub_refresh ();
}
}
/* Never reach here. */
return -1;
} }
/* Callback invoked immediately before a menu entry is executed. */
static void static void
notify_booting (grub_menu_entry_t entry, menu_text_fini (void *dataptr)
void *userdata __attribute__((unused)))
{ {
grub_printf (" "); struct menu_viewer_data *data = dataptr;
grub_printf_ (N_("Booting \'%s\'"), entry->title);
grub_printf ("\n\n"); grub_term_setcursor (data->term, 1);
} }
/* Callback invoked when a default menu entry executed because of a timeout
has failed and an attempt will be made to execute the next fallback
entry, ENTRY. */
static void static void
notify_fallback (grub_menu_entry_t entry, menu_text_clear_timeout (void *dataptr)
void *userdata __attribute__((unused)))
{ {
grub_printf ("\n "); struct menu_viewer_data *data = dataptr;
grub_printf_ (N_("Falling back to \'%s\'"), entry->title);
grub_printf ("\n\n"); grub_term_gotoxy (data->term, 0, grub_term_height (data->term) - 3);
grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS); print_spaces (grub_term_width (data->term) - 1, data->term);
grub_term_gotoxy (data->term, grub_term_cursor_x (data->term),
GRUB_TERM_FIRST_ENTRY_Y + data->offset);
grub_term_refresh (data->term);
} }
/* Callback invoked when a menu entry has failed and there is no remaining void
fallback entry to attempt. */ grub_menu_text_register_instances (int entry, grub_menu_t menu, int nested)
static void
notify_execution_failure (void *userdata __attribute__((unused)))
{ {
if (grub_errno != GRUB_ERR_NONE) struct menu_viewer_data *data;
struct grub_menu_viewer *instance;
struct grub_term_output *term;
for (term = grub_term_outputs; term; term = term->next)
{
if (!grub_term_is_active (term))
continue;
instance = grub_zalloc (sizeof (*instance));
if (!instance)
{ {
grub_print_error (); grub_print_error ();
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
continue;
} }
grub_printf ("\n "); data = grub_zalloc (sizeof (*data));
grub_printf_ (N_("Failed to boot default entries.\n")); if (!data)
grub_wait_after_message ();
}
/* Callbacks used by the text menu to provide user feedback when menu entries
are executed. */
static struct grub_menu_execute_callback execution_callback =
{
.notify_booting = notify_booting,
.notify_fallback = notify_fallback,
.notify_failure = notify_execution_failure
};
static grub_err_t
show_text_menu (grub_menu_t menu, int nested)
{
while (1)
{
int boot_entry;
grub_menu_entry_t e;
int auto_boot;
boot_entry = run_menu (menu, nested, &auto_boot);
if (boot_entry < 0)
break;
e = grub_menu_get_entry (menu, boot_entry);
if (! e)
continue; /* Menu is empty. */
grub_cls ();
grub_setcursor (1);
if (auto_boot)
{
grub_menu_execute_with_fallback (menu, e, &execution_callback, 0);
}
else
{
grub_errno = GRUB_ERR_NONE;
grub_menu_execute_entry (e);
if (grub_errno != GRUB_ERR_NONE)
{ {
grub_free (instance);
grub_print_error (); grub_print_error ();
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
grub_wait_after_message (); continue;
}
} }
data->term = term;
instance->data = data;
instance->set_chosen_entry = menu_text_set_chosen_entry;
instance->print_timeout = menu_text_print_timeout;
instance->clear_timeout = menu_text_clear_timeout;
instance->fini = menu_text_fini;
data->menu = menu;
data->offset = entry;
data->first = 0;
if (data->offset > grub_term_num_entries (data->term) - 1)
{
data->first = data->offset - (grub_term_num_entries (data->term) - 1);
data->offset = grub_term_num_entries (data->term) - 1;
} }
return GRUB_ERR_NONE; grub_term_setcursor (data->term, 0);
grub_menu_init_page (nested, 0, data->term);
print_entries (menu, data->first, data->offset, data->term);
grub_term_refresh (data->term);
}
} }
struct grub_menu_viewer grub_normal_text_menu_viewer =
{
.name = "text",
.show_menu = show_text_menu
};

View file

@ -23,59 +23,4 @@
#include <grub/menu.h> #include <grub/menu.h>
#include <grub/auth.h> #include <grub/auth.h>
/* The list of menu viewers. */
static grub_menu_viewer_t menu_viewer_list;
void
grub_menu_viewer_register (grub_menu_viewer_t viewer)
{
viewer->next = menu_viewer_list;
menu_viewer_list = viewer;
}
static grub_menu_viewer_t get_current_menu_viewer (void)
{
const char *selected_name = grub_env_get ("menuviewer");
/* If none selected, pick the last registered one. */
if (selected_name == 0)
return menu_viewer_list;
grub_menu_viewer_t cur;
for (cur = menu_viewer_list; cur; cur = cur->next)
{
if (grub_strcmp (cur->name, selected_name) == 0)
return cur;
}
/* Fall back to the first entry (or null). */
return menu_viewer_list;
}
grub_err_t
grub_menu_viewer_show_menu (grub_menu_t menu, int nested)
{
grub_menu_viewer_t cur = get_current_menu_viewer ();
grub_err_t err1, err2;
if (!cur)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available.");
while (1)
{
err1 = cur->show_menu (menu, nested);
grub_print_error ();
err2 = grub_auth_check_authentication (NULL);
if (err2)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
continue;
}
break;
}
return err1;
}

View file

@ -16,8 +16,12 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <grub/term.h>
#include <grub/misc.h>
#include <grub/mm.h>
/* The amount of lines counted by the pager. */ /* The amount of lines counted by the pager. */
static int grub_more_lines; static unsigned grub_more_lines;
/* If the more pager is active. */ /* If the more pager is active. */
static int grub_more; static int grub_more;
@ -25,19 +29,21 @@ static int grub_more;
static void static void
process_newline (void) process_newline (void)
{ {
if (code == '\n') struct grub_term_output *cur;
{ unsigned height = -1;
grub_putcode ('\r');
for (cur = grub_term_outputs; cur; cur = cur->next)
if (grub_term_is_active(cur) && grub_term_height (cur) < height)
height = grub_term_height (cur);
grub_more_lines++; grub_more_lines++;
if (grub_more && grub_more_lines == height - 1) if (grub_more && grub_more_lines == height - 1)
{ {
char key; char key;
int pos = term->getxy (); grub_uint16_t *pos;
pos = grub_term_save_pos ();
/* Show --MORE-- on the lower left side of the screen. */
term->gotoxy (1, height - 1);
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
grub_printf ("--MORE--"); grub_printf ("--MORE--");
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
@ -45,9 +51,9 @@ process_newline (void)
key = grub_getkey (); key = grub_getkey ();
/* Remove the message. */ /* Remove the message. */
term->gotoxy (1, height - 1); grub_term_restore_pos (pos);
grub_printf (" "); grub_printf (" ");
term->gotoxy (pos >> 8, pos & 0xFF); grub_term_restore_pos (pos);
/* Scroll one lines or an entire page, depending on the key. */ /* Scroll one lines or an entire page, depending on the key. */
if (key == '\r' || key =='\n') if (key == '\r' || key =='\n')
@ -55,7 +61,6 @@ process_newline (void)
else else
grub_more_lines = 0; grub_more_lines = 0;
} }
}
} }
void void
@ -67,6 +72,7 @@ grub_set_more (int onoff)
grub_more--; grub_more--;
grub_more_lines = 0; grub_more_lines = 0;
grub_newline_hook = process_newline;
} }
void void
@ -74,20 +80,13 @@ grub_puts_terminal (const char *str, struct grub_term_output *term)
{ {
grub_uint32_t code; grub_uint32_t code;
grub_ssize_t ret; grub_ssize_t ret;
const char *ptr = str; const grub_uint8_t *ptr = (const grub_uint8_t *) str;
unsigned i; const grub_uint8_t *end;
end = (const grub_uint8_t *) (str + grub_strlen (str));
while (*ptr) while (*ptr)
{ {
ret = grub_utf8_to_ucs4 (&code, 1, ptr, ret = grub_utf8_to_ucs4 (&code, 1, ptr, end - ptr, &ptr);
grub_strlen (ptr), &ptr);
if (ret < 0)
{
grub_putcode ('?', term);
ptr++;
continue;
}
else
grub_putcode (code, term); grub_putcode (code, term);
} }
} }
@ -100,16 +99,17 @@ grub_term_save_pos (void)
grub_uint16_t *ret, *ptr; grub_uint16_t *ret, *ptr;
for (cur = grub_term_outputs; cur; cur = cur->next) for (cur = grub_term_outputs; cur; cur = cur->next)
if (cur->flags & GRUB_TERM_ACTIVE) if (grub_term_is_active (cur))
cnt++; cnt++;
ret = grub_malloc (cnt * sizeof (ret[0])); ret = grub_malloc (cnt * sizeof (ret[0]));
if (!ret) if (!ret)
return NULL; return NULL;
ptr = ret;
for (cur = grub_term_outputs; cur; cur = cur->next) for (cur = grub_term_outputs; cur; cur = cur->next)
if (cur->flags & GRUB_TERM_ACTIVE) if (grub_term_is_active (cur))
*ptr++ = cur->getxy (); *ptr++ = grub_term_getxy (cur);
return ret; return ret;
} }
@ -118,11 +118,15 @@ void
grub_term_restore_pos (grub_uint16_t *pos) grub_term_restore_pos (grub_uint16_t *pos)
{ {
struct grub_term_output *cur; struct grub_term_output *cur;
grub_uint16_t *ptr = pos;
if (!pos) if (!pos)
return; return;
for (cur = grub_term_outputs; cur; cur = cur->next) for (cur = grub_term_outputs; cur; cur = cur->next)
if (cur->flags & GRUB_TERM_ACTIVE) if (grub_term_is_active (cur))
cur->gotoxy ((*ptr & 0xff00) >> 8, *ptr & 0xff); {
grub_term_gotoxy (cur, (*ptr & 0xff00) >> 8, *ptr & 0xff);
ptr++;
}
} }

View file

@ -352,7 +352,7 @@ static struct grub_term_output grub_console_term_output =
.setcolor = grub_console_setcolor, .setcolor = grub_console_setcolor,
.getcolor = grub_console_getcolor, .getcolor = grub_console_getcolor,
.setcursor = grub_console_setcursor, .setcursor = grub_console_setcursor,
.flags = 0, .flags = GRUB_TERM_ACTIVE,
}; };
void void

View file

@ -66,7 +66,7 @@ static struct grub_term_output grub_console_term_output =
.setcolor = grub_console_setcolor, .setcolor = grub_console_setcolor,
.getcolor = grub_console_getcolor, .getcolor = grub_console_getcolor,
.setcursor = grub_console_setcursor, .setcursor = grub_console_setcursor,
.flags = 0, .flags = GRUB_TERM_ACTIVE,
}; };
void void

View file

@ -164,10 +164,17 @@ static struct grub_term_output grub_vga_text_term =
.setcolor = grub_console_setcolor, .setcolor = grub_console_setcolor,
.getcolor = grub_console_getcolor, .getcolor = grub_console_getcolor,
.setcursor = grub_vga_text_setcursor, .setcursor = grub_vga_text_setcursor,
#if defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
.flags = GRUB_TERM_ACTIVE,
#endif
}; };
GRUB_MOD_INIT(vga_text) GRUB_MOD_INIT(vga_text)
{ {
#if defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
grub_vga_text_init_fini ();
#endif
grub_term_register_output ("vga_text", &grub_vga_text_term); grub_term_register_output ("vga_text", &grub_vga_text_term);
} }

View file

@ -415,7 +415,7 @@ static struct grub_term_output grub_ofconsole_term_output =
.getcolor = grub_ofconsole_getcolor, .getcolor = grub_ofconsole_getcolor,
.setcursor = grub_ofconsole_setcursor, .setcursor = grub_ofconsole_setcursor,
.refresh = grub_ofconsole_refresh, .refresh = grub_ofconsole_refresh,
.flags = 0, .flags = GRUB_TERM_ACTIVE,
}; };
void void

View file

@ -368,7 +368,7 @@ static struct grub_term_output grub_ncurses_term_output =
.getcolor = grub_ncurses_getcolor, .getcolor = grub_ncurses_getcolor,
.setcursor = grub_ncurses_setcursor, .setcursor = grub_ncurses_setcursor,
.refresh = grub_ncurses_refresh, .refresh = grub_ncurses_refresh,
.flags = 0, .flags = GRUB_TERM_ACTIVE
}; };
void void