2009-01-31 Colin D Bennett <colin@gibibit.com>

* normal/main.c: Add include to grub/menu_viewer.h. 
	(free_menu_entry_classes): Added.
	(grub_normal_menu_addentry): Added class property handling.
	(grub_normal_execute): Changed to use new menu viewer for menu viewing.
	(GRUB_MOD_INIT(normal)): Added register for text based menu viewer.

	* normal/menu_viewer.c: New file.

	* normal/menu.c (run_menu_entry): Renamed to ...
	(grub_menu_execute_entry): ... this and	made it as global.
	(grub_menu_run): Renamed to ...
	(show_text_menu): ... this and made it local.
	(show_text_menu): Adapt to new function names.
	(grub_normal_terminal_menu_viewer): New global variable.

	* include/grub/menu.h: New file.

	* include/grub/menu_viewer.h: New file.

	* include/grub/normal.h: Added include to grub/menu.h.
	(grub_menu_entry): Moved to include/grub/menu.h.
	(grub_menu_entry_t): Likewise.
	(grub_menu): Likewise.
	(grub_menu_t): Likewise.
	(grub_normal_terminal_menu_viewer): Added.
	(grub_menu_execute_entry): Likewise.
	(grub_menu_run): Removed.

	* DISTLIST: Added include/grub/menu.h.
	Added include/grub/menu_viewer.h.
	Added normal/menu_viewer.c.

2009-01-31  Vesa Jääskeläinen  <chaac@nic.fi>

	* normal/execute.c (grub_script_execute_menuentry): Changed to use
	arglist for menutitle arguments.

	* normal/main.c (grub_normal_menu_addentry): Likewise.

	* normal/parser.y (menuentry): Likewise.

	* normal/script.c (grub_script_create_cmdmenu): Likewise.

	* include/grub/script.h (grub_script_cmd_menuentry): Likewise.
	(grub_script_create_cmdmenu): Likewise.

	* include/grub/normal.h (grub_normal_menu_addentry): Likewise.

	* conf/i386-pc.rmk (normal_mod_SOURCES): Adapt Colin D Bennett's
	changes.

	* conf/x86_64-efi.rmk (normal_mod_SOURCES): Likewise.

	* conf/i386-coreboot.rmk (normal_mod_SOURCES): Likewise.

	* conf/i386-efi.rmk (normal_mod_SOURCES): Likewise.

	* conf/i386-ieee1275.rmk (normal_mod_SOURCES): Likewise.

	* conf/powerpc-ieee1275.rmk (normal_mod_SOURCES): Likewise.

	* conf/sparc64-ieee1275.rmk (normal_mod_SOURCES): Likewise.
This commit is contained in:
chaac 2009-01-31 09:15:43 +00:00
parent 56192c2346
commit 6fa42fa65a
26 changed files with 934 additions and 301 deletions

View file

