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>
|
2006-01-03 Marco Gerards <marco@gnu.org>
|
||||||
|
|
||||||
* INSTALL: GNU Bison is required.
|
* INSTALL: GNU Bison is required.
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <grub/symbol.h>
|
#include <grub/symbol.h>
|
||||||
#include <grub/err.h>
|
#include <grub/err.h>
|
||||||
#include <grub/arg.h>
|
#include <grub/arg.h>
|
||||||
|
#include <grub/script.h>
|
||||||
|
|
||||||
/* The maximum size of a command-line. */
|
/* The maximum size of a command-line. */
|
||||||
#define GRUB_MAX_CMDLINE 1600
|
#define GRUB_MAX_CMDLINE 1600
|
||||||
|
@ -84,28 +85,17 @@ struct grub_command
|
||||||
};
|
};
|
||||||
typedef struct grub_command *grub_command_t;
|
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. */
|
/* The menu entry. */
|
||||||
struct grub_menu_entry
|
struct grub_menu_entry
|
||||||
{
|
{
|
||||||
/* The title name. */
|
/* The title name. */
|
||||||
const char *title;
|
const char *title;
|
||||||
|
|
||||||
/* The number of commands. */
|
/* The commands associated with this menu entry. */
|
||||||
int num;
|
struct grub_script *commands;
|
||||||
|
|
||||||
/* The list of commands. */
|
/* The sourcecode of the menu entry, used by the editor. */
|
||||||
grub_command_list_t command_list;
|
const char *sourcecode;
|
||||||
|
|
||||||
/* The next element. */
|
/* The next element. */
|
||||||
struct grub_menu_entry *next;
|
struct grub_menu_entry *next;
|
||||||
|
@ -192,6 +182,9 @@ void grub_context_pop_menu (void);
|
||||||
char *grub_normal_do_completion (char *buf, int *restore,
|
char *grub_normal_do_completion (char *buf, int *restore,
|
||||||
void (*hook) (const char *item, grub_completion_type_t type, int count));
|
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_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
|
#ifdef GRUB_UTIL
|
||||||
void grub_normal_init (void);
|
void grub_normal_init (void);
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef GRUB_SCRIPT_HEADER
|
||||||
|
#define GRUB_SCRIPT_HEADER 1
|
||||||
|
|
||||||
#include <grub/types.h>
|
#include <grub/types.h>
|
||||||
#include <grub/err.h>
|
#include <grub/err.h>
|
||||||
|
|
||||||
|
@ -104,6 +108,21 @@ struct grub_script_cmdif
|
||||||
struct grub_script_cmd *false;
|
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 *
|
struct grub_script_arglist *
|
||||||
grub_script_create_arglist (void);
|
grub_script_create_arglist (void);
|
||||||
|
|
||||||
|
@ -120,6 +139,12 @@ struct grub_script_cmd *
|
||||||
grub_script_create_cmdif (struct grub_script_cmd *bool,
|
grub_script_create_cmdif (struct grub_script_cmd *bool,
|
||||||
struct grub_script_cmd *true,
|
struct grub_script_cmd *true,
|
||||||
struct grub_script_cmd *false);
|
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 *
|
struct grub_script_cmd *
|
||||||
grub_script_add_cmd (struct grub_script_cmdblock *cmdblock,
|
grub_script_add_cmd (struct grub_script_cmdblock *cmdblock,
|
||||||
struct grub_script_cmd *cmd);
|
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_init (char *s, grub_err_t (*getline) (char **));
|
||||||
void grub_script_lexer_ref (void);
|
void grub_script_lexer_ref (void);
|
||||||
void grub_script_lexer_deref (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. */
|
/* Functions to track allocated memory. */
|
||||||
void *grub_script_malloc (grub_size_t size);
|
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_cmdline (struct grub_script_cmd *cmd);
|
||||||
grub_err_t grub_script_execute_cmdblock (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_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. */
|
/* Execute any GRUB pre-parsed command or script. */
|
||||||
grub_err_t grub_script_execute (struct grub_script *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_iterate (int (*iterate) (grub_script_function_t));
|
||||||
int grub_script_function_call (grub_script_function_t func,
|
int grub_script_function_call (grub_script_function_t func,
|
||||||
int argc, char **args);
|
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);
|
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. */
|
/* Execute any GRUB pre-parsed command or script. */
|
||||||
|
|
|
@ -54,6 +54,11 @@ static int grub_script_lexer_refs = 0;
|
||||||
static char *script;
|
static char *script;
|
||||||
static char *newscript;
|
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. */
|
/* XXX: The lexer is not reentrant. */
|
||||||
void
|
void
|
||||||
grub_script_lexer_init (char *s, grub_err_t (*getline) (char **))
|
grub_script_lexer_init (char *s, grub_err_t (*getline) (char **))
|
||||||
|
@ -78,6 +83,63 @@ grub_script_lexer_deref (void)
|
||||||
grub_script_lexer_refs--;
|
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
|
int
|
||||||
grub_script_yylex (void)
|
grub_script_yylex (void)
|
||||||
{
|
{
|
||||||
|
@ -96,13 +158,17 @@ grub_script_yylex (void)
|
||||||
|| grub_script_lexer_state == GRUB_PARSER_STATE_ESC)
|
|| grub_script_lexer_state == GRUB_PARSER_STATE_ESC)
|
||||||
&& grub_script_lexer_getline)
|
&& grub_script_lexer_getline)
|
||||||
{
|
{
|
||||||
while (! grub_strlen (script))
|
while (!script || ! grub_strlen (script))
|
||||||
{
|
{
|
||||||
grub_free (newscript);
|
grub_free (newscript);
|
||||||
|
newscript = 0;
|
||||||
grub_script_lexer_getline (&newscript);
|
grub_script_lexer_getline (&newscript);
|
||||||
script = newscript;
|
script = newscript;
|
||||||
|
if (! script)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
grub_dprintf ("scripting", "token=`\\n'\n");
|
grub_dprintf ("scripting", "token=`\\n'\n");
|
||||||
|
recordchar ('\n');
|
||||||
if (grub_script_lexer_state != GRUB_PARSER_STATE_ESC)
|
if (grub_script_lexer_state != GRUB_PARSER_STATE_ESC)
|
||||||
return '\n';
|
return '\n';
|
||||||
}
|
}
|
||||||
|
@ -139,7 +205,7 @@ grub_script_yylex (void)
|
||||||
return ' ';
|
return ' ';
|
||||||
}
|
}
|
||||||
grub_script_lexer_state = newstate;
|
grub_script_lexer_state = newstate;
|
||||||
script++;
|
nextchar ();
|
||||||
}
|
}
|
||||||
grub_dprintf ("scripting", "token=` '\n");
|
grub_dprintf ("scripting", "token=` '\n");
|
||||||
return ' ';
|
return ' ';
|
||||||
|
@ -147,13 +213,18 @@ grub_script_yylex (void)
|
||||||
case '}':
|
case '}':
|
||||||
case ';':
|
case ';':
|
||||||
case '\n':
|
case '\n':
|
||||||
|
{
|
||||||
|
char c;
|
||||||
grub_dprintf ("scripting", "token=`%c'\n", *script);
|
grub_dprintf ("scripting", "token=`%c'\n", *script);
|
||||||
return *(script++);
|
c = *script;;
|
||||||
|
nextchar ();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: Use a better size. */
|
/* XXX: Use a better size. */
|
||||||
buffer = grub_script_malloc (2096);
|
buffer = grub_script_malloc (2048);
|
||||||
if (! buffer)
|
if (! buffer)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -194,7 +265,7 @@ grub_script_yylex (void)
|
||||||
*(bp++) = use;
|
*(bp++) = use;
|
||||||
|
|
||||||
grub_script_lexer_state = newstate;
|
grub_script_lexer_state = newstate;
|
||||||
script++;
|
nextchar ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A string of text was read in. */
|
/* A string of text was read in. */
|
||||||
|
@ -209,6 +280,10 @@ grub_script_yylex (void)
|
||||||
return GRUB_PARSER_TOKEN_IF;
|
return GRUB_PARSER_TOKEN_IF;
|
||||||
else if (! grub_strcmp (buffer, "function"))
|
else if (! grub_strcmp (buffer, "function"))
|
||||||
return GRUB_PARSER_TOKEN_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"))
|
else if (! grub_strcmp (buffer, "else"))
|
||||||
return GRUB_PARSER_TOKEN_ELSE;
|
return GRUB_PARSER_TOKEN_ELSE;
|
||||||
else if (! grub_strcmp (buffer, "then"))
|
else if (! grub_strcmp (buffer, "then"))
|
||||||
|
@ -240,14 +315,14 @@ grub_script_yylex (void)
|
||||||
{
|
{
|
||||||
if (grub_script_lexer_state == GRUB_PARSER_STATE_VARNAME2
|
if (grub_script_lexer_state == GRUB_PARSER_STATE_VARNAME2
|
||||||
|| grub_script_lexer_state == GRUB_PARSER_STATE_QVARNAME2)
|
|| grub_script_lexer_state == GRUB_PARSER_STATE_QVARNAME2)
|
||||||
script++;
|
nextchar ();
|
||||||
grub_script_lexer_state = newstate;
|
grub_script_lexer_state = newstate;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use)
|
if (use)
|
||||||
*(bp++) = use;
|
*(bp++) = use;
|
||||||
script++;
|
nextchar ();
|
||||||
grub_script_lexer_state = newstate;
|
grub_script_lexer_state = newstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
237
normal/main.c
237
normal/main.c
|
@ -27,11 +27,16 @@
|
||||||
#include <grub/mm.h>
|
#include <grub/mm.h>
|
||||||
#include <grub/term.h>
|
#include <grub/term.h>
|
||||||
#include <grub/env.h>
|
#include <grub/env.h>
|
||||||
|
#include <grub/parser.h>
|
||||||
|
#include <grub/script.h>
|
||||||
|
|
||||||
grub_jmp_buf grub_exit_env;
|
grub_jmp_buf grub_exit_env;
|
||||||
|
|
||||||
static grub_fs_module_list_t fs_module_list = 0;
|
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
|
#define GRUB_DEFAULT_HISTORY_SIZE 50
|
||||||
|
|
||||||
/* Read a line from the file FILE. */
|
/* Read a line from the file FILE. */
|
||||||
|
@ -110,188 +115,118 @@ free_menu (grub_menu_t menu)
|
||||||
while (entry)
|
while (entry)
|
||||||
{
|
{
|
||||||
grub_menu_entry_t next_entry = entry->next;
|
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->title);
|
||||||
|
grub_free ((void *) entry->sourcecode);
|
||||||
entry = next_entry;
|
entry = next_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
grub_free (menu);
|
grub_free (menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the config file CONFIG and return a menu. If no entry is present,
|
grub_err_t
|
||||||
return NULL. */
|
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
|
static grub_menu_t
|
||||||
read_config_file (const char *config)
|
read_config_file (const char *config)
|
||||||
{
|
{
|
||||||
grub_file_t file;
|
grub_file_t file;
|
||||||
static char cmdline[GRUB_MAX_CMDLINE];
|
auto grub_err_t getline (char **line);
|
||||||
grub_menu_t menu;
|
int currline = 0;
|
||||||
grub_menu_entry_t *next_entry, cur_entry = 0;
|
|
||||||
grub_command_list_t *next_cmd, cur_cmd;
|
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. */
|
/* Try to open the config file. */
|
||||||
file = grub_file_open (config);
|
file = grub_file_open (config);
|
||||||
if (! file)
|
if (! file)
|
||||||
return 0;
|
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)))
|
while (get_line (file, cmdline, sizeof (cmdline)))
|
||||||
{
|
{
|
||||||
grub_command_t cmd;
|
struct grub_script *parsed_script;
|
||||||
|
|
||||||
cmd = grub_command_find (cmdline);
|
currline++;
|
||||||
grub_errno = GRUB_ERR_NONE;
|
|
||||||
|
|
||||||
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))
|
/* Wait until the user pushes any key so that the user can
|
||||||
{
|
see what happened. */
|
||||||
cur_cmd = (grub_command_list_t) grub_malloc (sizeof (*cur_cmd));
|
grub_printf ("\nPress any key to continue...");
|
||||||
if (! cur_cmd)
|
(void) grub_getkey ();
|
||||||
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:
|
|
||||||
|
|
||||||
grub_file_close (file);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check values of the default entry and the fallback one. */
|
/* Execute the command(s). */
|
||||||
if (menu->fallback_entry >= menu->size)
|
grub_script_execute (parsed_script);
|
||||||
menu->fallback_entry = -1;
|
|
||||||
|
|
||||||
if (menu->default_entry < 0 || menu->default_entry >= menu->size)
|
/* The parsed script was executed, throw it away. */
|
||||||
{
|
grub_script_free (parsed_script);
|
||||||
if (menu->fallback_entry < 0)
|
|
||||||
menu->default_entry = 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
menu->default_entry = menu->fallback_entry;
|
|
||||||
menu->fallback_entry = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return menu;
|
return newmenu;
|
||||||
|
|
||||||
|
grub_file_close (file);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This starts the normal mode. */
|
/* This starts the normal mode. */
|
||||||
|
|
|
@ -347,17 +347,7 @@ run_menu (grub_menu_t menu, int nested)
|
||||||
static void
|
static void
|
||||||
run_menu_entry (grub_menu_entry_t entry)
|
run_menu_entry (grub_menu_entry_t entry)
|
||||||
{
|
{
|
||||||
grub_command_list_t cl;
|
grub_script_execute (entry->commands);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
|
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
|
||||||
/* Implicit execution of boot, only if something 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)
|
make_screen (grub_menu_entry_t entry)
|
||||||
{
|
{
|
||||||
struct screen *screen;
|
struct screen *screen;
|
||||||
grub_command_list_t cl;
|
|
||||||
|
|
||||||
/* Initialize the screen. */
|
/* Initialize the screen. */
|
||||||
screen = grub_malloc (sizeof (*screen));
|
screen = grub_malloc (sizeof (*screen));
|
||||||
|
@ -436,15 +435,7 @@ make_screen (grub_menu_entry_t entry)
|
||||||
if (! init_line (screen->lines))
|
if (! init_line (screen->lines))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* Input the entry. */
|
insert_string (screen, (char *) entry->sourcecode, 0);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset the cursor position. */
|
/* Reset the cursor position. */
|
||||||
screen->column = 0;
|
screen->column = 0;
|
||||||
|
@ -979,38 +970,61 @@ clear_completions (void)
|
||||||
static int
|
static int
|
||||||
run (struct screen *screen)
|
run (struct screen *screen)
|
||||||
{
|
{
|
||||||
int i;
|
struct grub_script *parsed_script = 0;
|
||||||
|
int currline = 0;
|
||||||
|
char *nextline;
|
||||||
|
|
||||||
grub_cls ();
|
auto grub_err_t editor_getline (char **line);
|
||||||
grub_printf (" Booting a command list\n\n");
|
grub_err_t editor_getline (char **line)
|
||||||
|
|
||||||
for (i = 0; i < screen->num_lines; i++)
|
|
||||||
{
|
{
|
||||||
struct line *linep = screen->lines + i;
|
struct line *linep = screen->lines + currline;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
|
if (currline > screen->num_lines)
|
||||||
|
{
|
||||||
|
*line = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Trim down space characters. */
|
/* Trim down space characters. */
|
||||||
for (p = linep->buf + linep->len - 1;
|
for (p = linep->buf + linep->len - 1;
|
||||||
p >= linep->buf && grub_isspace (*p);
|
p >= linep->buf && grub_isspace (*p);
|
||||||
p--)
|
p--)
|
||||||
;
|
;
|
||||||
*++p = '\0';
|
*++p = '\0';
|
||||||
linep->len = p - linep->buf;
|
|
||||||
|
|
||||||
|
linep->len = p - linep->buf;
|
||||||
for (p = linep->buf; grub_isspace (*p); p++)
|
for (p = linep->buf; grub_isspace (*p); p++)
|
||||||
;
|
;
|
||||||
|
*line = p;
|
||||||
if (*p == '\0')
|
currline++;
|
||||||
/* Ignore an empty command line. */
|
return 0;
|
||||||
continue;
|
|
||||||
|
|
||||||
if (grub_command_execute (p, 0) != 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 ())
|
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
|
||||||
/* Implicit execution of boot, only if something is loaded. */
|
/* Implicit execution of boot, only if something is loaded. */
|
||||||
grub_command_execute ("boot", 0);
|
grub_command_execute ("boot", 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (grub_errno != GRUB_ERR_NONE)
|
if (grub_errno != GRUB_ERR_NONE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
/* Keep track of the memory allocated for this specific function. */
|
/* Keep track of the memory allocated for this specific function. */
|
||||||
static struct grub_script_mem *func_mem = 0;
|
static struct grub_script_mem *func_mem = 0;
|
||||||
|
|
||||||
|
static char *menu_entry = 0;
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
|
@ -40,12 +42,13 @@ static struct grub_script_mem *func_mem = 0;
|
||||||
%token GRUB_PARSER_TOKEN_IF "if"
|
%token GRUB_PARSER_TOKEN_IF "if"
|
||||||
%token GRUB_PARSER_TOKEN_WHILE "while"
|
%token GRUB_PARSER_TOKEN_WHILE "while"
|
||||||
%token GRUB_PARSER_TOKEN_FUNCTION "function"
|
%token GRUB_PARSER_TOKEN_FUNCTION "function"
|
||||||
|
%token GRUB_PARSER_TOKEN_MENUENTRY "menuentry"
|
||||||
%token GRUB_PARSER_TOKEN_ELSE "else"
|
%token GRUB_PARSER_TOKEN_ELSE "else"
|
||||||
%token GRUB_PARSER_TOKEN_THEN "then"
|
%token GRUB_PARSER_TOKEN_THEN "then"
|
||||||
%token GRUB_PARSER_TOKEN_FI "fi"
|
%token GRUB_PARSER_TOKEN_FI "fi"
|
||||||
%token GRUB_PARSER_TOKEN_NAME
|
%token GRUB_PARSER_TOKEN_NAME
|
||||||
%token GRUB_PARSER_TOKEN_VAR
|
%token GRUB_PARSER_TOKEN_VAR
|
||||||
%type <cmd> script grubcmd command commands if
|
%type <cmd> script grubcmd command commands menuentry if
|
||||||
%type <arglist> arguments;
|
%type <arglist> arguments;
|
||||||
%type <arg> argument;
|
%type <arg> argument;
|
||||||
%type <string> "if" "while" "function" "else" "then" "fi"
|
%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... */
|
/* It should be possible to do this in a clean way... */
|
||||||
script: commands '\n'
|
script: commands returns
|
||||||
{
|
{
|
||||||
grub_script_parsed = $1;
|
grub_script_parsed = $1;
|
||||||
}
|
}
|
||||||
|
@ -127,6 +130,7 @@ grubcmd: ws GRUB_PARSER_TOKEN_NAME ' ' arguments ws
|
||||||
command: grubcmd { $$ = $1; }
|
command: grubcmd { $$ = $1; }
|
||||||
| if { $$ = $1; }
|
| if { $$ = $1; }
|
||||||
| function { $$ = 0; }
|
| function { $$ = 0; }
|
||||||
|
| menuentry { $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/* A block of commands. */
|
/* 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
|
/* The first part of the if statement. It's used to switch the lexer
|
||||||
to a state in which it demands more tokens. */
|
to a state in which it demands more tokens. */
|
||||||
if_statement: "if" { grub_script_lexer_ref (); }
|
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_create_cmdif ($2, $7, 0);
|
||||||
grub_script_lexer_deref ();
|
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_create_cmdif ($2, $7, $11);
|
||||||
grub_script_lexer_deref ();
|
grub_script_lexer_deref ();
|
||||||
|
|
|
@ -201,6 +201,37 @@ grub_script_create_cmdif (struct grub_script_cmd *bool,
|
||||||
return (struct grub_script_cmd *) cmd;
|
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
|
/* 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
|
be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new
|
||||||
cmdblock will be created. */
|
cmdblock will be created. */
|
||||||
|
|
Loading…
Reference in a new issue