diff --git a/conf/tests.rmk b/conf/tests.rmk index c14fe0fda..0d41a711b 100644 --- a/conf/tests.rmk +++ b/conf/tests.rmk @@ -83,6 +83,9 @@ grub_script_continue_SOURCES = tests/grub_script_continue.in check_SCRIPTS += grub_script_shift grub_script_shift_SOURCES = tests/grub_script_shift.in +check_SCRIPTS += grub_script_setparams +grub_script_setparams_SOURCES = tests/grub_script_setparams.in + # List of tests to execute on "make check" # SCRIPTED_TESTS = example_scripted_test # SCRIPTED_TESTS += example_grub_script_test @@ -103,6 +106,7 @@ SCRIPTED_TESTS += grub_script_functions SCRIPTED_TESTS += grub_script_break SCRIPTED_TESTS += grub_script_continue SCRIPTED_TESTS += grub_script_shift +SCRIPTED_TESTS += grub_script_setparams # dependencies between tests and testing-tools $(SCRIPTED_TESTS): grub-shell grub-shell-tester diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index ae435ff1e..de5f625a2 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -226,6 +226,7 @@ void grub_script_fini (void); void grub_script_mem_free (struct grub_script_mem *mem); void grub_script_argv_free (struct grub_script_argv *argv); +int grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args); int grub_script_argv_next (struct grub_script_argv *argv); int grub_script_argv_append (struct grub_script_argv *argv, const char *s); int grub_script_argv_split_append (struct grub_script_argv *argv, char *s); @@ -314,6 +315,9 @@ grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]); /* SHIFT command for GRUB script. */ grub_err_t grub_script_shift (grub_command_t cmd, int argc, char *argv[]); +/* SETPARAMS command for GRUB script functions. */ +grub_err_t grub_script_setparams (grub_command_t cmd, int argc, char *argv[]); + /* This variable points to the parsed command. This is used to communicate with the bison code. */ extern struct grub_script_cmd *grub_script_parsed; diff --git a/script/argv.c b/script/argv.c index 92449138b..911989d0b 100644 --- a/script/argv.c +++ b/script/argv.c @@ -59,6 +59,23 @@ grub_script_argv_free (struct grub_script_argv *argv) argv->script = 0; } +/* Make argv from argc, args pair. */ +int +grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args) +{ + int i; + struct grub_script_argv r = { 0, 0, 0 }; + + for (i = 0; i < argc; i++) + if (grub_script_argv_next (&r) || grub_script_argv_append (&r, args[i])) + { + grub_script_argv_free (&r); + return 1; + } + *argv = r; + return 0; +} + /* Prepare for next argc. */ int grub_script_argv_next (struct grub_script_argv *argv) diff --git a/script/execute.c b/script/execute.c index c36d4e44b..3962b6ba5 100644 --- a/script/execute.c +++ b/script/execute.c @@ -35,13 +35,35 @@ static unsigned long is_continue; static unsigned long active_loops; static unsigned long active_breaks; +#define GRUB_SCRIPT_SCOPE_MALLOCED 1 +#define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2 + /* Scope for grub script functions. */ struct grub_script_scope { + unsigned flags; + unsigned shifts; struct grub_script_argv argv; }; static struct grub_script_scope *scope = 0; +static void +replace_scope (struct grub_script_scope *new_scope) +{ + if (scope) + { + scope->argv.argc += scope->shifts; + scope->argv.args -= scope->shifts; + + if (scope->flags & GRUB_SCRIPT_SCOPE_ARGS_MALLOCED) + grub_script_argv_free (&scope->argv); + + if (scope->flags & GRUB_SCRIPT_SCOPE_MALLOCED) + grub_free (scope); + } + scope = new_scope; +} + grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]) { @@ -86,11 +108,41 @@ grub_script_shift (grub_command_t cmd __attribute__((unused)), if (n > scope->argv.argc) return GRUB_ERR_BAD_ARGUMENT; + scope->shifts += n; scope->argv.argc -= n; scope->argv.args += n; return GRUB_ERR_NONE; } +grub_err_t +grub_script_setparams (grub_command_t cmd __attribute__((unused)), + int argc, char **args) +{ + struct grub_script_scope *new_scope; + struct grub_script_argv argv = { 0, 0, 0 }; + + if (! scope) + return GRUB_ERR_INVALID_COMMAND; + + new_scope = grub_malloc (sizeof (*new_scope)); + if (! new_scope) + return grub_errno; + + if (grub_script_argv_make (&argv, argc, args)) + { + grub_free (new_scope); + return grub_errno; + } + + new_scope->shifts = 0; + new_scope->argv = argv; + new_scope->flags = GRUB_SCRIPT_SCOPE_MALLOCED | + GRUB_SCRIPT_SCOPE_ARGS_MALLOCED; + + replace_scope (new_scope); + return GRUB_ERR_NONE; +} + static int grub_env_special (const char *name) { @@ -105,6 +157,7 @@ grub_env_special (const char *name) static char ** grub_script_env_get (const char *name, grub_script_arg_type_t type) { + unsigned i; struct grub_script_argv result = { 0, 0, 0 }; if (grub_script_argv_next (&result)) @@ -139,8 +192,6 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else if (grub_strcmp (name, "*") == 0) { - unsigned i; - for (i = 0; i < scope->argv.argc; i++) if (type == GRUB_SCRIPT_ARG_TYPE_VAR) { @@ -161,8 +212,6 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else if (grub_strcmp (name, "@") == 0) { - unsigned i; - for (i = 0; i < scope->argv.argc; i++) { if (i != 0 && grub_script_argv_next (&result)) @@ -311,6 +360,8 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) struct grub_script_scope new_scope; active_loops = 0; + new_scope.flags = 0; + new_scope.shifts = 0; new_scope.argv.argc = argc; new_scope.argv.args = args; @@ -320,7 +371,7 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) ret = grub_script_execute (func->func); active_loops = loops; - scope = old_scope; + replace_scope (old_scope); /* free any scopes by setparams */ return ret; } diff --git a/script/main.c b/script/main.c index 1aada18b8..71ca4acc1 100644 --- a/script/main.c +++ b/script/main.c @@ -44,6 +44,7 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline) static grub_command_t cmd_break; static grub_command_t cmd_continue; static grub_command_t cmd_shift; +static grub_command_t cmd_setparams; void grub_script_init (void) @@ -54,6 +55,9 @@ grub_script_init (void) N_("[n]"), N_("Continue loops")); cmd_shift = grub_register_command ("shift", grub_script_shift, N_("[n]"), N_("Shift positional parameters.")); + cmd_setparams = grub_register_command ("setparams", grub_script_setparams, + N_("[VALUE]..."), + N_("Set positional parameters.")); } void @@ -70,4 +74,8 @@ grub_script_fini (void) if (cmd_shift) grub_unregister_command (cmd_shift); cmd_shift = 0; + + if (cmd_setparams) + grub_unregister_command (cmd_setparams); + cmd_setparams = 0; } diff --git a/tests/grub_script_setparams.in b/tests/grub_script_setparams.in new file mode 100644 index 000000000..82d316813 --- /dev/null +++ b/tests/grub_script_setparams.in @@ -0,0 +1,59 @@ +#! @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 . + +if test x$grubshell = xyes; then cmd=setparams; else cmd=set; fi + +function f1 { + echo $# + echo "$#" + + echo $@ + echo "$@" + + echo $* + echo "$*" + + echo $1 $2 + for v in "$@"; do echo $v; done + shift + echo $1 $2 + for v in "$@"; do echo $v; done + + $cmd 1 2 3 4 + + echo $# + echo "$#" + + echo $@ + echo "$@" + + echo $* + echo "$*" + + echo $1 $2 + for v in "$@"; do echo $v; done + shift + echo $1 $2 + for v in "$@"; do echo $v; done +} +# f1 +# f1 a +f1 a b +f1 a b c +f1 a b c d +f1 a b c d e diff --git a/util/grub-script-check.c b/util/grub-script-check.c index 403870680..dedf2c534 100644 --- a/util/grub-script-check.c +++ b/util/grub-script-check.c @@ -73,6 +73,14 @@ grub_script_shift (grub_command_t cmd __attribute__((unused)), return 0; } +grub_err_t +grub_script_setparams (grub_command_t cmd __attribute__((unused)), + int argc __attribute__((unused)), + char *argv[] __attribute__((unused))) +{ + return 0; +} + char * grub_script_execute_argument_to_string (struct grub_script_arg *arg __attribute__ ((unused))) {