@ -1,7 +1,7 @@
/* execute.c -- Execute a GRUB script. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2005,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2005,2007,2008,2009 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
@ -148,11 +148,11 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
parser = (struct grub_arg_option *) grubcmd->options;
while (parser && (parser++)->doc)
maxargs++;
/* Set up the option state. */
state = grub_malloc (sizeof (struct grub_arg_list) * maxargs);
grub_memset (state, 0, sizeof (struct grub_arg_list) * maxargs);
/* Start the command. */
if (! (grubcmd->flags & GRUB_COMMAND_FLAG_NO_ARG_PARSE))
{
@ -161,7 +161,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
}
else
ret = (grubcmd->func) (state, argcount, args);
grub_free (state);
}
else
@ -178,7 +178,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
return ret;
}
/* Execute a block of one or more commands. */
/* Execute a block of one or more commands. */
grub_err_t
grub_script_execute_cmdblock (struct grub_script_cmd *cmd)
{
@ -216,32 +216,53 @@ grub_err_t
grub_script_execute_menuentry (struct grub_script_cmd *cmd)
{
struct grub_script_cmd_menuentry *cmd_menuentry;
char *title;
struct grub_script_arglist *arglist;
struct grub_script *script;
char **args = 0;
int argcount = 0;
int i = 0;
cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd;
/* The title can contain variables, parse them and generate a string
from it. */
title = grub_script_execute_argument_to_string (cmd_menuentry->title);
if (! title)
return grub_errno;
if (cmd_menuentry->arglist)
{
argcount = cmd_menuentry->arglist->argcount;
/* Create argv from the arguments. */
args = grub_malloc (sizeof (char *) * argcount);
if (! args)
{
return grub_errno;
}
for (arglist = cmd_menuentry->arglist; arglist; arglist = arglist->next)
{
char *str;
str = grub_script_execute_argument_to_string (arglist->arg);
args[i++] = str;
}
}
/* Parse the menu entry *again*. */
script = grub_script_parse ((char *) cmd_menuentry->sourcecode, 0);
if (! script)
/* Add new menu entry. */
if (script)
{
grub_free (title);
return grub_errno;
grub_normal_menu_addentry (argcount, (const char **)args,
script, cmd_menuentry->sourcecode);
}
/* XXX: When this fails, the memory should be freed? */
return grub_normal_menu_addentry (title, script,
cmd_menuentry->sourcecode);
/* Free arguments. */
for (i = 0; i < argcount; i++)
grub_free (args[i]);
grub_free (args);
return grub_errno;
}
/* Execute any GRUB pre-parsed command or script. */
grub_err_t

View file

@ -1,7 +1,7 @@
/* main.c - the normal mode main routine */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2000,2001,2002,2003,2005,2006,2007,2008,2009 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
@ -28,6 +28,7 @@
#include <grub/env.h>
#include <grub/parser.h>
#include <grub/script.h>
#include <grub/menu_viewer.h>
grub_jmp_buf grub_exit_env;
@ -147,14 +148,41 @@ free_menu (grub_menu_t menu)
grub_env_unset_data_slot ("menu");
}
static void
free_menu_entry_classes (struct grub_menu_entry_class *head)
{
/* Free all the classes. */
while (head)
{
struct grub_menu_entry_class *next;
grub_free (head->name);
next = head->next;
grub_free (head);
head = next;
}
}
grub_err_t
grub_normal_menu_addentry (const char *title, struct grub_script *script,
grub_normal_menu_addentry (int argc, const char **args, struct grub_script *script,
const char *sourcecode)
{
const char *menutitle;
const char *menutitle = 0;
const char *menusourcecode;
grub_menu_t menu;
grub_menu_entry_t *last;
int failed = 0;
int i;
struct grub_menu_entry_class *classes_head; /* Dummy head node for list. */
struct grub_menu_entry_class *classes_tail;
/* Allocate dummy head node for class list. */
classes_head = grub_malloc (sizeof (struct grub_menu_entry_class));
if (! classes_head)
return grub_errno;
classes_head->name = 0;
classes_head->next = 0;
classes_tail = classes_head;
menu = grub_env_get_data_slot("menu");
if (! menu)
@ -166,10 +194,81 @@ grub_normal_menu_addentry (const char *title, struct grub_script *script,
if (! menusourcecode)
return grub_errno;
menutitle = grub_strdup (title);
if (! menutitle)
/* Parse menu arguments. */
for (i = 0; i < argc; i++)
{
/* Capture arguments. */
if (grub_strncmp ("--", args[i], 2) == 0)
{
const char *arg = &args[i][2];
/* Handle menu class. */
if (grub_strcmp(arg, "class") == 0)
{
char *class_name;
struct grub_menu_entry_class *new_class;
i++;
class_name = grub_strdup (args[i]);
if (! class_name)
{
failed = 1;
break;
}
/* Create a new class and add it at the tail of the list. */
new_class = grub_malloc (sizeof (struct grub_menu_entry_class));
if (! new_class)
{
grub_free (class_name);
failed = 1;
break;
}
/* Fill in the new class node. */
new_class->name = class_name;
new_class->next = 0;
/* Link the tail to it, and make it the new tail. */
classes_tail->next = new_class;
classes_tail = new_class;
continue;
}
else
{
/* Handle invalid argument. */
failed = 1;
grub_error (GRUB_ERR_MENU, "invalid argument for menuentry: %s", args[i]);
break;
}
}
/* Capture title. */
if (! menutitle)
{
menutitle = grub_strdup (args[i]);
}
else
{
failed = 1;
grub_error (GRUB_ERR_MENU, "too many titles for menuentry: %s", args[i]);
break;
}
}
/* Validate arguments. */
if ((! failed) && (! menutitle))
{
grub_error (GRUB_ERR_MENU, "menuentry is missing title");
failed = 1;
}
/* If argument parsing failed, free any allocated resources. */
if (failed)
{
free_menu_entry_classes (classes_head);
grub_free ((void *) menutitle);
grub_free ((void *) menusourcecode);
/* Here we assume that grub_error has been used to specify failure details. */
return grub_errno;
}
@ -180,6 +279,7 @@ grub_normal_menu_addentry (const char *title, struct grub_script *script,
*last = grub_malloc (sizeof (**last));
if (! *last)
{
free_menu_entry_classes (classes_head);
grub_free ((void *) menutitle);
grub_free ((void *) menusourcecode);
return grub_errno;
@ -187,6 +287,7 @@ grub_normal_menu_addentry (const char *title, struct grub_script *script,
(*last)->commands = script;
(*last)->title = menutitle;
(*last)->classes = classes_head;
(*last)->next = 0;
(*last)->sourcecode = menusourcecode;
@ -476,7 +577,7 @@ grub_normal_execute (const char *config, int nested)
if (menu && menu->size)
{
grub_menu_run (menu, nested);
grub_menu_viewer_show_menu (menu, nested);
if (nested)
free_menu (menu);
}
@ -519,6 +620,8 @@ GRUB_MOD_INIT(normal)
if (mod)
grub_dl_ref (mod);
grub_menu_viewer_register (&grub_normal_terminal_menu_viewer);
grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
/* Register a command "normal" for the rescue mode. */

View file

@ -24,6 +24,7 @@
#include <grub/time.h>
#include <grub/env.h>
#include <grub/script.h>
#include <grub/menu_viewer.h>
static grub_uint8_t grub_color_menu_normal;
static grub_uint8_t grub_color_menu_highlight;
@ -41,9 +42,9 @@ static void
draw_border (void)
{
unsigned i;
grub_setcolorstate (GRUB_TERM_COLOR_NORMAL);
grub_gotoxy (GRUB_TERM_MARGIN, GRUB_TERM_TOP_BORDER_Y);
grub_putcode (GRUB_TERM_DISP_UL);
for (i = 0; i < (unsigned) GRUB_TERM_BORDER_WIDTH - 2; i++)
@ -97,7 +98,7 @@ print_message (int nested, int edit)
grub_printf ("\n\
ESC to return previous menu.");
}
}
static grub_menu_entry_t
@ -128,7 +129,7 @@ print_entry (int y, int highlight, grub_menu_entry_t entry)
if (! unicode_title)
/* XXX How to show this error? */
return;
len = grub_utf8_to_ucs4 (unicode_title, title_len,
(grub_uint8_t *) title, -1, 0);
if (len < 0)
@ -157,7 +158,7 @@ print_entry (int y, int highlight, grub_menu_entry_t entry)
grub_ssize_t width;
width = grub_getcharwidth (unicode_title[i]);
if (x + width > (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH
- GRUB_TERM_MARGIN - 1))
grub_putcode (GRUB_TERM_DISP_RIGHT);
@ -187,7 +188,7 @@ print_entries (grub_menu_t menu, int first, int offset)
{
grub_menu_entry_t e;
int i;
grub_gotoxy (GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_BORDER_WIDTH,
GRUB_TERM_FIRST_ENTRY_Y);
@ -248,13 +249,13 @@ get_timeout (void)
{
char *val;
int timeout;
val = grub_env_get ("timeout");
if (! val)
return -1;
grub_error_push ();
timeout = (int) grub_strtoul (val, 0, 0);
/* If the value is invalid, unset the variable. */
@ -266,7 +267,7 @@ get_timeout (void)
}
grub_error_pop ();
return timeout;
}
@ -278,7 +279,7 @@ set_timeout (int timeout)
if (timeout > 0)
{
char buf[16];
grub_sprintf (buf, "%d", timeout);
grub_env_set ("timeout", buf);
}
@ -290,13 +291,13 @@ 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)
@ -306,7 +307,7 @@ get_entry_number (const char *name)
}
grub_error_pop ();
return entry;
}
@ -317,7 +318,7 @@ print_timeout (int timeout, int offset, int second_stage)
They are required to clear the line. */
char *msg = " The highlighted entry will be booted automatically in %ds. ";
char *msg_end = grub_strchr (msg, '%');
grub_gotoxy (second_stage ? (msg_end - msg) : 0, GRUB_TERM_HEIGHT - 3);
grub_printf (second_stage ? msg_end : msg, timeout);
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
@ -331,9 +332,9 @@ run_menu (grub_menu_t menu, int nested)
grub_uint64_t saved_time;
int default_entry;
int timeout;
first = 0;
default_entry = get_entry_number ("default");
/* If DEFAULT_ENTRY is not within the menu entries, fall back to
@ -370,7 +371,7 @@ run_menu (grub_menu_t menu, int nested)
{
int c;
timeout = get_timeout ();
if (timeout > 0)
{
grub_uint64_t current_time;
@ -390,11 +391,11 @@ run_menu (grub_menu_t menu, int nested)
grub_env_unset ("timeout");
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);
@ -404,7 +405,7 @@ run_menu (grub_menu_t menu, int nested)
grub_env_unset ("fallback");
grub_gotoxy (GRUB_TERM_CURSOR_X, GRUB_TERM_FIRST_ENTRY_Y + offset);
}
switch (c)
{
case GRUB_TERM_HOME:
@ -439,7 +440,7 @@ run_menu (grub_menu_t menu, int nested)
print_entries (menu, first, offset);
}
break;
case GRUB_TERM_DOWN:
case 'v':
if (menu->size > first + offset + 1)
@ -459,7 +460,7 @@ run_menu (grub_menu_t menu, int nested)
}
}
break;
case GRUB_TERM_PPAGE:
if (first == 0)
{
@ -490,12 +491,12 @@ run_menu (grub_menu_t menu, int nested)
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)
{
@ -510,13 +511,13 @@ run_menu (grub_menu_t menu, int nested)
}
print_entries (menu, first, offset);
break;
case '\n':
case '\r':
case 6:
grub_setcursor (1);
return first + offset;
case '\e':
if (nested)
{
@ -524,7 +525,7 @@ run_menu (grub_menu_t menu, int nested)
return -1;
}
break;
case 'c':
grub_cmdline_run (1);
goto refresh;
@ -536,11 +537,11 @@ run_menu (grub_menu_t menu, int nested)
grub_menu_entry_run (e);
}
goto refresh;
default:
break;
}
grub_refresh ();
}
}
@ -550,25 +551,25 @@ run_menu (grub_menu_t menu, int nested)
}
/* Run a menu entry. */
static void
run_menu_entry (grub_menu_entry_t entry)
void
grub_menu_execute_entry(grub_menu_entry_t entry)
{
grub_script_execute (entry->commands);
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
/* Implicit execution of boot, only if something is loaded. */
grub_command_execute ("boot", 0);
}
void
grub_menu_run (grub_menu_t menu, int nested)
static grub_err_t
show_text_menu (grub_menu_t menu, int nested)
{
while (1)
{
int boot_entry;
grub_menu_entry_t e;
int fallback_entry;
boot_entry = run_menu (menu, nested);
if (boot_entry < 0)
break;
@ -576,13 +577,13 @@ grub_menu_run (grub_menu_t menu, int nested)
e = get_entry (menu, boot_entry);
if (! e)
continue; /* Menu is empty. */
grub_cls ();
grub_setcursor (1);
grub_printf (" Booting \'%s\'\n\n", e->title);
run_menu_entry (e);
grub_menu_execute_entry (e);
/* Deal with a fallback entry. */
/* FIXME: Multiple fallback entries like GRUB Legacy. */
@ -591,11 +592,11 @@ grub_menu_run (grub_menu_t menu, int nested)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
e = get_entry (menu, fallback_entry);
grub_env_unset ("fallback");
grub_printf ("\n Falling back to \'%s\'\n\n", e->title);
run_menu_entry (e);
grub_menu_execute_entry (e);
}
if (grub_errno != GRUB_ERR_NONE)
@ -606,4 +607,12 @@ grub_menu_run (grub_menu_t menu, int nested)
grub_wait_after_message ();
}
}
return GRUB_ERR_NONE;
}
struct grub_menu_viewer grub_normal_terminal_menu_viewer =
{
.name = "terminal",
.show_menu = show_text_menu
};

