2006-01-17 Marco Gerards <marco@gnu.org>
* include/grub/normal.h: Include <grub/script.h>. (grub_command_list): Removed struct. (grub_command_list_t): Removed type. (grub_menu_entry): Remove members `num' and `command_list'. Add members `commands' and `sourcecode'. * include/grub/script.h: Add inclusion guards. (grub_script_cmd_menuentry): New struct. (grub_script_execute_menuentry): New prototype. (grub_script_lexer_record_start): Likewise. (grub_script_lexer_record_stop): Likewise. * normal/execute.c (grub_script_execute_menuentry): New function. * normal/lexer.c (record, recording, recordpos, recordlen): New variables. (grub_script_lexer_record_start): New function. (grub_script_lexer_record_stop): Likewise. (recordchar): Likewise. (nextchar): Likewise. (grub_script_yylex): Use `nextchar' to fetch new characters. Use 2048 as the buffer size. Add the tokens `menuentry' and `@'. * normal/main.c: Include <grub/parser.h> and <grub/script.h> (current_menu): New variable. (free_menu): Mainly rewritten. (grub_normal_menu_addentry): New function. (read_config_file): Rewritten. * normal/menu.c (run_menu_entry): Mainly rewritten. * normal/menu_entry.c (make_screen): Rewritten te code to insert the menu entry. (run): Mainly rewritten. * normal/parser.y (menu_entry): New variable. (GRUB_PARSER_TOKEN_MENUENTRY): New token. (menuentry): New rule. (command): Add `menuentry'. (if_statement): Allow additional returns before `fi'. * normal/script.c (grub_script_create_cmdmenu): New function.
This commit is contained in:
parent
144f1f986f
commit
77c4a3939d
10 changed files with 378 additions and 221 deletions
37
ChangeLog
37
ChangeLog
|
@ -1,3 +1,40 @@
|
|||
2006-01-17 Marco Gerards <marco@gnu.org>
|
||||
|
||||
* include/grub/normal.h: Include <grub/script.h>.
|
||||
(grub_command_list): Removed struct.
|
||||
(grub_command_list_t): Removed type.
|
||||
(grub_menu_entry): Remove members `num' and `command_list'. Add
|
||||
members `commands' and `sourcecode'.
|
||||
* include/grub/script.h: Add inclusion guards.
|
||||
(grub_script_cmd_menuentry): New struct.
|
||||
(grub_script_execute_menuentry): New prototype.
|
||||
(grub_script_lexer_record_start): Likewise.
|
||||
(grub_script_lexer_record_stop): Likewise.
|
||||
* normal/execute.c (grub_script_execute_menuentry): New function.
|
||||
* normal/lexer.c (record, recording, recordpos, recordlen): New
|
||||
variables.
|
||||
(grub_script_lexer_record_start): New function.
|
||||
(grub_script_lexer_record_stop): Likewise.
|
||||
(recordchar): Likewise.
|
||||
(nextchar): Likewise.
|
||||
(grub_script_yylex): Use `nextchar' to fetch new characters. Use
|
||||
2048 as the buffer size. Add the tokens `menuentry' and `@'.
|
||||
* normal/main.c: Include <grub/parser.h> and <grub/script.h>
|
||||
(current_menu): New variable.
|
||||
(free_menu): Mainly rewritten.
|
||||
(grub_normal_menu_addentry): New function.
|
||||
(read_config_file): Rewritten.
|
||||
* normal/menu.c (run_menu_entry): Mainly rewritten.
|
||||
* normal/menu_entry.c (make_screen): Rewritten te code to insert
|
||||
the menu entry.
|
||||
(run): Mainly rewritten.
|
||||
* normal/parser.y (menu_entry): New variable.
|
||||
(GRUB_PARSER_TOKEN_MENUENTRY): New token.
|
||||
(menuentry): New rule.
|
||||
(command): Add `menuentry'.
|
||||
(if_statement): Allow additional returns before `fi'.
|
||||
* normal/script.c (grub_script_create_cmdmenu): New function.
|
||||
|
||||
2006-01-03 Marco Gerards <marco@gnu.org>
|
||||
|
||||
* INSTALL: GNU Bison is required.
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <grub/symbol.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/arg.h>
|
||||
#include <grub/script.h>
|
||||
|
||||
/* The maximum size of a command-line. */
|
||||
#define GRUB_MAX_CMDLINE 1600
|
||||
|
@ -84,28 +85,17 @@ struct grub_command
|
|||
};
|
||||
typedef struct grub_command *grub_command_t;
|
||||
|
||||
/* The command list. */
|
||||
struct grub_command_list
|
||||
{
|
||||
/* The string of a command. */
|
||||
char *command;
|
||||
|
||||
/* The next element. */
|
||||
struct grub_command_list *next;
|
||||
};
|
||||
typedef struct grub_command_list *grub_command_list_t;
|
||||
|
||||
/* The menu entry. */
|
||||
struct grub_menu_entry
|
||||
{
|
||||
/* The title name. */
|
||||
const char *title;
|
||||
|
||||
/* The number of commands. */
|
||||
int num;
|
||||
/* The commands associated with this menu entry. */
|
||||
struct grub_script *commands;
|
||||
|
||||
/* The list of commands. */
|
||||
grub_command_list_t command_list;
|
||||
/* The sourcecode of the menu entry, used by the editor. */
|
||||
const char *sourcecode;
|
||||
|
||||
/* The next element. */
|
||||
struct grub_menu_entry *next;
|
||||
|
@ -192,6 +182,9 @@ void grub_context_pop_menu (void);
|
|||
char *grub_normal_do_completion (char *buf, int *restore,
|
||||
void (*hook) (const char *item, grub_completion_type_t type, int count));
|
||||
grub_err_t grub_normal_print_device_info (const char *name);
|
||||
grub_err_t grub_normal_menu_addentry (const char *title,
|
||||
struct grub_script *script,
|
||||
const char *sourcecode);
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
void grub_normal_init (void);
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_SCRIPT_HEADER
|
||||
#define GRUB_SCRIPT_HEADER 1
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/err.h>
|
||||
|
||||
|
@ -104,6 +108,21 @@ struct grub_script_cmdif
|
|||
struct grub_script_cmd *false;
|
||||
};
|
||||
|
||||
/* A menu entry generate statement. */
|
||||
struct grub_script_cmd_menuentry
|
||||
{
|
||||
struct grub_script_cmd cmd;
|
||||
|
||||
/* The title of the menu entry. */
|
||||
struct grub_script_arg *title;
|
||||
|
||||
/* The sourcecode the entry will be generated from. */
|
||||
const char *sourcecode;
|
||||
|
||||
/* Options. XXX: Not used yet. */
|
||||
int options;
|
||||
};
|
||||
|
||||
struct grub_script_arglist *
|
||||
grub_script_create_arglist (void);
|
||||
|
||||
|
@ -120,6 +139,12 @@ struct grub_script_cmd *
|
|||
grub_script_create_cmdif (struct grub_script_cmd *bool,
|
||||
struct grub_script_cmd *true,
|
||||
struct grub_script_cmd *false);
|
||||
|
||||
struct grub_script_cmd *
|
||||
grub_script_create_cmdmenu (struct grub_script_arg *title,
|
||||
char *sourcecode,
|
||||
int options);
|
||||
|
||||
struct grub_script_cmd *
|
||||
grub_script_add_cmd (struct grub_script_cmdblock *cmdblock,
|
||||
struct grub_script_cmd *cmd);
|
||||
|
@ -136,6 +161,8 @@ struct grub_script *grub_script_create (struct grub_script_cmd *cmd,
|
|||
void grub_script_lexer_init (char *s, grub_err_t (*getline) (char **));
|
||||
void grub_script_lexer_ref (void);
|
||||
void grub_script_lexer_deref (void);
|
||||
void grub_script_lexer_record_start (void);
|
||||
char *grub_script_lexer_record_stop (void);
|
||||
|
||||
/* Functions to track allocated memory. */
|
||||
void *grub_script_malloc (grub_size_t size);
|
||||
|
@ -151,6 +178,7 @@ void grub_script_yyerror (char const *err);
|
|||
grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd);
|
||||
grub_err_t grub_script_execute_cmdblock (struct grub_script_cmd *cmd);
|
||||
grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd);
|
||||
grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd);
|
||||
|
||||
/* Execute any GRUB pre-parsed command or script. */
|
||||
grub_err_t grub_script_execute (struct grub_script *script);
|
||||
|
@ -187,3 +215,5 @@ grub_script_function_t grub_script_function_find (char *functionname);
|
|||
int grub_script_function_iterate (int (*iterate) (grub_script_function_t));
|
||||
int grub_script_function_call (grub_script_function_t func,
|
||||
int argc, char **args);
|
||||
|
||||
#endif /* ! GRUB_SCRIPT_HEADER */
|
||||
|
|
|
@ -191,6 +191,36 @@ grub_script_execute_cmdif (struct grub_script_cmd *cmd)
|
|||
return grub_script_execute_cmd (cmdif->false);
|
||||
}
|
||||
|
||||
/* Execute the menu entry generate statement. */
|
||||
grub_err_t
|
||||
grub_script_execute_menuentry (struct grub_script_cmd *cmd)
|
||||
{
|
||||
struct grub_script_cmd_menuentry *cmd_menuentry;
|
||||
char *title;
|
||||
struct grub_script *script;
|
||||
|
||||
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;
|
||||
|
||||
/* Parse the menu entry *again*. */
|
||||
script = grub_script_parse ((char *) cmd_menuentry->sourcecode, 0);
|
||||
|
||||
if (! script)
|
||||
{
|
||||
grub_free (title);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* XXX: When this fails, the memory should be free'ed? */
|
||||
return grub_normal_menu_addentry (title, script,
|
||||
cmd_menuentry->sourcecode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Execute any GRUB pre-parsed command or script. */
|
||||
|
|
|
@ -54,6 +54,11 @@ static int grub_script_lexer_refs = 0;
|
|||
static char *script;
|
||||
static char *newscript;
|
||||
|
||||
static int record = 0;
|
||||
static char *recording = 0;
|
||||
static int recordpos = 0;
|
||||
static int recordlen = 0;
|
||||
|
||||
/* XXX: The lexer is not reentrant. */
|
||||
void
|
||||
grub_script_lexer_init (char *s, grub_err_t (*getline) (char **))
|
||||
|
@ -78,6 +83,63 @@ grub_script_lexer_deref (void)
|
|||
grub_script_lexer_refs--;
|
||||
}
|
||||
|
||||
/* Start recording all characters passing through the lexer. */
|
||||
void
|
||||
grub_script_lexer_record_start (void)
|
||||
{
|
||||
record = 1;
|
||||
recordlen = 100;
|
||||
recording = grub_malloc (recordlen);
|
||||
recordpos = 0;
|
||||
}
|
||||
|
||||
char *
|
||||
grub_script_lexer_record_stop (void)
|
||||
{
|
||||
record = 0;
|
||||
|
||||
/* Delete the last character, it is a `}'. */
|
||||
if (recordpos > 0)
|
||||
{
|
||||
if (recording[--recordpos] != '}')
|
||||
{
|
||||
grub_printf ("Internal error while parsing menu entry");
|
||||
for (;;); /* XXX */
|
||||
}
|
||||
recording[recordpos] = '\0';
|
||||
}
|
||||
|
||||
return recording;
|
||||
}
|
||||
|
||||
/* When recording is enabled, record the character C as the next item
|
||||
in the character stream. */
|
||||
static void
|
||||
recordchar (char c)
|
||||
{
|
||||
if (recordpos == recordlen)
|
||||
{
|
||||
char *old = recording;
|
||||
recordlen += 100;
|
||||
recording = grub_realloc (recording, recordlen);
|
||||
if (! recording)
|
||||
{
|
||||
grub_free (old);
|
||||
record = 0;
|
||||
}
|
||||
}
|
||||
recording[recordpos++] = c;
|
||||
}
|
||||
|
||||
/* Fetch the next character for the lexer. */
|
||||
static void
|
||||
nextchar (void)
|
||||
{
|
||||
if (record)
|
||||
recordchar (*script);
|
||||
script++;
|
||||
}
|
||||
|
||||
int
|
||||
grub_script_yylex (void)
|
||||
{
|
||||
|
@ -96,13 +158,17 @@ grub_script_yylex (void)
|
|||
|| grub_script_lexer_state == GRUB_PARSER_STATE_ESC)
|
||||
&& grub_script_lexer_getline)
|
||||
{
|
||||
while (! grub_strlen (script))
|
||||
while (!script || ! grub_strlen (script))
|
||||
{
|
||||
grub_free (newscript);
|
||||
newscript = 0;
|
||||
grub_script_lexer_getline (&newscript);
|
||||
script = newscript;
|
||||
if (! script)
|
||||
return 0;
|
||||
}
|
||||
grub_dprintf ("scripting", "token=`\\n'\n");
|
||||
recordchar ('\n');
|
||||
if (grub_script_lexer_state != GRUB_PARSER_STATE_ESC)
|
||||
return '\n';
|
||||
}
|
||||
|
@ -139,7 +205,7 @@ grub_script_yylex (void)
|
|||
return ' ';
|
||||
}
|
||||
grub_script_lexer_state = newstate;
|
||||
script++;
|
||||
nextchar ();
|
||||
}
|
||||
grub_dprintf ("scripting", "token=` '\n");
|
||||
return ' ';
|
||||
|
@ -147,13 +213,18 @@ grub_script_yylex (void)
|
|||
case '}':
|
||||
case ';':
|
||||
case '\n':
|
||||
{
|
||||
char c;
|
||||
grub_dprintf ("scripting", "token=`%c'\n", *script);
|
||||
return *(script++);
|
||||
c = *script;;
|
||||
nextchar ();
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: Use a better size. */
|
||||
buffer = grub_script_malloc (2096);
|
||||
buffer = grub_script_malloc (2048);
|
||||
if (! buffer)
|
||||
return 0;
|
||||
|
||||
|
@ -194,7 +265,7 @@ grub_script_yylex (void)
|
|||
*(bp++) = use;
|
||||
|
||||
grub_script_lexer_state = newstate;
|
||||
script++;
|
||||
nextchar ();
|
||||
}
|
||||
|
||||
/* A string of text was read in. */
|
||||
|
@ -209,6 +280,10 @@ grub_script_yylex (void)
|
|||
return GRUB_PARSER_TOKEN_IF;
|
||||
else if (! grub_strcmp (buffer, "function"))
|
||||
return GRUB_PARSER_TOKEN_FUNCTION;
|
||||
else if (! grub_strcmp (buffer, "menuentry"))
|
||||
return GRUB_PARSER_TOKEN_MENUENTRY;
|
||||
else if (! grub_strcmp (buffer, "@"))
|
||||
return GRUB_PARSER_TOKEN_MENUENTRY;
|
||||
else if (! grub_strcmp (buffer, "else"))
|
||||
return GRUB_PARSER_TOKEN_ELSE;
|
||||
else if (! grub_strcmp (buffer, "then"))
|
||||
|
@ -240,14 +315,14 @@ grub_script_yylex (void)
|
|||
{
|
||||
if (grub_script_lexer_state == GRUB_PARSER_STATE_VARNAME2
|
||||
|| grub_script_lexer_state == GRUB_PARSER_STATE_QVARNAME2)
|
||||
script++;
|
||||
nextchar ();
|
||||
grub_script_lexer_state = newstate;
|
||||
break;
|
||||
}
|
||||
|
||||
if (use)
|
||||
*(bp++) = use;
|
||||
script++;
|
||||
nextchar ();
|
||||
grub_script_lexer_state = newstate;
|
||||
}
|
||||
|
||||
|
|
237
normal/main.c
237
normal/main.c
|
@ -27,11 +27,16 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/parser.h>
|
||||
#include <grub/script.h>
|
||||
|
||||
grub_jmp_buf grub_exit_env;
|
||||
|
||||
static grub_fs_module_list_t fs_module_list = 0;
|
||||
|
||||
/* The menu to which the new entries are added by the parser. */
|
||||
static grub_menu_t current_menu = 0;
|
||||
|
||||
#define GRUB_DEFAULT_HISTORY_SIZE 50
|
||||
|
||||
/* Read a line from the file FILE. */
|
||||
|
@ -110,188 +115,118 @@ free_menu (grub_menu_t menu)
|
|||
while (entry)
|
||||
{
|
||||
grub_menu_entry_t next_entry = entry->next;
|
||||
grub_command_list_t cmd = entry->command_list;
|
||||
|
||||
while (cmd)
|
||||
{
|
||||
grub_command_list_t next_cmd = cmd->next;
|
||||
|
||||
grub_free ((void *) cmd->command);
|
||||
cmd = next_cmd;
|
||||
}
|
||||
|
||||
grub_script_free (entry->commands);
|
||||
grub_free ((void *) entry->title);
|
||||
grub_free ((void *) entry->sourcecode);
|
||||
entry = next_entry;
|
||||
}
|
||||
|
||||
grub_free (menu);
|
||||
}
|
||||
|
||||
/* Read the config file CONFIG and return a menu. If no entry is present,
|
||||
return NULL. */
|
||||
grub_err_t
|
||||
grub_normal_menu_addentry (const char *title, struct grub_script *script,
|
||||
const char *sourcecode)
|
||||
{
|
||||
const char *menutitle;
|
||||
grub_menu_entry_t *last = ¤t_menu->entry_list;
|
||||
|
||||
menutitle = grub_strdup (title);
|
||||
if (! menutitle)
|
||||
return grub_errno;
|
||||
|
||||
/* Add the menu entry at the end of the list. */
|
||||
while (*last)
|
||||
last = &(*last)->next;
|
||||
|
||||
*last = grub_malloc (sizeof (**last));
|
||||
if (! *last)
|
||||
{
|
||||
grub_free ((void *) menutitle);
|
||||
grub_free ((void *) sourcecode);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
(*last)->commands = script;
|
||||
(*last)->title = menutitle;
|
||||
(*last)->next = 0;
|
||||
(*last)->sourcecode = sourcecode;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_menu_t
|
||||
read_config_file (const char *config)
|
||||
{
|
||||
grub_file_t file;
|
||||
static char cmdline[GRUB_MAX_CMDLINE];
|
||||
grub_menu_t menu;
|
||||
grub_menu_entry_t *next_entry, cur_entry = 0;
|
||||
grub_command_list_t *next_cmd, cur_cmd;
|
||||
auto grub_err_t getline (char **line);
|
||||
int currline = 0;
|
||||
|
||||
grub_err_t getline (char **line)
|
||||
{
|
||||
char cmdline[100];
|
||||
currline++;
|
||||
|
||||
if (! get_line (file, cmdline, sizeof (cmdline)))
|
||||
return 0;
|
||||
|
||||
*line = grub_strdup (cmdline);
|
||||
if (! *line)
|
||||
return grub_errno;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
char cmdline[100];
|
||||
grub_menu_t newmenu;
|
||||
|
||||
newmenu = grub_malloc (sizeof (*newmenu));
|
||||
if (! newmenu)
|
||||
return 0;
|
||||
newmenu->default_entry = 0;
|
||||
newmenu->fallback_entry = -1;
|
||||
newmenu->timeout = -1;
|
||||
newmenu->size = 0;
|
||||
newmenu->entry_list = 0;
|
||||
current_menu = newmenu;
|
||||
|
||||
/* Try to open the config file. */
|
||||
file = grub_file_open (config);
|
||||
if (! file)
|
||||
return 0;
|
||||
|
||||
/* Initialize the menu. */
|
||||
menu = (grub_menu_t) grub_malloc (sizeof (*menu));
|
||||
if (! menu)
|
||||
{
|
||||
grub_file_close (file);
|
||||
return 0;
|
||||
}
|
||||
menu->default_entry = 0;
|
||||
menu->fallback_entry = -1;
|
||||
menu->timeout = -1;
|
||||
menu->size = 0;
|
||||
menu->entry_list = 0;
|
||||
|
||||
if (! grub_context_push_menu (menu))
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
|
||||
free_menu (menu);
|
||||
grub_file_close (file);
|
||||
|
||||
/* Wait until the user pushes any key so that the user
|
||||
can see what happened. */
|
||||
grub_printf ("\nPress any key to continue...");
|
||||
(void) grub_getkey ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
next_entry = &(menu->entry_list);
|
||||
next_cmd = 0;
|
||||
|
||||
/* Read each line. */
|
||||
while (get_line (file, cmdline, sizeof (cmdline)))
|
||||
{
|
||||
grub_command_t cmd;
|
||||
struct grub_script *parsed_script;
|
||||
|
||||
cmd = grub_command_find (cmdline);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
currline++;
|
||||
|
||||
if (cur_entry)
|
||||
/* Execute the script, line for line. */
|
||||
parsed_script = grub_script_parse (cmdline, getline);
|
||||
|
||||
if (! parsed_script)
|
||||
{
|
||||
if (! cmd || ! (cmd->flags & GRUB_COMMAND_FLAG_TITLE))
|
||||
{
|
||||
cur_cmd = (grub_command_list_t) grub_malloc (sizeof (*cur_cmd));
|
||||
if (! cur_cmd)
|
||||
goto fail;
|
||||
|
||||
cur_cmd->command = grub_strdup (cmdline);
|
||||
if (! cur_cmd->command)
|
||||
{
|
||||
grub_free (cur_cmd);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cur_cmd->next = 0;
|
||||
|
||||
*next_cmd = cur_cmd;
|
||||
next_cmd = &(cur_cmd->next);
|
||||
|
||||
cur_entry->num++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (! cmd)
|
||||
{
|
||||
grub_printf ("Unknown command `%s' is ignored.\n", cmdline);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmd->flags & GRUB_COMMAND_FLAG_TITLE)
|
||||
{
|
||||
char *p;
|
||||
|
||||
cur_entry = (grub_menu_entry_t) grub_malloc (sizeof (*cur_entry));
|
||||
if (! cur_entry)
|
||||
goto fail;
|
||||
|
||||
p = grub_strchr (cmdline, ' ');
|
||||
if (p)
|
||||
cur_entry->title = grub_strdup (p);
|
||||
else
|
||||
cur_entry->title = grub_strdup ("");
|
||||
|
||||
if (! cur_entry->title)
|
||||
{
|
||||
grub_free (cur_entry);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cur_entry->num = 0;
|
||||
cur_entry->command_list = 0;
|
||||
cur_entry->next = 0;
|
||||
|
||||
*next_entry = cur_entry;
|
||||
next_entry = &(cur_entry->next);
|
||||
|
||||
next_cmd = &(cur_entry->command_list);
|
||||
|
||||
menu->size++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Run the command if possible. */
|
||||
if (cmd->flags & GRUB_COMMAND_FLAG_MENU)
|
||||
{
|
||||
grub_command_execute (cmdline, 0);
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_print_error ();
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_printf ("Invalid command `%s' is ignored.\n", cmdline);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
/* Wait until the user pushes any key so that the user can
|
||||
see what happened. */
|
||||
grub_printf ("\nPress any key to continue...");
|
||||
(void) grub_getkey ();
|
||||
|
||||
grub_file_close (file);
|
||||
|
||||
/* If no entry was found or any error occurred, return NULL. */
|
||||
if (menu->size == 0 || grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_context_pop_menu ();
|
||||
free_menu (menu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check values of the default entry and the fallback one. */
|
||||
if (menu->fallback_entry >= menu->size)
|
||||
menu->fallback_entry = -1;
|
||||
/* Execute the command(s). */
|
||||
grub_script_execute (parsed_script);
|
||||
|
||||
if (menu->default_entry < 0 || menu->default_entry >= menu->size)
|
||||
{
|
||||
if (menu->fallback_entry < 0)
|
||||
menu->default_entry = 0;
|
||||
else
|
||||
{
|
||||
menu->default_entry = menu->fallback_entry;
|
||||
menu->fallback_entry = -1;
|
||||
}
|
||||
/* The parsed script was executed, throw it away. */
|
||||
grub_script_free (parsed_script);
|
||||
}
|
||||
|
||||
return menu;
|
||||
return newmenu;
|
||||
|
||||
grub_file_close (file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This starts the normal mode. */
|
||||
|
|
|
@ -347,17 +347,7 @@ run_menu (grub_menu_t menu, int nested)
|
|||
static void
|
||||
run_menu_entry (grub_menu_entry_t entry)
|
||||
{
|
||||
grub_command_list_t cl;
|
||||
|
||||
for (cl = entry->command_list; cl != 0; cl = cl->next)
|
||||
{
|
||||
if (cl->command[0] == '\0')
|
||||
/* Ignore an empty command line. */
|
||||
continue;
|
||||
|
||||
if (grub_command_execute (cl->command, 0) != 0)
|
||||
break;
|
||||
}
|
||||
grub_script_execute (entry->commands);
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
|
||||
/* Implicit execution of boot, only if something is loaded. */
|
||||
|
|
|
@ -413,7 +413,6 @@ static struct screen *
|
|||
make_screen (grub_menu_entry_t entry)
|
||||
{
|
||||
struct screen *screen;
|
||||
grub_command_list_t cl;
|
||||
|
||||
/* Initialize the screen. */
|
||||
screen = grub_malloc (sizeof (*screen));
|
||||
|
@ -436,15 +435,7 @@ make_screen (grub_menu_entry_t entry)
|
|||
if (! init_line (screen->lines))
|
||||
goto fail;
|
||||
|
||||
/* Input the entry. */
|
||||
for (cl = entry->command_list; cl; cl = cl->next)
|
||||
{
|
||||
if (! insert_string (screen, cl->command, 0))
|
||||
goto fail;
|
||||
|
||||
if (! insert_string (screen, "\n", 0))
|
||||
goto fail;
|
||||
}
|
||||
insert_string (screen, (char *) entry->sourcecode, 0);
|
||||
|
||||
/* Reset the cursor position. */
|
||||
screen->column = 0;
|
||||
|
@ -979,38 +970,61 @@ clear_completions (void)
|
|||
static int
|
||||
run (struct screen *screen)
|
||||
{
|
||||
int i;
|
||||
struct grub_script *parsed_script = 0;
|
||||
int currline = 0;
|
||||
char *nextline;
|
||||
|
||||
grub_cls ();
|
||||
grub_printf (" Booting a command list\n\n");
|
||||
|
||||
for (i = 0; i < screen->num_lines; i++)
|
||||
auto grub_err_t editor_getline (char **line);
|
||||
grub_err_t editor_getline (char **line)
|
||||
{
|
||||
struct line *linep = screen->lines + i;
|
||||
struct line *linep = screen->lines + currline;
|
||||
char *p;
|
||||
|
||||
if (currline > screen->num_lines)
|
||||
{
|
||||
*line = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Trim down space characters. */
|
||||
for (p = linep->buf + linep->len - 1;
|
||||
p >= linep->buf && grub_isspace (*p);
|
||||
p--)
|
||||
;
|
||||
*++p = '\0';
|
||||
linep->len = p - linep->buf;
|
||||
|
||||
linep->len = p - linep->buf;
|
||||
for (p = linep->buf; grub_isspace (*p); p++)
|
||||
;
|
||||
|
||||
if (*p == '\0')
|
||||
/* Ignore an empty command line. */
|
||||
continue;
|
||||
|
||||
if (grub_command_execute (p, 0) != 0)
|
||||
break;
|
||||
*line = p;
|
||||
currline++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_cls ();
|
||||
grub_printf (" Booting a command list\n\n");
|
||||
|
||||
|
||||
/* Execute the script, line for line. */
|
||||
while (currline < screen->num_lines - 1)
|
||||
{
|
||||
editor_getline (&nextline);
|
||||
parsed_script = grub_script_parse (nextline, editor_getline);
|
||||
if (parsed_script)
|
||||
{
|
||||
/* Execute the command(s). */
|
||||
grub_script_execute (parsed_script);
|
||||
|
||||
/* The parsed script was executed, throw it away. */
|
||||
grub_script_free (parsed_script);
|
||||
|
||||
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
|
||||
/* Implicit execution of boot, only if something is loaded. */
|
||||
grub_command_execute ("boot", 0);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (grub_errno != GRUB_ERR_NONE)
|
||||
{
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
/* Keep track of the memory allocated for this specific function. */
|
||||
static struct grub_script_mem *func_mem = 0;
|
||||
|
||||
static char *menu_entry = 0;
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
|
@ -40,12 +42,13 @@ static struct grub_script_mem *func_mem = 0;
|
|||
%token GRUB_PARSER_TOKEN_IF "if"
|
||||
%token GRUB_PARSER_TOKEN_WHILE "while"
|
||||
%token GRUB_PARSER_TOKEN_FUNCTION "function"
|
||||
%token GRUB_PARSER_TOKEN_MENUENTRY "menuentry"
|
||||
%token GRUB_PARSER_TOKEN_ELSE "else"
|
||||
%token GRUB_PARSER_TOKEN_THEN "then"
|
||||
%token GRUB_PARSER_TOKEN_FI "fi"
|
||||
%token GRUB_PARSER_TOKEN_NAME
|
||||
%token GRUB_PARSER_TOKEN_VAR
|
||||
%type <cmd> script grubcmd command commands if
|
||||
%type <cmd> script grubcmd command commands menuentry if
|
||||
%type <arglist> arguments;
|
||||
%type <arg> argument;
|
||||
%type <string> "if" "while" "function" "else" "then" "fi"
|
||||
|
@ -53,7 +56,7 @@ static struct grub_script_mem *func_mem = 0;
|
|||
|
||||
%%
|
||||
/* It should be possible to do this in a clean way... */
|
||||
script: commands '\n'
|
||||
script: commands returns
|
||||
{
|
||||
grub_script_parsed = $1;
|
||||
}
|
||||
|
@ -127,6 +130,7 @@ grubcmd: ws GRUB_PARSER_TOKEN_NAME ' ' arguments ws
|
|||
command: grubcmd { $$ = $1; }
|
||||
| if { $$ = $1; }
|
||||
| function { $$ = 0; }
|
||||
| menuentry { $$ = $1; }
|
||||
;
|
||||
|
||||
/* A block of commands. */
|
||||
|
@ -172,6 +176,24 @@ function: "function" ' ' GRUB_PARSER_TOKEN_NAME
|
|||
}
|
||||
;
|
||||
|
||||
/* A menu entry. Carefully save the memory that is allocated. */
|
||||
menuentry: "menuentry" ' ' argument
|
||||
{
|
||||
grub_script_lexer_ref ();
|
||||
} ws '{' returns
|
||||
{
|
||||
/* Record sourcecode of the menu entry. It can be
|
||||
parsed multiple times if it is part of a
|
||||
loop. */
|
||||
grub_script_lexer_record_start ();
|
||||
} commands returns '}'
|
||||
{
|
||||
menu_entry = grub_script_lexer_record_stop ();
|
||||
$$ = grub_script_create_cmdmenu ($3, menu_entry, 0);
|
||||
grub_script_lexer_deref ();
|
||||
}
|
||||
;
|
||||
|
||||
/* The first part of the if statement. It's used to switch the lexer
|
||||
to a state in which it demands more tokens. */
|
||||
if_statement: "if" { grub_script_lexer_ref (); }
|
||||
|
@ -183,7 +205,7 @@ if: if_statement grubcmd ';' ws "then" returns commands returns "fi"
|
|||
$$ = grub_script_create_cmdif ($2, $7, 0);
|
||||
grub_script_lexer_deref ();
|
||||
}
|
||||
| if_statement grubcmd ';' ws "then" returns commands returns "else" returns commands "fi"
|
||||
| if_statement grubcmd ';' ws "then" returns commands returns "else" returns commands returns "fi"
|
||||
{
|
||||
$$ = grub_script_create_cmdif ($2, $7, $11);
|
||||
grub_script_lexer_deref ();
|
||||
|
|
|
@ -201,6 +201,37 @@ grub_script_create_cmdif (struct grub_script_cmd *bool,
|
|||
return (struct grub_script_cmd *) cmd;
|
||||
}
|
||||
|
||||
/* Create a command that adds a menu entry to the menu. Title is an
|
||||
argument that is parsed to generate a string that can be used as
|
||||
the title. The sourcecode for this entry is passed in SOURCECODE.
|
||||
The options for this entry are passed in OPTIONS. */
|
||||
struct grub_script_cmd *
|
||||
grub_script_create_cmdmenu (struct grub_script_arg *title,
|
||||
char *sourcecode,
|
||||
int options)
|
||||
{
|
||||
struct grub_script_cmd_menuentry *cmd;
|
||||
int i;
|
||||
|
||||
/* Having trailing returns can some some annoying conflicts, remove
|
||||
them. XXX: Can the parser be improved to handle this? */
|
||||
for (i = grub_strlen (sourcecode) - 1; i > 0; i--)
|
||||
{
|
||||
if (sourcecode[i] != '\n')
|
||||
break;
|
||||
sourcecode[i] = '\0';
|
||||
}
|
||||
|
||||
cmd = grub_script_malloc (sizeof (*cmd));
|
||||
cmd->cmd.exec = grub_script_execute_menuentry;
|
||||
cmd->cmd.next = 0;
|
||||
cmd->sourcecode = sourcecode;
|
||||
cmd->title = title;
|
||||
cmd->options = options;
|
||||
|
||||
return (struct grub_script_cmd *) cmd;
|
||||
}
|
||||
|
||||
/* Create a block of commands. CMD contains the command that should
|
||||
be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new
|
||||
cmdblock will be created. */
|
||||
|
|
Loading…
Reference in a new issue