=== added file 'ChangeLog.lexer-rewrite'
--- ChangeLog.lexer-rewrite 1970-01-01 00:00:00 +0000
+++ ChangeLog.lexer-rewrite 2010-01-18 15:28:12 +0000
@@ -0,0 +1,70 @@
+2010-01-10 BVK Chaitanya
+
+ * conf/any-emu.rmk: Build rule updates.
+ * conf/common.rmk: Likewise.
+ * conf/i386-coreboot.rmk: Likewise.
+ * conf/i386-efi.rmk: Likewise.
+ * conf/i386-ieee1275.rmk: Likewise.
+ * conf/i386-pc.rmk: Likewise.
+ * conf/powerpc-ieee1275.rmk: Likewise.
+ * conf/x86_64-efi.rmk: Likewise.
+
+ * configure.ac: Configure check for flex.
+
+ * include/grub/script_sh.h (grub_script_arg_type_t): More argument
+ types.
+ (grub_lexer_param): Struct member updates.
+ (grub_parser_param): Likewise.
+ (GRUB_LEXER_TOKEN_MAX): Maximum token size.
+ (GRUB_LEXER_RECORD_INCREMENT): Memory increments' size.
+ (grub_script_lexer_init): Prototype update.
+ (grub_script_lexer_record_start): Likewise.
+ (grub_script_lexer_record_stop): Likewise.
+ (grub_script_lexer_yywrap): New function prototype.
+ (grub_script_lexer_fini): Likewise.
+ (grub_script_execute_argument_to_string): Removed by...
+ (grub_script_execute_argument_to_argv): ...better version.
+
+ * script/execute.c (ROUND_UPTO): New macro.
+ (grub_script_execute_cmdline): Out of memory fixes.
+ (grub_script_execute_menuentry): Likewise.
+ (grub_script_execute_argument_to_string): Removed. Update all
+ users by...
+ (grub_script_execute_argument_to_argv): ...better version.
+ * script/function.c (grub_script_function_create): Use
+ grub_script_execute_argument_to_argv instead of
+ grub_script_execute_argument_to_string.
+
+ * script/lexer.c (check_varstate): Removed.
+ (check_textstate): Removed.
+ (grub_script_lexer_record_start): Likewise.
+ (grub_script_lexer_record_stop): Likewise.
+ (recordchar): Replaced with...
+ (grub_script_lexer_record): ...new function.
+ (nextchar): Removed.
+ (grub_script_lexer_init): Rewritten.
+ (grub_script_yylex): Rewritten.
+ (append_newline): New function.
+ (grub_script_lexer_yywrap): New function.
+ (grub_script_lexer_fini): New function.
+ (grub_script_yyerror): Sets error flag.
+
+ * script/yylex.l: New file.
+ (grub_lexer_yyfree): Wrapper for flex yyffre.
+ (grub_lexer_yyalloc): Likewise.
+ (grub_lexer_yyrealloc): Likewise.
+ * script/parser.y: Refactored.
+
+ * script/script.c (grub_script_arg_add): Out of memory fixes.
+ (grub_script_add_arglist): Likewise.
+ (grub_script_create_cmdline): Likewise.
+ (grub_script_create_cmdmenu): Likewise.
+ (grub_script_add_cmd): Likewise.
+ (grub_script_parse): Use grub_script_lexer_fini to deallocated.
+ * util/grub-script-check.c (grub_script_execute_menuentry): Remove
+ unnecessary code.
+
+ * tests/grub_script_echo1.in: New testcase.
+ * tests/grub_script_vars1.in: New testcase.
+ * tests/grub_script_echo_keywords.in: New testcase.
+
=== modified file 'conf/any-emu.rmk'
--- conf/any-emu.rmk 2010-01-10 00:47:19 +0000
+++ conf/any-emu.rmk 2010-01-18 15:32:17 +0000
@@ -1,7 +1,7 @@
# -*- makefile -*-
# Used by various components. These rules need to precede them.
-script/lexer.c_DEPENDENCIES = grub_script.tab.h
+script/lexer.c_DEPENDENCIES = grub_script.tab.h grub_script.yy.h
sbin_UTILITIES += grub-emu
util/grub-emu.c_DEPENDENCIES = grub_emu_init.h
@@ -33,6 +33,8 @@
commands/terminal.c lib/charset.c \
script/main.c script/execute.c script/function.c \
script/lexer.c script/script.c grub_script.tab.c \
+ grub_script.yy.c \
+ \
partmap/amiga.c partmap/apple.c partmap/msdos.c partmap/sun.c \
partmap/acorn.c partmap/gpt.c \
\
@@ -98,3 +100,9 @@
grub_script.tab.c grub_script.tab.h: script/parser.y
$(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/script/parser.y
DISTCLEANFILES += grub_script.tab.c grub_script.tab.h
+
+grub_script.yy.c grub_script.yy.h: script/yylex.l
+ $(LEX) -o grub_script.yy.c --header-file=grub_script.yy.h $(srcdir)/script/yylex.l
+ sed -i 's/^#include.*\(\|\|\|\|\)//g' grub_script.yy.h
+ sed -i 's/^#include.*\(\|\|\|\|\)//g' grub_script.yy.c
+DISTCLEANFILES += grub_script.yy.c grub_script.yy.h
=== modified file 'conf/common.rmk'
--- conf/common.rmk 2010-01-18 11:28:03 +0000
+++ conf/common.rmk 2010-01-18 14:26:47 +0000
@@ -88,13 +88,21 @@
bin_UTILITIES += grub-mkrelpath
grub_mkrelpath_SOURCES = gnulib/progname.c util/grub-mkrelpath.c util/misc.c
+# For the lexer.
+grub_script.yy.c grub_script.yy.h: script/yylex.l
+ $(LEX) -o grub_script.yy.c --header-file=grub_script.yy.h $(srcdir)/script/yylex.l
+ sed -i 's/^#include.*\(\|\|\|\|\)//g' grub_script.yy.h
+ sed -i 's/^#include.*\(\|\|\|\|\)//g' grub_script.yy.c
+DISTCLEANFILES += grub_script.yy.c grub_script.yy.h
+
# For grub-script-check.
bin_UTILITIES += grub-script-check
util/grub-script-check.c_DEPENDENCIES = grub_script_check_init.h
grub_script_check_SOURCES = gnulib/progname.c util/grub-script-check.c util/misc.c \
script/main.c script/script.c script/function.c script/lexer.c \
kern/handler.c kern/err.c kern/parser.c kern/list.c \
- kern/misc.c kern/env.c grub_script_check_init.c grub_script.tab.c
+ kern/misc.c kern/env.c grub_script_check_init.c grub_script.tab.c \
+ grub_script.yy.c
# For the parser.
grub_script.tab.c grub_script.tab.h: script/parser.y
@@ -591,7 +599,7 @@
# For sh.mod.
sh_mod_SOURCES = script/main.c script/script.c script/execute.c \
- script/function.c script/lexer.c grub_script.tab.c
+ script/function.c script/lexer.c grub_script.tab.c grub_script.yy.c
sh_mod_CFLAGS = $(COMMON_CFLAGS)
sh_mod_LDFLAGS = $(COMMON_LDFLAGS)
=== modified file 'conf/i386-coreboot.rmk'
--- conf/i386-coreboot.rmk 2010-01-15 20:11:51 +0000
+++ conf/i386-coreboot.rmk 2010-01-18 12:53:02 +0000
@@ -5,7 +5,7 @@
COMMON_LDFLAGS = -m32 -nostdlib
# Used by various components. These rules need to precede them.
-script/lexer.c_DEPENDENCIES = grub_script.tab.h
+script/lexer.c_DEPENDENCIES = grub_script.tab.h grub_script.yy.h
# Images.
=== modified file 'conf/i386-efi.rmk'
--- conf/i386-efi.rmk 2010-01-07 21:18:59 +0000
+++ conf/i386-efi.rmk 2010-01-18 12:53:02 +0000
@@ -5,7 +5,7 @@
COMMON_LDFLAGS = -melf_i386 -nostdlib
# Used by various components. These rules need to precede them.
-script/lexer.c_DEPENDENCIES = grub_script.tab.h
+script/lexer.c_DEPENDENCIES = grub_script.tab.h grub_script.yy.h
# Utilities.
bin_UTILITIES = grub-mkimage
=== modified file 'conf/i386-ieee1275.rmk'
--- conf/i386-ieee1275.rmk 2010-01-07 21:18:59 +0000
+++ conf/i386-ieee1275.rmk 2010-01-18 12:53:02 +0000
@@ -5,7 +5,7 @@
COMMON_LDFLAGS = -nostdlib
# Used by various components. These rules need to precede them.
-script/lexer.c_DEPENDENCIES = grub_script.tab.h
+script/lexer.c_DEPENDENCIES = grub_script.tab.h grub_script.yy.h
# Images.
pkglib_PROGRAMS = kernel.img
=== modified file 'conf/i386-pc.rmk'
--- conf/i386-pc.rmk 2010-01-15 20:11:51 +0000
+++ conf/i386-pc.rmk 2010-01-18 12:53:02 +0000
@@ -7,7 +7,7 @@
COMMON_LDFLAGS = -m32 -nostdlib
# Used by various components. These rules need to precede them.
-script/lexer.c_DEPENDENCIES = grub_script.tab.h
+script/lexer.c_DEPENDENCIES = grub_script.tab.h grub_script.yy.h
# Images.
pkglib_IMAGES = boot.img cdboot.img diskboot.img kernel.img lnxboot.img \
=== modified file 'conf/powerpc-ieee1275.rmk'
--- conf/powerpc-ieee1275.rmk 2010-01-09 22:22:48 +0000
+++ conf/powerpc-ieee1275.rmk 2010-01-18 12:53:02 +0000
@@ -6,7 +6,7 @@
COMMON_LDFLAGS += -nostdlib
# Used by various components. These rules need to precede them.
-script/lexer.c_DEPENDENCIES = grub_script.tab.h
+script/lexer.c_DEPENDENCIES = grub_script.tab.h grub_script.yy.h
# Images.
=== modified file 'conf/sparc64-ieee1275.rmk'
--- conf/sparc64-ieee1275.rmk 2010-01-07 21:18:59 +0000
+++ conf/sparc64-ieee1275.rmk 2010-01-18 15:35:50 +0000
@@ -6,7 +6,7 @@
COMMON_LDFLAGS = -melf64_sparc -nostdlib -mno-relax
# Used by various components. These rules need to precede them.
-script/lexer.c_DEPENDENCIES = grub_script.tab.h
+script/lexer.c_DEPENDENCIES = grub_script.tab.h grub_script.yy.h
# Images.
pkglib_IMAGES = boot.img diskboot.img kernel.img
=== modified file 'conf/tests.rmk'
--- conf/tests.rmk 2010-01-12 10:19:40 +0000
+++ conf/tests.rmk 2010-01-18 14:57:10 +0000
@@ -37,12 +37,28 @@
check_SCRIPTS += example_grub_script_test
example_grub_script_test_SOURCES = tests/example_grub_script_test.in
+#
+# Rules for real tests
+#
+
+check_SCRIPTS += grub_script_echo1
+grub_script_echo1_SOURCES = tests/grub_script_echo1.in
+
+check_SCRIPTS += grub_script_echo_keywords
+grub_script_echo_keywords_SOURCES = tests/grub_script_echo_keywords.in
+
+check_SCRIPTS += grub_script_vars1
+grub_script_vars1_SOURCES = tests/grub_script_vars1.in
# List of tests to execute on "make check"
-SCRIPTED_TESTS = example_scripted_test
-SCRIPTED_TESTS += example_grub_script_test
-UNIT_TESTS = example_unit_test
-FUNCTIONAL_TESTS = example_functional_test.mod
+# SCRIPTED_TESTS = example_scripted_test
+# SCRIPTED_TESTS += example_grub_script_test
+# UNIT_TESTS = example_unit_test
+# FUNCTIONAL_TESTS = example_functional_test.mod
+
+SCRIPTED_TESTS = grub_script_echo1
+SCRIPTED_TESTS += grub_script_echo_keywords
+SCRIPTED_TESTS += grub_script_vars1
# dependencies between tests and testing-tools
$(SCRIPTED_TESTS): grub-shell grub-shell-tester
=== modified file 'conf/x86_64-efi.rmk'
--- conf/x86_64-efi.rmk 2010-01-15 20:11:51 +0000
+++ conf/x86_64-efi.rmk 2010-01-18 12:53:02 +0000
@@ -5,7 +5,7 @@
COMMON_LDFLAGS = -melf_x86_64 -nostdlib
# Used by various components. These rules need to precede them.
-script/lexer.c_DEPENDENCIES = grub_script.tab.h
+script/lexer.c_DEPENDENCIES = grub_script.tab.h grub_script.yy.h
# Utilities.
bin_UTILITIES = grub-mkimage
=== modified file 'configure.ac'
--- configure.ac 2010-01-01 20:32:30 +0000
+++ configure.ac 2010-01-09 17:40:47 +0000
@@ -148,6 +148,11 @@
AC_MSG_ERROR([cmp is not found])
fi
+AC_CHECK_PROGS([LEX], [flex])
+if test "x$LEX" = x; then
+ AC_MSG_ERROR([flex is not found])
+fi
+
AC_CHECK_PROGS([YACC], [bison])
if test "x$YACC" = x; then
AC_MSG_ERROR([bison is not found])
=== modified file 'include/grub/script_sh.h'
--- include/grub/script_sh.h 2009-06-17 13:47:37 +0000
+++ include/grub/script_sh.h 2010-01-18 15:05:46 +0000
@@ -1,7 +1,7 @@
/* normal_parser.h */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2005,2007,2009 Free Software Foundation, Inc.
+ * Copyright (C) 2005,2007,2009,2010 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
@@ -45,8 +45,11 @@
typedef enum
{
- GRUB_SCRIPT_ARG_TYPE_STR,
- GRUB_SCRIPT_ARG_TYPE_VAR
+ GRUB_SCRIPT_ARG_TYPE_VAR,
+ GRUB_SCRIPT_ARG_TYPE_TEXT,
+ GRUB_SCRIPT_ARG_TYPE_DQVAR,
+ GRUB_SCRIPT_ARG_TYPE_DQSTR,
+ GRUB_SCRIPT_ARG_TYPE_SQSTR
} grub_script_arg_type_t;
/* A part of an argument. */
@@ -121,12 +124,6 @@
/* State of the lexer as passed to the lexer. */
struct grub_lexer_param
{
- /* Set to 0 when the lexer is done. */
- int done;
-
- /* State of the state machine. */
- grub_parser_state_t state;
-
/* Function used by the lexer to get a new line when more input is
expected, but not available. */
grub_reader_getline_t getline;
@@ -137,10 +134,6 @@
depleted. */
int refs;
- /* The character stream that has to be parsed. */
- char *script;
- char *newscript; /* XXX */
-
/* While walking through the databuffer, `record' the characters to
this other buffer. It can be used to edit the menu entry at a
later moment. */
@@ -157,13 +150,32 @@
/* Size of RECORDING. */
int recordlen;
- /* The token that is already parsed but not yet returned. */
- int tokenonhold;
-
- /* Was the last token a newline? */
- int was_newline;
+ /* End of file reached. */
+ int eof;
+
+ /* Merge multiple word tokens. */
+ int merge_start;
+ int merge_end;
+
+ /* Text of current token. */
+ char *text;
+
+ /* Type of text. */
+ grub_script_arg_type_t type;
+
+ /* Flex scanner. */
+ void *yyscanner;
+
+ /* Flex scanner buffer. */
+ void *buffer;
+
+ /* Length of current token text. */
+ unsigned size;
};
+#define GRUB_LEXER_TOKEN_MAX 256
+#define GRUB_LEXER_RECORD_INCREMENT 256
+
/* State of the parser as passes to the parser. */
struct grub_parser_param
{
@@ -223,12 +235,16 @@
struct grub_script *grub_script_create (struct grub_script_cmd *cmd,
struct grub_script_mem *mem);
-struct grub_lexer_param *grub_script_lexer_init (char *s,
+struct grub_lexer_param *grub_script_lexer_init (struct grub_parser_param *parser,
+ char *script,
grub_reader_getline_t getline);
+void grub_script_lexer_fini (struct grub_lexer_param *);
void grub_script_lexer_ref (struct grub_lexer_param *);
void grub_script_lexer_deref (struct grub_lexer_param *);
-void grub_script_lexer_record_start (struct grub_lexer_param *);
-char *grub_script_lexer_record_stop (struct grub_lexer_param *);
+void grub_script_lexer_record_start (struct grub_parser_param *);
+char *grub_script_lexer_record_stop (struct grub_parser_param *);
+int grub_script_lexer_yywrap (struct grub_parser_param *);
+void grub_script_lexer_record (struct grub_parser_param *, char *);
/* Functions to track allocated memory. */
struct grub_script_mem *grub_script_mem_record (struct grub_parser_param *state);
@@ -284,7 +300,7 @@
int grub_script_function_call (grub_script_function_t func,
int argc, char **args);
-char *
-grub_script_execute_argument_to_string (struct grub_script_arg *arg);
+char **
+grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist);
#endif /* ! GRUB_NORMAL_PARSER_HEADER */
=== modified file 'script/execute.c'
--- script/execute.c 2009-12-13 12:35:20 +0000
+++ script/execute.c 2010-01-18 15:06:08 +0000
@@ -1,7 +1,7 @@
/* execute.c -- Execute a GRUB script. */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2005,2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright (C) 2005,2007,2008,2009,2010 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
@@ -35,49 +35,146 @@
return cmd->exec (cmd);
}
-/* Parse ARG and return the textual representation. Add strings are
- concatenated and all values of the variables are filled in. */
-char *
-grub_script_execute_argument_to_string (struct grub_script_arg *arg)
+#define ROUND_UPTO(sz,up) (((sz) + (up) - 1) / (up) * (up))
+
+/* Expand arguments in ARGLIST into multiple arguments. */
+char **
+grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist)
{
- int size = 0;
- char *val;
- char *chararg;
- struct grub_script_arg *argi;
-
- /* First determine the size of the argument. */
- for (argi = arg; argi; argi = argi->next)
- {
- if (argi->type == 1)
- {
- val = grub_env_get (argi->str);
- if (val)
- size += grub_strlen (val);
- }
- else
- size += grub_strlen (argi->str);
- }
-
- /* Create the argument. */
- chararg = grub_malloc (size + 1);
- if (! chararg)
- return 0;
-
- *chararg = '\0';
- /* First determine the size of the argument. */
- for (argi = arg; argi; argi = argi->next)
- {
- if (argi->type == 1)
- {
- val = grub_env_get (argi->str);
- if (val)
- grub_strcat (chararg, val);
- }
- else
- grub_strcat (chararg, argi->str);
- }
-
- return chararg;
+ int i;
+ int oom;
+ int argc;
+ int empty;
+ char *ptr;
+ char **argv;
+ char *value;
+ struct grub_script_arg *arg;
+
+ auto void push (char *str);
+ void push (char *str)
+ {
+ char **p;
+
+ if (oom)
+ return;
+
+ p = grub_realloc (argv, ROUND_UPTO (sizeof(char*) * (argc + 1), 32));
+ if (!p)
+ oom = 1;
+ else
+ {
+ p[argc++] = str;
+ argv = p;
+ }
+ }
+
+ auto char* append (const char *str, grub_size_t nchar);
+ char* append (const char *str, grub_size_t nchar)
+ {
+ int len;
+ int old;
+ char *p;
+
+ if (oom || !str)
+ return 0;
+
+ len = nchar ?: grub_strlen (str);
+ old = argv[argc - 1] ? grub_strlen (argv[argc - 1]) : 0;
+ p = grub_realloc (argv[argc - 1], ROUND_UPTO(old + len + 1, 32));
+
+ if (p)
+ {
+ grub_strncpy (p + old, str, len);
+ p[old + len] = '\0';
+ }
+ else
+ {
+ oom = 1;
+ grub_free (argv[argc - 1]);
+ }
+ argv[argc - 1] = p;
+ return argv[argc - 1];
+ }
+
+ /* Move *STR to the begining of next word, but return current word. */
+ auto char* move_to_next (char **str);
+ char* move_to_next (char **str)
+ {
+ char *end;
+ char *start;
+
+ if (oom || !str || !*str)
+ return 0;
+
+ start = *str;
+ while (*start && grub_isspace (*start)) start++;
+ if (*start == '\0')
+ return 0;
+
+ end = start + 1;
+ while (*end && !grub_isspace (*end)) end++;
+
+ *str = end;
+ return start;
+ }
+
+ oom = 0;
+ argv = 0;
+ argc = 0;
+ push (0);
+ for (; arglist; arglist = arglist->next)
+ {
+ empty = 1;
+ arg = arglist->arg;
+ while (arg)
+ {
+ switch (arg->type)
+ {
+ case GRUB_SCRIPT_ARG_TYPE_VAR:
+ value = grub_env_get (arg->str);
+ while (*value && (ptr = move_to_next(&value)))
+ {
+ empty = 0;
+ append (ptr, value - ptr);
+ if (*value) push(0);
+ }
+ break;
+
+ case GRUB_SCRIPT_ARG_TYPE_TEXT:
+ if (grub_strlen (arg->str) > 0)
+ {
+ empty = 0;
+ append (arg->str, 0);
+ }
+ break;
+
+ case GRUB_SCRIPT_ARG_TYPE_DQSTR:
+ case GRUB_SCRIPT_ARG_TYPE_SQSTR:
+ empty = 0;
+ append (arg->str, 0);
+ break;
+
+ case GRUB_SCRIPT_ARG_TYPE_DQVAR:
+ empty = 0;
+ append (grub_env_get (arg->str), 0);
+ break;
+ }
+ arg = arg->next;
+ }
+ if (!empty)
+ push (0);
+ }
+ push (0); /* Ensure argv[argc] == 0. */
+
+ if (oom)
+ {
+ for (i = 0; i < argc; i++)
+ grub_free (argv[i]);
+ grub_free (argv);
+ argv = 0;
+ }
+
+ return argv;
}
/* Execute a single command line. */
@@ -85,7 +182,6 @@
grub_script_execute_cmdline (struct grub_script_cmd *cmd)
{
struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd;
- struct grub_script_arglist *arglist;
char **args = 0;
int i = 0;
grub_command_t grubcmd;
@@ -96,7 +192,11 @@
char *cmdname;
/* Lookup the command. */
- cmdname = grub_script_execute_argument_to_string (cmdline->arglist->arg);
+ args = grub_script_execute_arglist_to_argv (cmdline->arglist);
+ if (!args)
+ return grub_errno;
+
+ cmdname = args[0];
grubcmd = grub_command_find (cmdname);
if (! grubcmd)
{
@@ -129,27 +229,15 @@
return 0;
}
}
- grub_free (cmdname);
-
- if (cmdline->arglist->next)
- {
- argcount = cmdline->arglist->argcount - 1;
-
- /* Create argv from the arguments. */
- args = grub_malloc (sizeof (char *) * argcount);
- for (arglist = cmdline->arglist->next; arglist; arglist = arglist->next)
- {
- char *str;
- str = grub_script_execute_argument_to_string (arglist->arg);
- args[i++] = str;
- }
- }
+
+ /* Count argv size. */
+ for (argcount = 0; args[argcount]; argcount++);
/* Execute the GRUB command or function. */
if (grubcmd)
- ret = (grubcmd->func) (grubcmd, argcount, args);
+ ret = (grubcmd->func) (grubcmd, argcount - 1, args + 1);
else
- ret = grub_script_function_call (func, argcount, args);
+ ret = grub_script_function_call (func, argcount - 1, args + 1);
/* Free arguments. */
for (i = 0; i < argcount; i++)
@@ -202,7 +290,6 @@
grub_script_execute_menuentry (struct grub_script_cmd *cmd)
{
struct grub_script_cmd_menuentry *cmd_menuentry;
- struct grub_script_arglist *arglist;
char **args = 0;
int argcount = 0;
int i = 0;
@@ -211,22 +298,11 @@
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;
- }
+ args = grub_script_execute_arglist_to_argv (cmd_menuentry->arglist);
+ if (!args)
+ return grub_errno;
+
+ for (argcount = 0; args[argcount]; argcount++);
}
grub_normal_add_menu_entry (argcount, (const char **) args,
=== modified file 'script/function.c'
--- script/function.c 2009-11-23 15:37:33 +0000
+++ script/function.c 2010-01-18 15:06:24 +0000
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2005,2007,2009 Free Software Foundation, Inc.
+ * Copyright (C) 2005,2007,2009,2010 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
@@ -34,7 +34,7 @@
if (! func)
return 0;
- func->name = grub_script_execute_argument_to_string (functionname_arg);
+ func->name = grub_strdup (functionname_arg->str);
if (! func->name)
{
grub_free (func);
=== modified file 'script/lexer.c'
--- script/lexer.c 2009-12-24 22:53:05 +0000
+++ script/lexer.c 2010-01-18 15:06:33 +0000
@@ -1,7 +1,7 @@
/* lexer.c - The scripting lexer. */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright (C) 2005,2006,2007,2008,2009,2010 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
@@ -23,42 +23,7 @@
#include
#include "grub_script.tab.h"
-
-static int
-check_varstate (grub_parser_state_t state)
-{
- return (state == GRUB_PARSER_STATE_VARNAME
- || state == GRUB_PARSER_STATE_VAR
- || state == GRUB_PARSER_STATE_QVAR
- || state == GRUB_PARSER_STATE_VARNAME2
- || state == GRUB_PARSER_STATE_QVARNAME
- || state == GRUB_PARSER_STATE_QVARNAME2);
-}
-
-static int
-check_textstate (grub_parser_state_t state)
-{
- return (state == GRUB_PARSER_STATE_TEXT
- || state == GRUB_PARSER_STATE_ESC
- || state == GRUB_PARSER_STATE_QUOTE
- || state == GRUB_PARSER_STATE_DQUOTE);
-}
-
-struct grub_lexer_param *
-grub_script_lexer_init (char *script, grub_reader_getline_t getline)
-{
- struct grub_lexer_param *param;
-
- param = grub_zalloc (sizeof (*param));
- if (! param)
- return 0;
-
- param->state = GRUB_PARSER_STATE_TEXT;
- param->getline = getline;
- param->script = script;
-
- return param;
-}
+#include "grub_script.yy.h"
void
grub_script_lexer_ref (struct grub_lexer_param *state)
@@ -74,360 +39,302 @@
/* Start recording all characters passing through the lexer. */
void
-grub_script_lexer_record_start (struct grub_lexer_param *state)
+grub_script_lexer_record_start (struct grub_parser_param *parser)
{
- state->record = 1;
- state->recordlen = 100;
- state->recording = grub_malloc (state->recordlen);
- state->recordpos = 0;
+ struct grub_lexer_param *lexer = parser->lexerstate;
+
+ lexer->record = 1;
+ lexer->recordpos = 0;
+ if (lexer->recording) /* reuse last record */
+ return;
+
+ lexer->recordlen = GRUB_LEXER_RECORD_INCREMENT;
+ lexer->recording = grub_malloc (lexer->recordlen);
+
+ if (!lexer->recording)
+ {
+ grub_script_yyerror (parser, "out of memory");
+ lexer->record = 0;
+ lexer->recordlen = 0;
+ }
}
char *
-grub_script_lexer_record_stop (struct grub_lexer_param *state)
+grub_script_lexer_record_stop (struct grub_parser_param *parser)
{
- state->record = 0;
-
- /* Delete the last character, it is a `}'. */
- if (state->recordpos > 0)
- {
- if (state->recording[--state->recordpos] != '}')
- {
- grub_printf ("Internal error while parsing menu entry");
- for (;;); /* XXX */
- }
- state->recording[state->recordpos] = '\0';
- }
-
- return state->recording;
+ char *ptr;
+ char *result;
+ struct grub_lexer_param *lexer = parser->lexerstate;
+
+ auto char *compact (char *start, char *end);
+ char *compact (char *start, char *end)
+ {
+ /* Delete '{' and '}' characters and whitespaces. */
+ while (*start && grub_isspace (*start)) start++;
+ if (*start == '{') start++;
+ while (*start && grub_isspace (*start)) start++;
+
+ while (*end && grub_isspace (*end)) end--;
+ if (*end == '}') end--;
+ while (*end && grub_isspace (*end)) end--;
+ *end = '\0';
+
+ return start;
+ }
+
+ if (!lexer->record || !lexer->recording)
+ return 0;
+
+ /* XXX This is not necessary in BASH. */
+
+ ptr = compact (lexer->recording, lexer->recording + lexer->recordpos - 1);
+ lexer->record = 0;
+ lexer->recordpos = 0;
+
+ /* This memory would be freed by, grub_script_free. */
+ result = grub_script_malloc (parser, grub_strlen (ptr) + 1);
+ if (result)
+ grub_strcpy (result, ptr);
+
+ return result;
}
-/* When recording is enabled, record the character C as the next item
- in the character stream. */
-static void
-recordchar (struct grub_lexer_param *state, char c)
+
+/* Record STR if input recording is enabled. */
+void
+grub_script_lexer_record (struct grub_parser_param *parser, char *str)
{
- if (state->recordpos == state->recordlen)
+ int len;
+ struct grub_lexer_param *lexer = parser->lexerstate;
+
+ if (!lexer->record)
+ return;
+
+ len = grub_strlen (str);
+ if (lexer->recordpos + len >= lexer->recordlen - 1)
{
- char *old = state->recording;
- state->recordlen += 100;
- state->recording = grub_realloc (state->recording, state->recordlen);
- if (! state->recording)
+ char *old = lexer->recording;
+ lexer->recordlen += GRUB_LEXER_RECORD_INCREMENT;
+ lexer->recording = grub_realloc (lexer->recording, lexer->recordlen);
+ if (!lexer->recording)
{
grub_free (old);
- state->record = 0;
- }
- }
- state->recording[state->recordpos++] = c;
-}
-
-/* Fetch the next character for the lexer. */
-static void
-nextchar (struct grub_lexer_param *state)
-{
- if (state->record)
- recordchar (state, *state->script);
- state->script++;
-}
-
-int
-grub_script_yylex (union YYSTYPE *yylval, struct grub_parser_param *parsestate)
-{
- grub_parser_state_t newstate;
- char use;
- struct grub_lexer_param *state = parsestate->lexerstate;
- int firstrun = 1;
-
- yylval->arg = 0;
-
- if (state->tokenonhold)
- {
- int token = state->tokenonhold;
- state->tokenonhold = 0;
- return token;
- }
-
- for (;! state->done; firstrun = 0)
- {
- if (! state->script || ! *state->script)
- {
- /* Check if more tokens are requested by the parser. */
- if (((state->refs && ! parsestate->err)
- || state->state == GRUB_PARSER_STATE_ESC
- || state->state == GRUB_PARSER_STATE_QUOTE
- || state->state == GRUB_PARSER_STATE_DQUOTE)
- && state->getline)
- {
- int doexit = 0;
- if (state->state != GRUB_PARSER_STATE_ESC
- && state->state != GRUB_PARSER_STATE_QUOTE
- && state->state != GRUB_PARSER_STATE_DQUOTE
- && ! state->was_newline)
- {
- state->was_newline = 1;
- state->tokenonhold = '\n';
- break;
- }
- while (! state->script || ! *state->script)
- {
- grub_free (state->newscript);
- state->newscript = 0;
- state->getline (&state->newscript, 1);
- state->script = state->newscript;
- if (! state->script)
- {
- doexit = 1;
- break;
- }
- }
- if (doexit)
- break;
- grub_dprintf ("scripting", "token=`\\n'\n");
- recordchar (state, '\n');
- if (state->state == GRUB_PARSER_STATE_VARNAME)
- state->state = GRUB_PARSER_STATE_TEXT;
- if (state->state == GRUB_PARSER_STATE_QVARNAME)
- state->state = GRUB_PARSER_STATE_DQUOTE;
- if (state->state == GRUB_PARSER_STATE_DQUOTE
- || state->state == GRUB_PARSER_STATE_QUOTE)
- yylval->arg = grub_script_arg_add (parsestate, yylval->arg,
- GRUB_SCRIPT_ARG_TYPE_STR,
- "\n");
- }
- else
- {
- grub_free (state->newscript);
- state->newscript = 0;
- state->done = 1;
- grub_dprintf ("scripting", "token=`\\n'\n");
- state->tokenonhold = '\n';
- break;
- }
- }
- state->was_newline = 0;
-
- newstate = grub_parser_cmdline_state (state->state, *state->script, &use);
-
- /* Check if it is a text. */
- if (check_textstate (newstate))
- {
- char *buffer = NULL;
- int bufpos = 0;
- /* Buffer is initially large enough to hold most commands
- but extends automatically when needed. */
- int bufsize = 128;
-
- buffer = grub_malloc (bufsize);
-
- /* In case the string is not quoted, this can be a one char
- length symbol. */
- if (newstate == GRUB_PARSER_STATE_TEXT)
- {
- int doexit = 0;
- switch (*state->script)
- {
- case ' ':
- while (*state->script)
- {
- newstate = grub_parser_cmdline_state (state->state,
- *state->script, &use);
- if (! (state->state == GRUB_PARSER_STATE_TEXT
- && *state->script == ' '))
- {
- grub_dprintf ("scripting", "token=` '\n");
- if (! firstrun)
- doexit = 1;
- break;
- }
- state->state = newstate;
- nextchar (state);
- }
- grub_dprintf ("scripting", "token=` '\n");
- if (! firstrun)
- doexit = 1;
- break;
- case '{':
- case '}':
- case ';':
- case '\n':
- {
- char c;
- grub_dprintf ("scripting", "token=`%c'\n", *state->script);
- c = *state->script;
- nextchar (state);
- state->tokenonhold = c;
- doexit = 1;
- break;
- }
- }
- if (doexit)
- {
- grub_free (buffer);
- break;
- }
- }
-
- /* Read one token, possible quoted. */
- while (*state->script)
- {
- newstate = grub_parser_cmdline_state (state->state,
- *state->script, &use);
-
- /* Check if a variable name starts. */
- if (check_varstate (newstate))
- break;
-
- /* If the string is not quoted or escaped, stop processing
- when a special token was found. It will be recognized
- next time when this function is called. */
- if (newstate == GRUB_PARSER_STATE_TEXT
- && state->state != GRUB_PARSER_STATE_ESC
- && state->state != GRUB_PARSER_STATE_QUOTE
- && state->state != GRUB_PARSER_STATE_DQUOTE)
- {
- int breakout = 0;
-
- switch (use)
- {
- case ' ':
- case '{':
- case '}':
- case ';':
- case '\n':
- breakout = 1;
- }
- if (breakout)
- break;
- }
-
- if (use)
- {
- if (bufsize <= bufpos + 1)
- {
- bufsize <<= 1;
- buffer = grub_realloc (buffer, bufsize);
- }
- buffer[bufpos++] = use;
- }
-
- state->state = newstate;
- nextchar (state);
- }
-
- /* A string of text was read in. */
- if (bufsize <= bufpos + 1)
- {
- bufsize <<= 1;
- buffer = grub_realloc (buffer, bufsize);
- }
-
- buffer[bufpos++] = 0;
-
- grub_dprintf ("scripting", "token=`%s'\n", buffer);
- yylval->arg = grub_script_arg_add (parsestate, yylval->arg,
- GRUB_SCRIPT_ARG_TYPE_STR, buffer);
-
- grub_free (buffer);
- }
- else if (newstate == GRUB_PARSER_STATE_VAR
- || newstate == GRUB_PARSER_STATE_QVAR)
- {
- char *buffer = NULL;
- int bufpos = 0;
- /* Buffer is initially large enough to hold most commands
- but extends automatically when needed. */
- int bufsize = 128;
-
- buffer = grub_malloc (bufsize);
-
- /* This is a variable, read the variable name. */
- while (*state->script)
- {
- newstate = grub_parser_cmdline_state (state->state,
- *state->script, &use);
-
- /* Check if this character is not part of the variable name
- anymore. */
- if (! (check_varstate (newstate)))
- {
- if (state->state == GRUB_PARSER_STATE_VARNAME2
- || state->state == GRUB_PARSER_STATE_QVARNAME2)
- nextchar (state);
- state->state = newstate;
- break;
- }
-
- if (use)
- {
- if (bufsize <= bufpos + 1)
- {
- bufsize <<= 1;
- buffer = grub_realloc (buffer, bufsize);
- }
- buffer[bufpos++] = use;
- }
-
- nextchar (state);
- state->state = newstate;
- }
-
- if (bufsize <= bufpos + 1)
- {
- bufsize <<= 1;
- buffer = grub_realloc (buffer, bufsize);
- }
-
- buffer[bufpos++] = 0;
-
- state->state = newstate;
- yylval->arg = grub_script_arg_add (parsestate, yylval->arg,
- GRUB_SCRIPT_ARG_TYPE_VAR, buffer);
- grub_dprintf ("scripting", "vartoken=`%s'\n", buffer);
-
- grub_free (buffer);
+ lexer->record = 0;
+ grub_script_yyerror (parser, "out of memory");
+ return;
+ }
+ }
+ grub_strcpy (lexer->recording + lexer->recordpos, str);
+ lexer->recordpos += len;
+}
+
+/* Append '\n' to SRC, before '\0' */
+static char *
+append_newline (const char *src)
+{
+ char *line;
+ grub_size_t len;
+
+ len = grub_strlen (src);
+ line = grub_malloc (len + 1);
+ if (!line)
+ return 0;
+
+ grub_strcpy (line, src);
+
+ line[len] = '\n';
+ line[len + 1] = '\0';
+ return line;
+}
+
+/* Read next line of input if necessary, and set yyscanner buffers. */
+int
+grub_script_lexer_yywrap (struct grub_parser_param *parserstate)
+{
+ int len;
+ char *line;
+ char *line2;
+ YY_BUFFER_STATE buffer;
+ struct grub_lexer_param *lexerstate = parserstate->lexerstate;
+
+ if (!lexerstate->refs)
+ return 0;
+
+ if (!lexerstate->getline)
+ {
+ grub_script_yyerror (parserstate, "unexpected end of file");
+ return 0;
+ }
+
+ line = 0;
+ buffer = 0;
+ lexerstate->getline (&line, 1);
+ if (!line)
+ {
+ grub_script_yyerror (parserstate, "input error"); /* XXX this could be for ^C case? */
+ return 0;
+ }
+
+ len = grub_strlen (line);
+ if (line[len - 1] == '\n')
+ {
+ buffer = yy_scan_string (line, lexerstate->yyscanner);
+ }
+ else
+ {
+ line2 = append_newline (line);
+ if (line2)
+ {
+ buffer = yy_scan_string (line2, lexerstate->yyscanner);
+ grub_free (line2);
+ }
+ }
+
+ grub_free (line);
+ if (!buffer)
+ {
+ grub_script_yyerror (parserstate, "out of memory");
+ return 0;
+ }
+
+ return 1;
+}
+
+struct grub_lexer_param *
+grub_script_lexer_init (struct grub_parser_param *parser, char *script,
+ grub_reader_getline_t getline)
+{
+ int len;
+ char *script2;
+ YY_BUFFER_STATE buffer;
+ struct grub_lexer_param *lexerstate;
+
+ lexerstate = grub_zalloc (sizeof (*lexerstate));
+ if (!lexerstate)
+ return 0;
+
+ lexerstate->text = grub_malloc (GRUB_LEXER_TOKEN_MAX);
+ if (!lexerstate->text)
+ {
+ grub_free (lexerstate);
+ return 0;
+ }
+
+ lexerstate->getline = getline; /* rest are all zeros already */
+ if (yylex_init (&lexerstate->yyscanner))
+ {
+ grub_free (lexerstate->text);
+ grub_free (lexerstate);
+ return 0;
+ }
+
+ buffer = 0;
+ script = script ? : "\n";
+ len = grub_strlen (script);
+
+ if (script[len - 1] == '\n')
+ {
+ buffer = yy_scan_string (script, lexerstate->yyscanner);
+ }
+ else
+ {
+ script2 = append_newline (script);
+ if (script2)
+ {
+ buffer = yy_scan_string (script2, lexerstate->yyscanner);
+ grub_free (script2);
+ }
+ }
+
+ if (!buffer)
+ {
+ yylex_destroy (lexerstate->yyscanner);
+ grub_free (lexerstate->yyscanner);
+
+ grub_free (lexerstate->text);
+ grub_free (lexerstate);
+ return 0;
+ }
+ yyset_extra (parser, lexerstate->yyscanner);
+
+ return lexerstate;
+}
+
+void
+grub_script_lexer_fini (struct grub_lexer_param *lexerstate)
+{
+ if (!lexerstate)
+ return;
+
+ yylex_destroy (lexerstate->yyscanner);
+
+ grub_free (lexerstate->recording);
+ grub_free (lexerstate->text);
+ grub_free (lexerstate);
+}
+
+int
+grub_script_yylex (union YYSTYPE *value,
+ struct grub_parser_param *parserstate)
+{
+ char *str;
+ int token;
+ grub_script_arg_type_t type;
+ struct grub_lexer_param *lexerstate = parserstate->lexerstate;
+
+ value->arg = 0;
+ if (parserstate->err)
+ return GRUB_PARSER_TOKEN_BAD;
+
+ if (lexerstate->eof)
+ return GRUB_PARSER_TOKEN_EOF;
+
+ /*
+ * Words with environment variables, like foo${bar}baz needs
+ * multiple tokens to be merged into a single grub_script_arg. We
+ * use two variables to achieve this: lexerstate->merge_start and
+ * lexerstate->merge_end
+ */
+
+ lexerstate->merge_start = 0;
+ lexerstate->merge_end = 0;
+ do
+ {
+ /* Empty lexerstate->text. */
+ lexerstate->size = 0;
+ lexerstate->text[0] = '\0';
+
+ token = yylex (value, lexerstate->yyscanner);
+ if (token == GRUB_PARSER_TOKEN_BAD)
+ break;
+
+ /* Merging feature uses lexerstate->text instead of yytext. */
+ if (lexerstate->merge_start)
+ {
+ lexerstate->text[lexerstate->size] = '\0';
+ str = lexerstate->text;
+ type = lexerstate->type;
}
else
{
- /* There is either text or a variable name. In the case you
- arrive here there is a serious problem with the lexer. */
- grub_error (GRUB_ERR_BAD_ARGUMENT, "internal error");
- return 0;
+ str = yyget_text (lexerstate->yyscanner);
+ type = GRUB_SCRIPT_ARG_TYPE_TEXT;
}
- }
-
- if (yylval->arg == 0)
- {
- int token = state->tokenonhold;
- state->tokenonhold = 0;
- return token;
- }
-
- if (yylval->arg->next == 0 && yylval->arg->type == GRUB_SCRIPT_ARG_TYPE_STR)
- {
- /* Detect some special tokens. */
- if (! grub_strcmp (yylval->arg->str, "while"))
- return GRUB_PARSER_TOKEN_WHILE;
- else if (! grub_strcmp (yylval->arg->str, "if"))
- return GRUB_PARSER_TOKEN_IF;
- else if (! grub_strcmp (yylval->arg->str, "function"))
- return GRUB_PARSER_TOKEN_FUNCTION;
- else if (! grub_strcmp (yylval->arg->str, "menuentry"))
- return GRUB_PARSER_TOKEN_MENUENTRY;
- else if (! grub_strcmp (yylval->arg->str, "@"))
- return GRUB_PARSER_TOKEN_MENUENTRY;
- else if (! grub_strcmp (yylval->arg->str, "else"))
- return GRUB_PARSER_TOKEN_ELSE;
- else if (! grub_strcmp (yylval->arg->str, "then"))
- return GRUB_PARSER_TOKEN_THEN;
- else if (! grub_strcmp (yylval->arg->str, "fi"))
- return GRUB_PARSER_TOKEN_FI;
- }
-
- return GRUB_PARSER_TOKEN_ARG;
+ /* grub_printf ("tok %u, txt [%s] size %u\n", token, str, lexerstate->size); */
+
+ value->arg = grub_script_arg_add (parserstate, value->arg, type, str);
+ }
+ while (lexerstate->merge_start && !lexerstate->merge_end);
+
+ if (!value->arg || parserstate->err)
+ return GRUB_PARSER_TOKEN_BAD;
+
+ return token;
}
void
-grub_script_yyerror (struct grub_parser_param *lex __attribute__ ((unused)),
- char const *err)
+grub_script_yyerror (struct grub_parser_param *state, char const *err)
{
grub_printf ("%s\n", err);
+ state->err++;
}
=== modified file 'script/parser.y'
--- script/parser.y 2009-11-23 15:37:33 +0000
+++ script/parser.y 2010-01-18 15:06:50 +0000
@@ -1,7 +1,7 @@
/* parser.y - The scripting parser. */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright (C) 2005,2006,2007,2008,2009,2010 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
@@ -21,10 +21,10 @@
#include
#include
-#define YYFREE grub_free
-#define YYMALLOC grub_malloc
+#define YYFREE grub_free
+#define YYMALLOC grub_malloc
#define YYLTYPE_IS_TRIVIAL 0
-#define YYENABLE_NLS 0
+#define YYENABLE_NLS 0
%}
@@ -35,163 +35,221 @@
char *string;
}
-%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_ARG
-%type script_init script grubcmd command commands commandblock menuentry if
-%type arguments;
-%type GRUB_PARSER_TOKEN_ARG;
+%token GRUB_PARSER_TOKEN_BAD
+%token GRUB_PARSER_TOKEN_EOF 0 "end-of-input"
+
+%token GRUB_PARSER_TOKEN_NEWLINE "\n"
+%token GRUB_PARSER_TOKEN_AND "&&"
+%token GRUB_PARSER_TOKEN_OR "||"
+%token GRUB_PARSER_TOKEN_SEMI2 ";;"
+%token GRUB_PARSER_TOKEN_PIPE "|"
+%token GRUB_PARSER_TOKEN_AMP "&"
+%token GRUB_PARSER_TOKEN_SEMI ";"
+%token GRUB_PARSER_TOKEN_LPAR "("
+%token GRUB_PARSER_TOKEN_RPAR ")"
+%token GRUB_PARSER_TOKEN_LBR "{"
+%token GRUB_PARSER_TOKEN_RBR "}"
+%token GRUB_PARSER_TOKEN_NOT "!"
+%token GRUB_PARSER_TOKEN_LSQBR2 "["
+%token GRUB_PARSER_TOKEN_RSQBR2 "]"
+%token GRUB_PARSER_TOKEN_LT "<"
+%token GRUB_PARSER_TOKEN_GT ">"
+
+%token GRUB_PARSER_TOKEN_CASE "case"
+%token GRUB_PARSER_TOKEN_DO "do"
+%token GRUB_PARSER_TOKEN_DONE "done"
+%token GRUB_PARSER_TOKEN_ELIF "elif"
+%token GRUB_PARSER_TOKEN_ELSE "else"
+%token GRUB_PARSER_TOKEN_ESAC "esac"
+%token GRUB_PARSER_TOKEN_FI "fi"
+%token GRUB_PARSER_TOKEN_FOR "for"
+%token GRUB_PARSER_TOKEN_IF "if"
+%token GRUB_PARSER_TOKEN_IN "in"
+%token GRUB_PARSER_TOKEN_SELECT "select"
+%token GRUB_PARSER_TOKEN_THEN "then"
+%token GRUB_PARSER_TOKEN_UNTIL "until"
+%token GRUB_PARSER_TOKEN_WHILE "while"
+%token GRUB_PARSER_TOKEN_TIME "time"
+%token GRUB_PARSER_TOKEN_FUNCTION "function"
+%token GRUB_PARSER_TOKEN_MENUENTRY "menuentry"
+%token GRUB_PARSER_TOKEN_NAME "name"
+%token GRUB_PARSER_TOKEN_WORD "word"
+
+%type word argument arguments0 arguments1
+%type script_init script grubcmd ifcmd command
+%type commands1 menuentry statement
%pure-parser
-%lex-param { struct grub_parser_param *state };
+%error-verbose
+
+%lex-param { struct grub_parser_param *state };
%parse-param { struct grub_parser_param *state };
+%start script_init
+
%%
/* It should be possible to do this in a clean way... */
-script_init: { state->err = 0; } script
- {
- state->parsed = $2;
- }
-;
-
-script: { $$ = 0; }
- | '\n' { $$ = 0; }
- | commands { $$ = $1; }
- | function '\n' { $$ = 0; }
- | menuentry '\n' { $$ = $1; }
- | error
- {
- $$ = 0;
- yyerror (state, "Incorrect command");
- state->err = 1;
- yyerrok;
- }
-;
-
-delimiter: '\n'
- | ';'
- | delimiter '\n'
-;
-
-newlines: /* Empty */
- | newlines '\n'
-;
-
-
-
-arguments: GRUB_PARSER_TOKEN_ARG
- {
- $$ = grub_script_add_arglist (state, 0, $1);
- }
- | arguments GRUB_PARSER_TOKEN_ARG
- {
- $$ = grub_script_add_arglist (state, $1, $2);
- }
-;
-
-grubcmd: arguments
- {
- $$ = grub_script_create_cmdline (state, $1);
- }
+script_init: { state->err = 0; } script { state->parsed = $2; state->err = 0; }
+;
+
+script: /* Empty */
+ {
+ $$ = 0;
+ }
+ | "\n" script
+ {
+ $$ = 0;
+ }
+ | statement delimiter script
+ {
+ struct grub_script_cmdblock *cmd;
+ cmd = (struct grub_script_cmdblock *) $3;
+ $$ = grub_script_add_cmd (state, cmd, $1);
+ }
+ | error
+ {
+ $$ = 0;
+ yyerror (state, "Incorrect command");
+ yyerrok;
+ }
+;
+
+newlines0: /* Empty */ | newlines1 ;
+newlines1: newlines0 "\n" ;
+
+delimiter: ";"
+ | "\n"
+;
+delimiters0: /* Empty */ | delimiters1 ;
+delimiters1: delimiter
+ | delimiters1 "\n"
+;
+
+word: "name" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "word" { $$ = grub_script_add_arglist (state, 0, $1); }
+;
+
+statement: command { $$ = $1; }
+ | function { $$ = 0; }
+ | menuentry { $$ = $1; }
+
+argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "do" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "done" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "elif" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "else" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "esac" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "fi" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "for" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "if" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "in" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "select" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "then" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "until" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "while" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "function" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | "menuentry" { $$ = grub_script_add_arglist (state, 0, $1); }
+ | word { $$ = $1; }
+;
+
+arguments0: /* Empty */ { $$ = 0; }
+ | arguments1 { $$ = $1; }
+;
+arguments1: argument arguments0
+ {
+ if ($1 && $2)
+ {
+ $1->next = $2;
+ $1->argcount += $2->argcount;
+ $2->argcount = 0;
+ }
+ $$ = $1;
+ }
+;
+
+grubcmd: word arguments0
+ {
+ if ($1 && $2) {
+ $1->next = $2;
+ $1->argcount += $2->argcount;
+ $2->argcount = 0;
+ }
+ $$ = grub_script_create_cmdline (state, $1);
+ }
;
/* A single command. */
-command: grubcmd delimiter { $$ = $1; }
- | if delimiter { $$ = $1; }
- | commandblock delimiter { $$ = $1; }
-;
-
-/* A block of commands. */
-commands: command
- {
- $$ = grub_script_add_cmd (state, 0, $1);
- }
- | command commands
- {
- struct grub_script_cmdblock *cmd;
- cmd = (struct grub_script_cmdblock *) $2;
- $$ = grub_script_add_cmd (state, cmd, $1);
- }
-;
-
-/* A function. Carefully save the memory that is allocated. Don't
- change any stuff because it might seem like a fun thing to do!
- Special care was take to make sure the mid-rule actions are
- executed on the right moment. So the `commands' rule should be
- recognized after executing the `grub_script_mem_record; and before
- `grub_script_mem_record_stop'. */
-function: "function" GRUB_PARSER_TOKEN_ARG
- {
- grub_script_lexer_ref (state->lexerstate);
- } newlines '{'
- {
- /* The first part of the function was recognized.
- Now start recording the memory usage to store
- this function. */
- state->func_mem = grub_script_mem_record (state);
- } newlines commands '}'
- {
- struct grub_script *script;
-
- /* All the memory usage for parsing this function
- was recorded. */
- state->func_mem = grub_script_mem_record_stop (state,
- state->func_mem);
- script = grub_script_create ($8, state->func_mem);
- if (script)
- grub_script_function_create ($2, script);
- grub_script_lexer_deref (state->lexerstate);
- }
-;
-
-/* Carefully designed, together with `menuentry' so everything happens
- just in the expected order. */
-commandblock: '{'
- {
- grub_script_lexer_ref (state->lexerstate);
- }
- newlines commands '}'
- {
- grub_script_lexer_deref (state->lexerstate);
- $$ = $4;
- }
-;
-
-/* A menu entry. Carefully save the memory that is allocated. */
-menuentry: "menuentry"
- {
- grub_script_lexer_ref (state->lexerstate);
- } arguments newlines '{'
- {
- grub_script_lexer_record_start (state->lexerstate);
- } newlines commands '}'
- {
- char *menu_entry;
- menu_entry = grub_script_lexer_record_stop (state->lexerstate);
- grub_script_lexer_deref (state->lexerstate);
- $$ = grub_script_create_cmdmenu (state, $3, menu_entry, 0);
- }
-;
-
-/* 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 (state->lexerstate); }
-;
-
-/* The if statement. */
-if: if_statement commands "then" newlines commands "fi"
- {
- $$ = grub_script_create_cmdif (state, $2, $5, 0);
- grub_script_lexer_deref (state->lexerstate);
- }
- | if_statement commands "then" newlines commands "else" newlines commands "fi"
- {
- $$ = grub_script_create_cmdif (state, $2, $5, $8);
- grub_script_lexer_deref (state->lexerstate);
- }
+command: grubcmd { $$ = $1; }
+ | ifcmd { $$ = $1; }
+;
+
+/* A list of commands. */
+commands1: newlines0 command
+ {
+ $$ = grub_script_add_cmd (state, 0, $2);
+ }
+ | commands1 delimiters1 command
+ {
+ struct grub_script_cmd *cmd;
+ struct grub_script_cmdblock *cmdblock;
+
+ if ($1)
+ {
+ cmdblock = (struct grub_script_cmdblock *) $1;
+ cmd = cmdblock->cmdlist;
+ while (cmd->next)
+ cmd = cmd->next;
+ cmd->next = $3;
+ }
+ $$ = $1;
+ }
+;
+
+function: "function" "name"
+ {
+ grub_script_lexer_ref (state->lexerstate);
+ state->func_mem = grub_script_mem_record (state);
+ }
+ delimiters0 "{" commands1 delimiters1 "}"
+ {
+ struct grub_script *script;
+ state->func_mem = grub_script_mem_record_stop (state,
+ state->func_mem);
+ script = grub_script_create ($6, state->func_mem);
+ if (script)
+ grub_script_function_create ($2, script);
+
+ grub_script_lexer_deref (state->lexerstate);
+ }
+;
+
+menuentry: "menuentry"
+ {
+ grub_script_lexer_ref (state->lexerstate);
+ }
+ arguments1
+ {
+ grub_script_lexer_record_start (state);
+ }
+ delimiters0 "{" commands1 delimiters1 "}"
+ {
+ char *menu_entry;
+ menu_entry = grub_script_lexer_record_stop (state);
+ grub_script_lexer_deref (state->lexerstate);
+ $$ = grub_script_create_cmdmenu (state, $3, menu_entry, 0);
+ }
+;
+
+if: "if" { grub_script_lexer_ref (state->lexerstate); }
+;
+ifcmd: if commands1 delimiters1 "then" commands1 delimiters1 "fi"
+ {
+ $$ = grub_script_create_cmdif (state, $2, $5, 0);
+ grub_script_lexer_deref (state->lexerstate);
+ }
+ | if commands1 delimiters1 "then" commands1 delimiters1 "else" commands1 delimiters1 "fi"
+ {
+ $$ = grub_script_create_cmdif (state, $2, $5, $8);
+ grub_script_lexer_deref (state->lexerstate);
+ }
;
=== modified file 'script/script.c'
--- script/script.c 2009-11-23 15:37:33 +0000
+++ script/script.c 2010-01-18 15:06:59 +0000
@@ -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,2009 Free Software Foundation, Inc.
+ * Copyright (C) 2005,2006,2007,2009,2010 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
@@ -24,12 +24,10 @@
/* It is not possible to deallocate the memory when a syntax error was
found. Because of that it is required to keep track of all memory
- allocations. The memory is freed in case of an error, or
- assigned to the parsed script when parsing was successful. */
-
-/* XXX */
-
-/* In case of the normal malloc, some additional bytes are allocated
+ allocations. The memory is freed in case of an error, or assigned
+ to the parsed script when parsing was successful.
+
+ In case of the normal malloc, some additional bytes are allocated
for this datastructure. All reserved memory is stored in a linked
list so it can be easily freed. The original memory can be found
from &mem. */
@@ -46,6 +44,8 @@
struct grub_script_mem *mem;
mem = (struct grub_script_mem *) grub_malloc (size + sizeof (*mem)
- sizeof (char));
+ if (!mem)
+ return 0;
grub_dprintf ("scripting", "malloc %p\n", mem);
mem->next = state->memused;
@@ -94,32 +94,40 @@
void
grub_script_free (struct grub_script *script)
{
- if (! script)
+ if (!script)
return;
grub_script_mem_free (script->mem);
grub_free (script);
}
-
+
/* Extend the argument arg with a variable or string of text. If ARG
is zero a new list is created. */
struct grub_script_arg *
-grub_script_arg_add (struct grub_parser_param *state, struct grub_script_arg *arg,
- grub_script_arg_type_t type, char *str)
+grub_script_arg_add (struct grub_parser_param *state,
+ struct grub_script_arg *arg, grub_script_arg_type_t type,
+ char *str)
{
struct grub_script_arg *argpart;
struct grub_script_arg *ll;
int len;
- argpart = (struct grub_script_arg *) grub_script_malloc (state, sizeof (*arg));
+ argpart =
+ (struct grub_script_arg *) grub_script_malloc (state, sizeof (*arg));
+ if (!argpart)
+ return arg;
+
argpart->type = type;
len = grub_strlen (str) + 1;
argpart->str = grub_script_malloc (state, len);
+ if (!argpart->str)
+ return arg; /* argpart is freed later, during grub_script_free. */
+
grub_memcpy (argpart->str, str, len);
argpart->next = 0;
- if (! arg)
+ if (!arg)
return argpart;
for (ll = arg; ll->next; ll = ll->next);
@@ -132,19 +140,24 @@
is zero, a new list will be created. */
struct grub_script_arglist *
grub_script_add_arglist (struct grub_parser_param *state,
- struct grub_script_arglist *list, struct grub_script_arg *arg)
+ struct grub_script_arglist *list,
+ struct grub_script_arg *arg)
{
struct grub_script_arglist *link;
struct grub_script_arglist *ll;
grub_dprintf ("scripting", "arglist\n");
- link = (struct grub_script_arglist *) grub_script_malloc (state, sizeof (*link));
+ link =
+ (struct grub_script_arglist *) grub_script_malloc (state, sizeof (*link));
+ if (!link)
+ return list;
+
link->next = 0;
link->arg = arg;
link->argcount = 0;
- if (! list)
+ if (!list)
{
link->argcount++;
return link;
@@ -171,6 +184,9 @@
grub_dprintf ("scripting", "cmdline\n");
cmd = grub_script_malloc (state, sizeof (*cmd));
+ if (!cmd)
+ return 0;
+
cmd->cmd.exec = grub_script_execute_cmdline;
cmd->cmd.next = 0;
cmd->arglist = arglist;
@@ -193,6 +209,9 @@
grub_dprintf ("scripting", "cmdif\n");
cmd = grub_script_malloc (state, sizeof (*cmd));
+ if (!cmd)
+ return 0;
+
cmd->cmd.exec = grub_script_execute_cmdif;
cmd->cmd.next = 0;
cmd->exec_to_evaluate = exec_to_evaluate;
@@ -209,30 +228,16 @@
struct grub_script_cmd *
grub_script_create_cmdmenu (struct grub_parser_param *state,
struct grub_script_arglist *arglist,
- char *sourcecode,
- int options)
+ char *sourcecode, int options)
{
struct grub_script_cmd_menuentry *cmd;
- int i;
-
- /* Skip leading newlines to make the sourcecode better readable when
- using the editor. */
- while (*sourcecode == '\n')
- sourcecode++;
-
- /* 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 (state, sizeof (*cmd));
+ if (!cmd)
+ return 0;
+
cmd->cmd.exec = grub_script_execute_menuentry;
cmd->cmd.next = 0;
- /* XXX: Check if this memory is properly freed. */
cmd->sourcecode = sourcecode;
cmd->arglist = arglist;
cmd->options = options;
@@ -250,13 +255,15 @@
{
grub_dprintf ("scripting", "cmdblock\n");
- if (! cmd)
+ if (!cmd)
return (struct grub_script_cmd *) cmdblock;
- if (! cmdblock)
+ if (!cmdblock)
{
- cmdblock = (struct grub_script_cmdblock *) grub_script_malloc (state,
- sizeof (*cmdblock));
+ cmdblock = grub_script_malloc (state, sizeof (*cmdblock));
+ if (!cmdblock)
+ return 0;
+
cmdblock->cmd.exec = grub_script_execute_cmdblock;
cmdblock->cmd.next = 0;
cmdblock->cmdlist = cmd;
@@ -270,16 +277,16 @@
return (struct grub_script_cmd *) cmdblock;
}
-
+
struct grub_script *
grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem)
{
struct grub_script *parsed;
parsed = grub_malloc (sizeof (*parsed));
- if (! parsed)
+ if (!parsed)
{
grub_script_mem_free (mem);
grub_free (cmd);
@@ -304,16 +311,16 @@
struct grub_parser_param *parsestate;
parsed = grub_malloc (sizeof (*parsed));
- if (! parsed)
+ if (!parsed)
return 0;
parsestate = grub_zalloc (sizeof (*parsestate));
- if (! parsestate)
+ if (!parsestate)
return 0;
/* Initialize the lexer. */
- lexstate = grub_script_lexer_init (script, getline);
- if (! lexstate)
+ lexstate = grub_script_lexer_init (parsestate, script, getline);
+ if (!lexstate)
{
grub_free (parsed);
grub_free (parsestate);
@@ -330,7 +337,7 @@
struct grub_script_mem *memfree;
memfree = grub_script_mem_record_stop (parsestate, membackup);
grub_script_mem_free (memfree);
- grub_free (lexstate);
+ grub_script_lexer_fini (lexstate);
grub_free (parsestate);
return 0;
}
@@ -338,7 +345,7 @@
parsed->mem = grub_script_mem_record_stop (parsestate, membackup);
parsed->cmd = parsestate->parsed;
- grub_free (lexstate);
+ grub_script_lexer_fini (lexstate);
grub_free (parsestate);
return parsed;
=== added file 'script/yylex.l'
--- script/yylex.l 1970-01-01 00:00:00 +0000
+++ script/yylex.l 2010-01-18 15:08:19 +0000
@@ -0,0 +1,331 @@
+%{
+/* yylex.l The scripting lexer. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009,2010 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 .
+ */
+
+#include
+#include
+#include
+#include
+#include "grub_script.tab.h"
+
+#define yyfree grub_lexer_yyfree
+#define yyalloc grub_lexer_yyalloc
+#define yyrealloc grub_lexer_yyrealloc
+
+/*
+ * As we don't have access to yyscanner, we cannot do much except to
+ * print the fatal error.
+ */
+#define YY_FATAL_ERROR(msg) \
+ do { \
+ grub_printf ("fatal error: %s\n", msg); \
+ } while (0)
+
+#define PUSH(c) \
+ do { \
+ if (yyextra->lexerstate->size >= GRUB_LEXER_TOKEN_MAX - 1) \
+ grub_script_yyerror (yyextra, "token too long"); \
+ else \
+ yyextra->lexerstate->text[yyextra->lexerstate->size++] = c; \
+ } while (0)
+
+#define COPY(str) \
+ do { \
+ char *ptr = str; \
+ while (*ptr && ! yyextra->err) \
+ { \
+ PUSH (*ptr); \
+ ptr++; \
+ } \
+ } while (0)
+
+#define RECORD \
+ do { \
+ grub_script_lexer_record (yyextra, yytext); \
+ } while (0)
+
+#define ARG(t) \
+ do { \
+ yyextra->lexerstate->type = t; \
+ return GRUB_PARSER_TOKEN_WORD; \
+ } while (0)
+
+/* We don't need YY_INPUT, as we rely on yy_scan_strings */
+#define YY_INPUT(buf,res,max) do { res = 0; } while (0)
+
+/* forward declarations */
+static void grub_lexer_yyfree (void *, yyscan_t yyscanner);
+static void* grub_lexer_yyalloc (yy_size_t, yyscan_t yyscanner);
+static void* grub_lexer_yyrealloc (void*, yy_size_t, yyscan_t yyscanner);
+
+%}
+
+%top{
+
+/*
+ * Some flex hacks for -nostdinc; XXX We need to fix these when libc
+ * support becomes availble in GRUB.
+ */
+
+#include
+
+typedef grub_size_t size_t;
+typedef grub_size_t yy_size_t;
+#define YY_TYPEDEF_YY_SIZE_T 1
+
+#define FILE void
+#define stdin 0
+#define stdout 0
+#define EOF 0
+
+#define errno grub_errno
+#define EINVAL GRUB_ERR_BAD_NUMBER
+#define ENOMEM GRUB_ERR_OUT_OF_MEMORY
+
+#define strlen grub_strlen
+#define memset grub_memset
+
+#define fprintf(...) 0
+#define exit(...)
+
+#pragma GCC diagnostic warning "-Wunused-variable"
+#pragma GCC diagnostic warning "-Wunused-function"
+#pragma GCC diagnostic warning "-Wunused-parameter"
+#pragma GCC diagnostic warning "-Wstrict-prototypes"
+#pragma GCC diagnostic warning "-Wmissing-prototypes"
+
+}
+
+%option ecs
+%option meta-ecs
+
+%option warn
+%option array
+%option stack
+%option reentrant
+%option bison-bridge
+%option never-interactive
+
+%option noyyfree noyyalloc noyyrealloc
+%option nounistd nostdinit nodefault noyylineno noyywrap
+
+/* Reduce lexer size, by not defining these. */
+%option noyy_top_state
+%option noinput nounput
+%option noyyget_in noyyset_in
+%option noyyget_out noyyset_out
+%option noyyget_debug noyyset_debug
+%option noyyget_lineno noyyset_lineno
+
+%option extra-type="struct grub_parser_param*"
+
+BLANK [ \t]
+COMMENT ^[ \t]*#.*$
+
+CHAR [^|&;()<> \t\n\'\"]
+DIGITS [[:digit:]]+
+NAME [[:alpha:]_][[:alnum:][:digit:]_]*
+
+ESC \\.
+VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|$\?|$\{\?\}
+DQSTR \"([^\"]|\\\")*\"
+SQSTR \'[^\']*\'
+WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+
+
+%x SPLIT
+%x DQUOTE
+%x SQUOTE
+%x VAR
+
+%%
+
+ /* White spaces */
+{BLANK}+ { RECORD; }
+{COMMENT} { RECORD; }
+
+ /* Special symbols */
+"\n" { RECORD; return GRUB_PARSER_TOKEN_NEWLINE; }
+"||" { RECORD; return GRUB_PARSER_TOKEN_OR; }
+"&&" { RECORD; return GRUB_PARSER_TOKEN_AND; }
+";;" { RECORD; return GRUB_PARSER_TOKEN_SEMI2; }
+"|" { RECORD; return GRUB_PARSER_TOKEN_PIPE; }
+"&" { RECORD; return GRUB_PARSER_TOKEN_AMP; }
+";" { RECORD; return GRUB_PARSER_TOKEN_SEMI; }
+"(" { RECORD; return GRUB_PARSER_TOKEN_LPAR; }
+")" { RECORD; return GRUB_PARSER_TOKEN_RPAR; }
+"<" { RECORD; return GRUB_PARSER_TOKEN_LT; }
+">" { RECORD; return GRUB_PARSER_TOKEN_GT; }
+
+ /* Reserved words */
+"!" { RECORD; return GRUB_PARSER_TOKEN_NOT; }
+"{" { RECORD; return GRUB_PARSER_TOKEN_LBR; }
+"}" { RECORD; return GRUB_PARSER_TOKEN_RBR; }
+"[[" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; }
+"]]" { RECORD; return GRUB_PARSER_TOKEN_LSQBR2; }
+"time" { RECORD; return GRUB_PARSER_TOKEN_TIME; }
+"case" { RECORD; return GRUB_PARSER_TOKEN_CASE; }
+"do" { RECORD; return GRUB_PARSER_TOKEN_DO; }
+"done" { RECORD; return GRUB_PARSER_TOKEN_DONE; }
+"elif" { RECORD; return GRUB_PARSER_TOKEN_ELIF; }
+"else" { RECORD; return GRUB_PARSER_TOKEN_ELSE; }
+"esac" { RECORD; return GRUB_PARSER_TOKEN_ESAC; }
+"fi" { RECORD; return GRUB_PARSER_TOKEN_FI; }
+"for" { RECORD; return GRUB_PARSER_TOKEN_FOR; }
+"if" { RECORD; return GRUB_PARSER_TOKEN_IF; }
+"in" { RECORD; return GRUB_PARSER_TOKEN_IN; }
+"select" { RECORD; return GRUB_PARSER_TOKEN_SELECT; }
+"then" { RECORD; return GRUB_PARSER_TOKEN_THEN; }
+"until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; }
+"while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; }
+"function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; }
+"menuentry" { RECORD; return GRUB_PARSER_TOKEN_MENUENTRY; }
+
+{NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; }
+{WORD} {
+ RECORD;
+ /* resplit yytext */
+ yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
+ if (yy_scan_string (yytext, yyscanner))
+ {
+ yyextra->lexerstate->merge_start = 1;
+ yy_push_state (SPLIT, yyscanner);
+ }
+ else
+ {
+ grub_script_yyerror (yyextra, "out of memory");
+ yypop_buffer_state (yyscanner);
+ return GRUB_PARSER_TOKEN_WORD;
+ }
+ }
+
+.|\n {
+ grub_script_yyerror (yyextra, "unrecognized token");
+ return GRUB_PARSER_TOKEN_BAD;
+ }
+
+
+ /* Split word into multiple args */
+
+{
+ \\. { PUSH (yytext[1]); }
+ \" {
+ yy_push_state (DQUOTE, yyscanner);
+ ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
+ }
+ \' {
+ yy_push_state (SQUOTE, yyscanner);
+ ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
+ }
+ \$ {
+ yy_push_state (VAR, yyscanner);
+ ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
+ }
+ {CHAR} { PUSH (yytext[0]); }
+ .|\n {
+ /* This cannot happen. */
+ grub_script_yyerror (yyextra, "internal error: unexpected characters in a word");
+ return GRUB_PARSER_TOKEN_BAD;
+ }
+
+ <> {
+ yy_pop_state (yyscanner);
+ yypop_buffer_state (yyscanner);
+ yyextra->lexerstate->merge_end = 1;
+ ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
+ }
+}
+
+{
+ \? |
+ {DIGITS} |
+ {NAME} {
+ COPY (yytext);
+ yy_pop_state (yyscanner);
+ if (YY_START == SPLIT)
+ ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
+ else
+ ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
+ }
+ \{\?\} |
+ \{{DIGITS}\} |
+ \{{NAME}\} {
+ yytext[yyleng - 1] = '\0';
+ COPY (yytext + 1);
+ yy_pop_state (yyscanner);
+ if (YY_START == SPLIT)
+ ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
+ else
+ ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
+ }
+ .|\n { return GRUB_PARSER_TOKEN_BAD; }
+}
+
+{
+ \' {
+ yy_pop_state (yyscanner);
+ ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
+ }
+ (.|\n) { PUSH (yytext[0]); }
+}
+
+{
+ \" {
+ yy_pop_state (yyscanner);
+ ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
+ }
+ \$ {
+ yy_push_state (VAR, yyscanner);
+ ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
+ }
+ \\\\ { PUSH ('\\'); }
+ \\\" { PUSH ('\"'); }
+ \\\n { /* ignore */ }
+ (.|\n) { PUSH (yytext[0]); }
+}
+
+<> {
+ yypop_buffer_state (yyscanner);
+ if (! grub_script_lexer_yywrap (yyextra))
+ {
+ yyextra->lexerstate->eof = 1;
+ return GRUB_PARSER_TOKEN_EOF;
+ }
+ }
+
+%%
+
+static void
+grub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused)))
+{
+ grub_free(ptr);
+}
+
+static void*
+grub_lexer_yyalloc (yy_size_t size, yyscan_t yyscanner __attribute__ ((unused)))
+{
+ return grub_malloc (size);
+}
+
+static void*
+grub_lexer_yyrealloc (void *ptr, yy_size_t size,
+ yyscan_t yyscanner __attribute__ ((unused)))
+{
+ return grub_realloc (ptr, size);
+}
+
=== added file 'tests/grub_script_echo1.in'
--- tests/grub_script_echo1.in 1970-01-01 00:00:00 +0000
+++ tests/grub_script_echo1.in 2010-01-18 15:09:05 +0000
@@ -0,0 +1,32 @@
+#! @builddir@/grub-shell-tester
+
+# Run GRUB script in a Qemu instance
+# Copyright (C) 2010 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 .
+
+foo=bar
+echo $foo ${foo}
+echo "$foo" "${foo}"
+echo '$foo' '${foo}'
+echo a$foob a${foo}b
+echo ab"cd"ef$foo'gh'ij${foo}kl\ mn\"op\'qr\$st\(uv\yz\)
+
+foo=c
+bar=h
+echo e"$foo"${bar}o
+e"$foo"${bar}o hello world
+
+foo=echo
+$foo 1234
=== added file 'tests/grub_script_echo_keywords.in'
--- tests/grub_script_echo_keywords.in 1970-01-01 00:00:00 +0000
+++ tests/grub_script_echo_keywords.in 2010-01-09 17:08:30 +0000
@@ -0,0 +1,3 @@
+#! @builddir@/grub-shell-tester
+
+echo if then else fi for do done
=== added file 'tests/grub_script_vars1.in'
--- tests/grub_script_vars1.in 1970-01-01 00:00:00 +0000
+++ tests/grub_script_vars1.in 2010-01-18 15:09:36 +0000
@@ -0,0 +1,34 @@
+#! @builddir@/grub-shell-tester
+
+# Run GRUB script in a Qemu instance
+# Copyright (C) 2010 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 .
+
+var=foo
+echo $var
+echo "$var"
+echo ${var}
+echo "${var}"
+
+echo $1 $2 $?
+
+foo=foo
+echo "" $foo
+
+echo $bar $foo
+
+bar=""
+echo $bar $foo
+
=== modified file 'tests/util/grub-shell-tester.in'
--- tests/util/grub-shell-tester.in 2010-01-12 03:30:55 +0000
+++ tests/util/grub-shell-tester.in 2010-01-18 15:12:12 +0000
@@ -1,7 +1,7 @@
#! /bin/bash -e
# Compares GRUB script output with BASH output.
-# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
+# Copyright (C) 2009,2010 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
=== modified file 'tests/util/grub-shell.in'
--- tests/util/grub-shell.in 2010-01-14 13:09:12 +0000
+++ tests/util/grub-shell.in 2010-01-18 15:12:00 +0000
@@ -1,7 +1,7 @@
#! /bin/bash -e
# Run GRUB script in a Qemu instance
-# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
+# Copyright (C) 2009,2010 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
=== modified file 'util/grub-script-check.c'
--- util/grub-script-check.c 2010-01-18 11:28:31 +0000
+++ util/grub-script-check.c 2010-01-18 12:54:49 +0000
@@ -1,7 +1,7 @@
/* grub-script-check.c - check grub script file for syntax errors */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
+ * Copyright (C) 2009,2010 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
@@ -82,16 +82,8 @@
}
grub_err_t
-grub_script_execute_menuentry (struct grub_script_cmd *cmd)
+grub_script_execute_menuentry (struct grub_script_cmd *cmd __attribute__ ((unused)))
{
- struct grub_script_cmd_menuentry *menu;
- menu = (struct grub_script_cmd_menuentry *)cmd;
-
- if (menu->sourcecode)
- {
- grub_free (menu->sourcecode);
- menu->sourcecode = 0;
- }
return 0;
}