63
normal/menu_viewer.c Normal file
View file

@ -0,0 +1,63 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 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/>.
*/
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/env.h>
#include <grub/menu_viewer.h>
#include <grub/menu.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 ();
if (!cur)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "No menu viewer available.");
return cur->show_menu (menu, nested);
}

View file

@ -1,7 +1,7 @@
/* parser.y - The scripting parser. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2005,2006,2007,2008 Free Software Foundation, Inc.
* Copyright (C) 2005,2006,2007,2008,2009 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
@ -204,7 +204,7 @@ commandblock: '{'
;
/* A menu entry. Carefully save the memory that is allocated. */
menuentry: "menuentry" argument
menuentry: "menuentry" arguments
{
grub_script_lexer_ref (state->lexerstate);
} newlines '{'

View file

@ -1,7 +1,7 @@
/* script.c -- Functions to create an in memory description of the script. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2005,2006,2007 Free Software Foundation, Inc.
* Copyright (C) 2005,2006,2007,2009 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
@ -206,7 +206,7 @@ grub_script_create_cmdif (struct grub_parser_param *state,
The options for this entry are passed in OPTIONS. */
struct grub_script_cmd *
grub_script_create_cmdmenu (struct grub_parser_param *state,
struct grub_script_arg *title,
struct grub_script_arglist *arglist,
char *sourcecode,
int options)
{
@ -232,9 +232,9 @@ grub_script_create_cmdmenu (struct grub_parser_param *state,
cmd->cmd.next = 0;
/* XXX: Check if this memory is properly freed. */
cmd->sourcecode = sourcecode;
cmd->title = title;
cmd->arglist = arglist;
cmd->options = options;
return (struct grub_script_cmd *) cmd;
}