2010-03-14 BVK Chaitanya <bvk.groups@gmail.com>
GRUB shell lexer and parser improvements. * 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.
This commit is contained in:
commit
0cdc2a095b
18 changed files with 1211 additions and 643 deletions
72
ChangeLog
72
ChangeLog
|
@ -1,3 +1,75 @@
|
|||
2010-03-14 BVK Chaitanya <bvk.groups@gmail.com>
|
||||
|
||||
GRUB shell lexer and parser improvements.
|
||||
|
||||
* 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.
|
||||
|
||||
2010-03-14 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Remove some redundancy in build system.
|
||||
|
|
|
@ -6,16 +6,15 @@ COMMON_CFLAGS += -nostdinc -isystem $(shell $(TARGET_CC) -print-file-name=includ
|
|||
util/grub-emu.c_DEPENDENCIES = grub_emu_init.h
|
||||
kernel_img_RELOCATABLE = yes
|
||||
pkglib_PROGRAMS = kernel.img
|
||||
kernel_img_SOURCES = kern/device.c kern/disk.c kern/dl.c kern/env.c \
|
||||
kern/err.c kern/list.c kern/handler.c \
|
||||
kern/command.c kern/corecmd.c kern/file.c \
|
||||
kern/fs.c kern/main.c kern/misc.c kern/parser.c \
|
||||
kern/partition.c kern/term.c \
|
||||
kernel_img_SOURCES = kern/device.c kern/disk.c kern/dl.c kern/env.c \
|
||||
kern/err.c kern/list.c kern/handler.c kern/command.c \
|
||||
kern/corecmd.c kern/file.c kern/fs.c kern/main.c kern/misc.c \
|
||||
kern/parser.c kern/partition.c kern/term.c \
|
||||
kern/rescue_reader.c kern/rescue_parser.c \
|
||||
\
|
||||
util/console.c util/grub-emu.c util/misc.c \
|
||||
util/hostdisk.c util/getroot.c util/time.c \
|
||||
\
|
||||
\
|
||||
util/console.c util/grub-emu.c util/misc.c util/hostdisk.c \
|
||||
util/getroot.c util/time.c \
|
||||
\
|
||||
grub_emu_init.c gnulib/progname.c util/hostfs.c disk/host.c
|
||||
kernel_img_CFLAGS = $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Wno-undef -I$(srcdir)/gnulib
|
||||
kernel_img_LDFLAGS = $(COMMON_LDFLAGS)
|
||||
|
|
|
@ -94,6 +94,13 @@ grub_mkrelpath_SOURCES = gnulib/progname.c util/grub-mkrelpath.c util/misc.c
|
|||
bin_UTILITIES += grub-bin2h
|
||||
grub_bin2h_SOURCES = gnulib/progname.c util/bin2h.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.*\(<stdio\.h>\|<string\.h>\|<errno\.h>\|<stdlib\.h>\|<unistd\.h>\)//g' grub_script.yy.h
|
||||
sed -i 's/^#include.*\(<stdio\.h>\|<string\.h>\|<errno\.h>\|<stdlib\.h>\|<unistd\.h>\)//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
|
||||
|
@ -101,7 +108,8 @@ grub_script_check_SOURCES = gnulib/progname.c gnulib/getdelim.c gnulib/getline.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
|
||||
|
||||
MOSTLYCLEANFILES += symlist.c kernel_syms.lst
|
||||
DEFSYMFILES += kernel_syms.lst
|
||||
|
@ -635,7 +643,7 @@ normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
|
|||
|
||||
# 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)
|
||||
|
||||
|
|
|
@ -37,12 +37,28 @@ example_scripted_test_SOURCES = tests/example_scripted_test.in
|
|||
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
|
||||
|
|
|
@ -170,6 +170,11 @@ if test "x$CMP" = x; then
|
|||
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])
|
||||
|
|
|
@ -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 @@ struct grub_script
|
|||
|
||||
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 @@ struct grub_script_cmd_menuentry
|
|||
/* 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 @@ struct grub_lexer_param
|
|||
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,31 @@ struct grub_lexer_param
|
|||
/* Size of RECORDING. */
|
||||
int recordlen;
|
||||
|
||||
/* The token that is already parsed but not yet returned. */
|
||||
int tokenonhold;
|
||||
/* End of file reached. */
|
||||
int eof;
|
||||
|
||||
/* Was the last token a newline? */
|
||||
int was_newline;
|
||||
/* Merge multiple word tokens. */
|
||||
int merge_start;
|
||||
int merge_end;
|
||||
|
||||
/* Part of a multi-part token. */
|
||||
char *text;
|
||||
unsigned used;
|
||||
unsigned size;
|
||||
|
||||
/* Type of text. */
|
||||
grub_script_arg_type_t type;
|
||||
|
||||
/* Flex scanner. */
|
||||
void *yyscanner;
|
||||
|
||||
/* Flex scanner buffer. */
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
#define GRUB_LEXER_INITIAL_TEXT_SIZE 32
|
||||
#define GRUB_LEXER_INITIAL_RECORD_SIZE 256
|
||||
|
||||
/* State of the parser as passes to the parser. */
|
||||
struct grub_parser_param
|
||||
{
|
||||
|
@ -223,12 +234,16 @@ void grub_script_free (struct grub_script *script);
|
|||
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 +299,7 @@ int grub_script_function_iterate (int (*iterate) (grub_script_function_t));
|
|||
int grub_script_function_call (grub_script_function_t func,
|
||||
int argc, char **args);
|
||||
|
||||
char *
|
||||
grub_script_execute_argument_to_string (struct grub_script_arg *arg);
|
||||
char **
|
||||
grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *count);
|
||||
|
||||
#endif /* ! GRUB_NORMAL_PARSER_HEADER */
|
||||
|
|
214
script/execute.c
214
script/execute.c
|
@ -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,149 @@ grub_script_execute_cmd (struct grub_script_cmd *cmd)
|
|||
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 ARG_ALLOCATION_UNIT (32 * sizeof (char))
|
||||
#define ARGV_ALLOCATION_UNIT (8 * sizeof (void*))
|
||||
|
||||
/* Expand arguments in ARGLIST into multiple arguments. */
|
||||
char **
|
||||
grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *count)
|
||||
{
|
||||
int size = 0;
|
||||
char *val;
|
||||
char *chararg;
|
||||
struct grub_script_arg *argi;
|
||||
int i;
|
||||
int oom;
|
||||
int argc;
|
||||
int empty;
|
||||
char *ptr;
|
||||
char **argv;
|
||||
char *value;
|
||||
struct grub_script_arg *arg;
|
||||
|
||||
/* First determine the size of the argument. */
|
||||
for (argi = arg; argi; argi = argi->next)
|
||||
auto void push (char *str);
|
||||
void push (char *str)
|
||||
{
|
||||
char **p;
|
||||
|
||||
if (oom)
|
||||
return;
|
||||
|
||||
p = grub_realloc (argv, ALIGN_UP (sizeof(char*) * (argc + 1), ARGV_ALLOCATION_UNIT));
|
||||
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], ALIGN_UP(old + len + 1, ARG_ALLOCATION_UNIT));
|
||||
|
||||
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)
|
||||
{
|
||||
if (argi->type == 1)
|
||||
empty = 1;
|
||||
arg = arglist->arg;
|
||||
while (arg)
|
||||
{
|
||||
val = grub_env_get (argi->str);
|
||||
if (val)
|
||||
size += grub_strlen (val);
|
||||
switch (arg->type)
|
||||
{
|
||||
case GRUB_SCRIPT_ARG_TYPE_VAR:
|
||||
value = grub_env_get (arg->str);
|
||||
while (value && *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;
|
||||
}
|
||||
else
|
||||
size += grub_strlen (argi->str);
|
||||
if (!empty)
|
||||
push (0);
|
||||
}
|
||||
|
||||
/* 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 (oom)
|
||||
{
|
||||
if (argi->type == 1)
|
||||
{
|
||||
val = grub_env_get (argi->str);
|
||||
if (val)
|
||||
grub_strcat (chararg, val);
|
||||
}
|
||||
else
|
||||
grub_strcat (chararg, argi->str);
|
||||
for (i = 0; i < argc; i++)
|
||||
grub_free (argv[i]);
|
||||
grub_free (argv);
|
||||
argv = 0;
|
||||
}
|
||||
|
||||
return chararg;
|
||||
if (argv)
|
||||
*count = argc - 1;
|
||||
|
||||
return argv;
|
||||
}
|
||||
|
||||
/* Execute a single command line. */
|
||||
|
@ -85,7 +185,6 @@ grub_err_t
|
|||
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 +195,11 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
|
|||
char *cmdname;
|
||||
|
||||
/* Lookup the command. */
|
||||
cmdname = grub_script_execute_argument_to_string (cmdline->arglist->arg);
|
||||
args = grub_script_execute_arglist_to_argv (cmdline->arglist, &argcount);
|
||||
if (!args)
|
||||
return grub_errno;
|
||||
|
||||
cmdname = args[0];
|
||||
grubcmd = grub_command_find (cmdname);
|
||||
if (! grubcmd)
|
||||
{
|
||||
|
@ -130,27 +233,12 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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++)
|
||||
|
@ -208,7 +296,6 @@ grub_err_t
|
|||
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;
|
||||
|
@ -217,22 +304,9 @@ grub_script_execute_menuentry (struct grub_script_cmd *cmd)
|
|||
|
||||
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, &argcount);
|
||||
if (!args)
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_normal_add_menu_entry (argcount, (const char **) args,
|
||||
|
|
|
@ -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 @@ grub_script_function_create (struct grub_script_arg *functionname_arg,
|
|||
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);
|
||||
|
|
615
script/lexer.c
615
script/lexer.c
|
@ -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 <grub/script_sh.h>
|
||||
|
||||
#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,308 @@ grub_script_lexer_deref (struct grub_lexer_param *state)
|
|||
|
||||
/* 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_INITIAL_RECORD_SIZE;
|
||||
lexer->recording = grub_malloc (lexer->recordlen);
|
||||
if (!lexer->recording)
|
||||
{
|
||||
grub_script_yyerror (parser, 0);
|
||||
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;
|
||||
char *ptr;
|
||||
char *result;
|
||||
struct grub_lexer_param *lexer = parser->lexerstate;
|
||||
|
||||
/* 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';
|
||||
}
|
||||
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++;
|
||||
|
||||
return state->recording;
|
||||
while (*end && grub_isspace (*end)) end--;
|
||||
if (*end == '}') end--;
|
||||
while (*end && grub_isspace (*end)) end--;
|
||||
end[1] = '\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)
|
||||
#define MAX(a,b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
/* 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;
|
||||
char *old;
|
||||
struct grub_lexer_param *lexer = parser->lexerstate;
|
||||
|
||||
if (!lexer->record)
|
||||
return;
|
||||
|
||||
len = grub_strlen (str);
|
||||
if (lexer->recordpos + len + 1 > lexer->recordlen)
|
||||
{
|
||||
char *old = state->recording;
|
||||
state->recordlen += 100;
|
||||
state->recording = grub_realloc (state->recording, state->recordlen);
|
||||
if (! state->recording)
|
||||
old = lexer->recording;
|
||||
lexer->recordlen = MAX (len, lexer->recordlen) * 2;
|
||||
lexer->recording = grub_realloc (lexer->recording, lexer->recordlen);
|
||||
if (!lexer->recording)
|
||||
{
|
||||
grub_free (old);
|
||||
state->record = 0;
|
||||
lexer->record = 0;
|
||||
lexer->recordpos = 0;
|
||||
lexer->recordlen /= 2;
|
||||
grub_script_yyerror (parser, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
state->recording[state->recordpos++] = c;
|
||||
grub_strcpy (lexer->recording + lexer->recordpos, str);
|
||||
lexer->recordpos += len;
|
||||
}
|
||||
|
||||
/* Fetch the next character for the lexer. */
|
||||
static void
|
||||
nextchar (struct grub_lexer_param *state)
|
||||
/* Append '\n' to SRC, before '\0' */
|
||||
static char *
|
||||
append_newline (const char *src)
|
||||
{
|
||||
if (state->record)
|
||||
recordchar (state, *state->script);
|
||||
state->script++;
|
||||
char *line;
|
||||
grub_size_t len;
|
||||
|
||||
len = grub_strlen (src);
|
||||
line = grub_malloc (len + 2);
|
||||
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_yylex (union YYSTYPE *yylval, struct grub_parser_param *parsestate)
|
||||
grub_script_lexer_yywrap (struct grub_parser_param *parserstate)
|
||||
{
|
||||
grub_parser_state_t newstate;
|
||||
char use;
|
||||
struct grub_lexer_param *state = parsestate->lexerstate;
|
||||
int firstrun = 1;
|
||||
int len;
|
||||
char *line;
|
||||
char *line2;
|
||||
YY_BUFFER_STATE buffer;
|
||||
struct grub_lexer_param *lexerstate = parserstate->lexerstate;
|
||||
|
||||
yylval->arg = 0;
|
||||
if (!lexerstate->refs)
|
||||
return 0;
|
||||
|
||||
if (state->tokenonhold)
|
||||
if (!lexerstate->getline)
|
||||
{
|
||||
int token = state->tokenonhold;
|
||||
state->tokenonhold = 0;
|
||||
return token;
|
||||
grub_script_yyerror (parserstate, "unexpected end of file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (;! state->done; firstrun = 0)
|
||||
line = 0;
|
||||
buffer = 0;
|
||||
lexerstate->getline (&line, 1);
|
||||
if (!line)
|
||||
{
|
||||
if (! state->script || ! *state->script)
|
||||
grub_script_yyerror (parserstate, 0); /* 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)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
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;
|
||||
buffer = yy_scan_string (line2, lexerstate->yyscanner);
|
||||
grub_free (line2);
|
||||
}
|
||||
}
|
||||
|
||||
if (yylval->arg == 0)
|
||||
grub_free (line);
|
||||
if (!buffer)
|
||||
{
|
||||
int token = state->tokenonhold;
|
||||
state->tokenonhold = 0;
|
||||
return token;
|
||||
grub_script_yyerror (parserstate, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (yylval->arg->next == 0 && yylval->arg->type == GRUB_SCRIPT_ARG_TYPE_STR)
|
||||
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->size = GRUB_LEXER_INITIAL_TEXT_SIZE;
|
||||
lexerstate->text = grub_malloc (lexerstate->size);
|
||||
if (!lexerstate->text)
|
||||
{
|
||||
/* 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;
|
||||
grub_free (lexerstate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return GRUB_PARSER_TOKEN_ARG;
|
||||
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_yyerror (struct grub_parser_param *lex __attribute__ ((unused)),
|
||||
char const *err)
|
||||
grub_script_lexer_fini (struct grub_lexer_param *lexerstate)
|
||||
{
|
||||
grub_printf ("%s\n", err);
|
||||
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->used = 1;
|
||||
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)
|
||||
{
|
||||
str = lexerstate->text;
|
||||
type = lexerstate->type;
|
||||
}
|
||||
else
|
||||
{
|
||||
str = yyget_text (lexerstate->yyscanner);
|
||||
type = GRUB_SCRIPT_ARG_TYPE_TEXT;
|
||||
}
|
||||
grub_dprintf("lexer", "token %u text [%s]\n", token, str);
|
||||
|
||||
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 *state, char const *err)
|
||||
{
|
||||
if (err)
|
||||
grub_error (GRUB_ERR_INVALID_COMMAND, err);
|
||||
|
||||
grub_print_error ();
|
||||
state->err++;
|
||||
}
|
||||
|
|
307
script/parser.y
307
script/parser.y
|
@ -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 <grub/script_sh.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
#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,204 @@
|
|||
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 <cmd> script_init script grubcmd command commands commandblock menuentry if
|
||||
%type <arglist> arguments;
|
||||
%type <arg> 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_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 <arg> GRUB_PARSER_TOKEN_CASE "case"
|
||||
%token <arg> GRUB_PARSER_TOKEN_DO "do"
|
||||
%token <arg> GRUB_PARSER_TOKEN_DONE "done"
|
||||
%token <arg> GRUB_PARSER_TOKEN_ELIF "elif"
|
||||
%token <arg> GRUB_PARSER_TOKEN_ELSE "else"
|
||||
%token <arg> GRUB_PARSER_TOKEN_ESAC "esac"
|
||||
%token <arg> GRUB_PARSER_TOKEN_FI "fi"
|
||||
%token <arg> GRUB_PARSER_TOKEN_FOR "for"
|
||||
%token <arg> GRUB_PARSER_TOKEN_IF "if"
|
||||
%token <arg> GRUB_PARSER_TOKEN_IN "in"
|
||||
%token <arg> GRUB_PARSER_TOKEN_SELECT "select"
|
||||
%token <arg> GRUB_PARSER_TOKEN_THEN "then"
|
||||
%token <arg> GRUB_PARSER_TOKEN_UNTIL "until"
|
||||
%token <arg> GRUB_PARSER_TOKEN_WHILE "while"
|
||||
%token <arg> GRUB_PARSER_TOKEN_TIME "time"
|
||||
%token <arg> GRUB_PARSER_TOKEN_FUNCTION "function"
|
||||
%token <arg> GRUB_PARSER_TOKEN_MENUENTRY "menuentry"
|
||||
%token <arg> GRUB_PARSER_TOKEN_NAME "name"
|
||||
%token <arg> GRUB_PARSER_TOKEN_WORD "word"
|
||||
|
||||
%type <arglist> word argument arguments0 arguments1
|
||||
%type <cmd> script_init script grubcmd ifcmd command
|
||||
%type <cmd> commands1 menuentry statement
|
||||
|
||||
%pure-parser
|
||||
%lex-param { struct grub_parser_param *state };
|
||||
%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_init: { state->err = 0; } script { state->parsed = $2; state->err = 0; }
|
||||
;
|
||||
|
||||
script: { $$ = 0; }
|
||||
| '\n' { $$ = 0; }
|
||||
| commands { $$ = $1; }
|
||||
| function '\n' { $$ = 0; }
|
||||
| menuentry '\n' { $$ = $1; }
|
||||
| error
|
||||
{
|
||||
$$ = 0;
|
||||
yyerror (state, "Incorrect command");
|
||||
state->err = 1;
|
||||
yyerrok;
|
||||
}
|
||||
script: newlines0
|
||||
{
|
||||
$$ = 0;
|
||||
}
|
||||
| script statement delimiter
|
||||
{
|
||||
struct grub_script_cmdblock *cmdblock;
|
||||
cmdblock = (struct grub_script_cmdblock *) $1;
|
||||
$$ = grub_script_add_cmd (state, cmdblock, $2);
|
||||
}
|
||||
| error
|
||||
{
|
||||
$$ = 0;
|
||||
yyerror (state, "Incorrect command");
|
||||
yyerrok;
|
||||
}
|
||||
;
|
||||
|
||||
delimiter: '\n'
|
||||
| ';'
|
||||
| delimiter '\n'
|
||||
newlines0: /* Empty */ | newlines1 ;
|
||||
newlines1: newlines0 "\n" ;
|
||||
|
||||
delimiter: ";"
|
||||
| "\n"
|
||||
;
|
||||
delimiters0: /* Empty */ | delimiters1 ;
|
||||
delimiters1: delimiter
|
||||
| delimiters1 "\n"
|
||||
;
|
||||
|
||||
newlines: /* Empty */
|
||||
| newlines '\n'
|
||||
word: GRUB_PARSER_TOKEN_NAME { $$ = grub_script_add_arglist (state, 0, $1); }
|
||||
| GRUB_PARSER_TOKEN_WORD { $$ = grub_script_add_arglist (state, 0, $1); }
|
||||
;
|
||||
|
||||
statement: command { $$ = $1; }
|
||||
| function { $$ = 0; }
|
||||
| menuentry { $$ = $1; }
|
||||
|
||||
|
||||
arguments: GRUB_PARSER_TOKEN_ARG
|
||||
{
|
||||
$$ = grub_script_add_arglist (state, 0, $1);
|
||||
}
|
||||
| arguments GRUB_PARSER_TOKEN_ARG
|
||||
{
|
||||
$$ = grub_script_add_arglist (state, $1, $2);
|
||||
}
|
||||
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; }
|
||||
;
|
||||
|
||||
grubcmd: arguments
|
||||
{
|
||||
$$ = grub_script_create_cmdline (state, $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; }
|
||||
command: grubcmd { $$ = $1; }
|
||||
| ifcmd { $$ = $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 list of commands. */
|
||||
commands1: newlines0 command
|
||||
{
|
||||
$$ = grub_script_add_cmd (state, 0, $2);
|
||||
}
|
||||
| commands1 delimiters1 command
|
||||
{
|
||||
struct grub_script_cmdblock *cmdblock;
|
||||
cmdblock = (struct grub_script_cmdblock *) $1;
|
||||
$$ = grub_script_add_cmd (state, cmdblock, $3);
|
||||
}
|
||||
;
|
||||
|
||||
/* 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;
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
if: "if" { grub_script_lexer_ref (state->lexerstate); }
|
||||
;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
;
|
||||
|
|
110
script/script.c
110
script/script.c
|
@ -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. */
|
||||
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
|
||||
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 @@ grub_script_malloc (struct grub_parser_param *state, grub_size_t size)
|
|||
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 @@ grub_script_mem_record_stop (struct grub_parser_param *state,
|
|||
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 @@ grub_script_arg_add (struct grub_parser_param *state, struct grub_script_arg *ar
|
|||
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_script_create_cmdline (struct grub_parser_param *state,
|
|||
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_script_create_cmdif (struct grub_parser_param *state,
|
|||
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 @@ grub_script_create_cmdif (struct grub_parser_param *state,
|
|||
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;
|
||||
|
@ -248,15 +253,19 @@ grub_script_add_cmd (struct grub_parser_param *state,
|
|||
struct grub_script_cmdblock *cmdblock,
|
||||
struct grub_script_cmd *cmd)
|
||||
{
|
||||
struct grub_script_cmd *ptr;
|
||||
|
||||
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;
|
||||
|
@ -264,22 +273,29 @@ grub_script_add_cmd (struct grub_parser_param *state,
|
|||
}
|
||||
else
|
||||
{
|
||||
cmd->next = cmdblock->cmdlist;
|
||||
cmdblock->cmdlist = cmd;
|
||||
if (!cmdblock->cmdlist)
|
||||
cmdblock->cmdlist = cmd;
|
||||
else
|
||||
{
|
||||
ptr = cmdblock->cmdlist;
|
||||
while (ptr->next)
|
||||
ptr = ptr->next;
|
||||
ptr->next = cmd;
|
||||
}
|
||||
}
|
||||
|
||||
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 +320,16 @@ grub_script_parse (char *script, grub_reader_getline_t getline)
|
|||
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 +346,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline)
|
|||
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 +354,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline)
|
|||
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;
|
||||
|
|
340
script/yylex.l
Normal file
340
script/yylex.l
Normal file
|
@ -0,0 +1,340 @@
|
|||
%{
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/parser.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/script_sh.h>
|
||||
#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 COPY(str, hint) \
|
||||
do { \
|
||||
copy_string (yyextra, str, hint); \
|
||||
} 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);
|
||||
static void copy_string (struct grub_parser_param *, const char *,
|
||||
unsigned hint);
|
||||
|
||||
%}
|
||||
|
||||
%top{
|
||||
|
||||
/*
|
||||
* Some flex hacks for -nostdinc; XXX We need to fix these when libc
|
||||
* support becomes availble in GRUB.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
|
||||
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 \"([^\\\"]|{ESC})*\"
|
||||
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_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 */
|
||||
grub_dprintf ("lexer", "word: [%s]\n", 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, 0);
|
||||
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 */
|
||||
|
||||
<SPLIT>{
|
||||
\\. { COPY (yytext + 1, yyleng - 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);
|
||||
}
|
||||
\\ |
|
||||
[^\"\'$\\]+ { COPY (yytext, yyleng); }
|
||||
<<EOF>> {
|
||||
yy_pop_state (yyscanner);
|
||||
yypop_buffer_state (yyscanner);
|
||||
yyextra->lexerstate->merge_end = 1;
|
||||
ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
<VAR>{
|
||||
\? |
|
||||
{DIGITS} |
|
||||
{NAME} {
|
||||
COPY (yytext, yyleng);
|
||||
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, yyleng - 2);
|
||||
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; }
|
||||
}
|
||||
|
||||
<SQUOTE>{
|
||||
\' {
|
||||
yy_pop_state (yyscanner);
|
||||
ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
|
||||
}
|
||||
[^\']+ { COPY (yytext, yyleng); }
|
||||
}
|
||||
|
||||
<DQUOTE>{
|
||||
\" {
|
||||
yy_pop_state (yyscanner);
|
||||
ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
|
||||
}
|
||||
\$ {
|
||||
yy_push_state (VAR, yyscanner);
|
||||
ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
|
||||
}
|
||||
\\\\ { COPY ("\\", 1); }
|
||||
\\\" { COPY ("\"", 1); }
|
||||
\\\n { /* ignore */ }
|
||||
[^\"$\\\n]+ { COPY (yytext, yyleng); }
|
||||
(.|\n) { COPY (yytext, yyleng); }
|
||||
}
|
||||
|
||||
<<EOF>> {
|
||||
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);
|
||||
}
|
||||
|
||||
#define MAX(a,b) ((a) < (b) ? (b) : (a))
|
||||
|
||||
static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
|
||||
{
|
||||
int size;
|
||||
char *ptr;
|
||||
unsigned len;
|
||||
|
||||
len = hint ? hint : grub_strlen (str);
|
||||
if (parser->lexerstate->used + len >= parser->lexerstate->size)
|
||||
{
|
||||
size = MAX (len, parser->lexerstate->size) * 2;
|
||||
ptr = grub_realloc (parser->lexerstate->text, size);
|
||||
if (!ptr)
|
||||
{
|
||||
grub_script_yyerror (parser, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
parser->lexerstate->text = ptr;
|
||||
parser->lexerstate->size = size;
|
||||
}
|
||||
grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str);
|
||||
parser->lexerstate->used += len;
|
||||
}
|
32
tests/grub_script_echo1.in
Normal file
32
tests/grub_script_echo1.in
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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\<wx\>yz\)
|
||||
|
||||
foo=c
|
||||
bar=h
|
||||
echo e"$foo"${bar}o
|
||||
e"$foo"${bar}o hello world
|
||||
|
||||
foo=echo
|
||||
$foo 1234
|
3
tests/grub_script_echo_keywords.in
Normal file
3
tests/grub_script_echo_keywords.in
Normal file
|
@ -0,0 +1,3 @@
|
|||
#! @builddir@/grub-shell-tester
|
||||
|
||||
echo if then else fi for do done
|
34
tests/grub_script_vars1.in
Normal file
34
tests/grub_script_vars1.in
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
var=foo
|
||||
echo $var
|
||||
echo "$var"
|
||||
echo ${var}
|
||||
echo "${var}"
|
||||
|
||||
echo $1 $2 $?
|
||||
|
||||
foo=foo
|
||||
echo "" $foo
|
||||
|
||||
echo $bar $foo
|
||||
|
||||
bar=""
|
||||
echo $bar $foo
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue