diff --git a/ChangeLog b/ChangeLog index 44c2d178d..4c1046655 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2010-09-04 BVK Chaitanya + + "return" command for GRUB script functions. + + * tests/grub_script_return.in: New test. + * Makefile.util.def: Rules for new test. + + * grub-core/script/execute.c (grub_script_return): New function. + * grub-core/script/main.c: Register/unregister return commaond. + * include/grub/script_sh.h (grub_script_return): New prototype. + +2010-09-04 BVK Chaitanya + + "setparams" command to update positional parameters. + + * tests/grub_script_setparams.in: New test. + * Makefile.util.def: Rules for new test. + + * grub-core/script/argv.c (grub_script_argv_make): New function. + * grub-core/script/execute.c (replace_scope): New function. + (grub_script_setparams): New function. + * grub-core/script/lexer.c: Remove unused variables. + * grub-core/script/main.c: Register/unregister setparams command. + * include/grub/script_sh.h (grub_script_argv_make): New prototype. + (grub_script_setparams): New prototype. + +2010-09-04 BVK Chaitanya + + * grub-core/normal/completion.c (grub_normal_do_completion): Fix + grub_free order. + 2010-09-04 BVK Chaitanya Support for passing block of commands as an argument to extcmds. diff --git a/Makefile.util.def b/Makefile.util.def index 45c2f9761..79541b5ed 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -513,6 +513,12 @@ script = { common = tests/grub_script_setparams.in; }; +script = { + testcase; + name = grub_script_return; + common = tests/grub_script_return.in; +}; + program = { testcase; name = example_unit_test; diff --git a/grub-core/normal/completion.c b/grub-core/normal/completion.c index d127f9baf..1b51dab3a 100644 --- a/grub-core/normal/completion.c +++ b/grub-core/normal/completion.c @@ -500,8 +500,8 @@ grub_normal_do_completion (char *buf, int *restore, fail: if (argc != 0) { - grub_free (argv); grub_free (argv[0]); + grub_free (argv); } grub_free (match); grub_errno = GRUB_ERR_NONE; diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index 3962b6ba5..ceda6f9c5 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -34,6 +34,10 @@ static unsigned long is_continue; static unsigned long active_loops; static unsigned long active_breaks; +static unsigned long function_return; + +#define GRUB_SCRIPT_SCOPE_MALLOCED 1 +#define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2 #define GRUB_SCRIPT_SCOPE_MALLOCED 1 #define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2 @@ -143,6 +147,30 @@ grub_script_setparams (grub_command_t cmd __attribute__((unused)), return GRUB_ERR_NONE; } +grub_err_t +grub_script_return (grub_command_t cmd __attribute__((unused)), + int argc, char *argv[]) +{ + char *p; + unsigned long n; + + if (! scope || argc > 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in function scope"); + + if (argc == 0) + { + function_return = 1; + return grub_strtoul (grub_env_get ("?"), NULL, 10); + } + + n = grub_strtoul (argv[0], &p, 10); + if (*p != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad argument"); + + function_return = 1; + return n ? grub_error (GRUB_ERR_TEST_FAILURE, "false") : GRUB_ERR_NONE; +} + static int grub_env_special (const char *name) { @@ -370,6 +398,7 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) ret = grub_script_execute (func->func); + function_return = 0; active_loops = loops; replace_scope (old_scope); /* free any scopes by setparams */ return ret; @@ -518,8 +547,16 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list) struct grub_script_cmd *cmd; /* Loop over every command and execute it. */ - for (cmd = list->next; cmd && ! active_breaks; cmd = cmd->next) - ret = grub_script_execute_cmd (cmd); + for (cmd = list->next; cmd; cmd = cmd->next) + { + if (active_breaks) + break; + + ret = grub_script_execute_cmd (cmd); + + if (function_return) + break; + } return ret; } @@ -528,14 +565,17 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list) grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd) { - struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd; + int ret; char *result; + struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd; /* Check if the commands results in a true or a false. The value is read from the env variable `?'. */ - grub_script_execute_cmd (cmdif->exec_to_evaluate); - result = grub_env_get ("?"); + ret = grub_script_execute_cmd (cmdif->exec_to_evaluate); + if (function_return) + return ret; + result = grub_env_get ("?"); grub_errno = GRUB_ERR_NONE; /* Execute the `if' or the `else' part depending on the value of @@ -569,6 +609,8 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { grub_script_env_set (cmdfor->name->str, argv.args[i]); result = grub_script_execute_cmd (cmdfor->list); + if (function_return) + break; } } @@ -584,18 +626,21 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) grub_err_t grub_script_execute_cmdwhile (struct grub_script_cmd *cmd) { - int cond; int result; struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd; active_loops++; - result = 0; do { - cond = grub_script_execute_cmd (cmdwhile->cond); - if (cmdwhile->until ? !cond : cond) + result = grub_script_execute_cmd (cmdwhile->cond); + if (function_return) + break; + + if (cmdwhile->until ? !result : result) break; result = grub_script_execute_cmd (cmdwhile->list); + if (function_return) + break; if (active_breaks == 1 && is_continue) active_breaks = 0; diff --git a/grub-core/script/lexer.c b/grub-core/script/lexer.c index 3ab40049f..8d1623fb8 100644 --- a/grub-core/script/lexer.c +++ b/grub-core/script/lexer.c @@ -205,8 +205,6 @@ struct grub_lexer_param * grub_script_lexer_init (struct grub_parser_param *parser, char *script, grub_reader_getline_t getline) { - int len; - YY_BUFFER_STATE buffer; struct grub_lexer_param *lexerstate; lexerstate = grub_zalloc (sizeof (*lexerstate)); diff --git a/grub-core/script/main.c b/grub-core/script/main.c index 4984848f0..482bb3fef 100644 --- a/grub-core/script/main.c +++ b/grub-core/script/main.c @@ -45,6 +45,7 @@ static grub_command_t cmd_break; static grub_command_t cmd_continue; static grub_command_t cmd_shift; static grub_command_t cmd_setparams; +static grub_command_t cmd_return; void grub_script_init (void) @@ -58,6 +59,8 @@ grub_script_init (void) cmd_setparams = grub_register_command ("setparams", grub_script_setparams, N_("[VALUE]..."), N_("Set positional parameters.")); + cmd_return = grub_register_command ("return", grub_script_return, + N_("[n]"), N_("Return from a function.")); } void @@ -78,4 +81,8 @@ grub_script_fini (void) if (cmd_setparams) grub_unregister_command (cmd_setparams); cmd_setparams = 0; + + if (cmd_return) + grub_unregister_command (cmd_return); + cmd_return = 0; } diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index f46dff51d..72744558a 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -331,6 +331,12 @@ 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[]); + +/* RETURN command for functions. */ +grub_err_t grub_script_return (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/tests/grub_script_return.in b/tests/grub_script_return.in new file mode 100644 index 000000000..712d1dfcf --- /dev/null +++ b/tests/grub_script_return.in @@ -0,0 +1,134 @@ +#! @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 . + +function f1 { + return + echo one +} +f1 + +function f2 { + true + return + echo one +} +if f2; then echo true; else echo false; fi + +function f3 { + false + return + echo one +} +if f3; then echo true; else echo false; fi + +function f4 { + true + return 1; + echo one +} +if f4; then echo true; else echo false; fi + +function f5 { + false + return 0; + echo one +} +if f5; then echo true; else echo false; fi + +function f6 { + echo one + if true; then + echo two + return 0 + else + echo three + return 1 + fi + echo four +} +if f6; then echo true; else echo false; fi + +function f7 { + if return 1; then + echo one + else + echo no + fi +} +if f7; then echo true; else echo false; fi + +function f8 { + echo one + for v in 1 2 3 4 5; do + echo $v + if test $v = 3; then return 1; fi + done + echo two +} +if f8; then echo true; else echo false; fi + +function f9 { + x=1 + echo one + until test x = 11111111; do + echo $x + x="1$x" + if test $x = 1111; then return 0; fi + done + echo two +} +if f9; then echo true; else echo false; fi + +function f10 { + echo one + while return 0; do + echo two + done + echo three +} +if f10; then echo true; else echo false; fi + +function f11 { + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 +} +if f11; then echo true; else echo false; fi + +function f12 { + echo one + f11 + return 1 + echo two +} +if f12; then echo true; else echo false; fi + +function f13 { + echo one + f12 + echo two + return 0 +} +if f13; then echo true; else echo false; fi