From 4e6a305be4782194a1aaf83e962f54b313db2ac8 Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Sat, 23 Jan 2010 11:03:41 +0530 Subject: [PATCH] for loop support to grub script --- ChangeLog.for-loop | 13 +++++++++++++ conf/tests.rmk | 4 ++++ include/grub/script_sh.h | 22 ++++++++++++++++++++++ script/execute.c | 26 ++++++++++++++++++++++++++ script/parser.y | 14 +++++++++++++- script/script.c | 24 ++++++++++++++++++++++++ tests/grub_script_for1.in | 27 +++++++++++++++++++++++++++ util/grub-script-check.c | 6 ++++++ 8 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 ChangeLog.for-loop create mode 100644 tests/grub_script_for1.in diff --git a/ChangeLog.for-loop b/ChangeLog.for-loop new file mode 100644 index 000000000..0fbb9d04a --- /dev/null +++ b/ChangeLog.for-loop @@ -0,0 +1,13 @@ +2010-01-12 BVK Chaitanya + + For loop support to GRUB script. + + * include/grub/script_sh.h (grub_script_cmdfor): New struct. + (grub_script_create_cmdfor): New function prototype. + (grub_script_execute_cmdfor): New function prototype. + * script/execute.c (grub_script_execute_cmdfor): New function. + * script/parser.y (command): New for command. + (forcmd): New grammar rule. + * script/script.c (grub_script_create_cmdfor): New function. + * util/grub-script-check.c (grub_script_execute_cmdfor): New + function. diff --git a/conf/tests.rmk b/conf/tests.rmk index c5080f58c..92f14797d 100644 --- a/conf/tests.rmk +++ b/conf/tests.rmk @@ -50,6 +50,9 @@ 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 +check_SCRIPTS += grub_script_for1 +grub_script_for1_SOURCES = tests/grub_script_for1.in + # List of tests to execute on "make check" # SCRIPTED_TESTS = example_scripted_test # SCRIPTED_TESTS += example_grub_script_test @@ -59,6 +62,7 @@ grub_script_vars1_SOURCES = tests/grub_script_vars1.in SCRIPTED_TESTS = grub_script_echo1 SCRIPTED_TESTS += grub_script_echo_keywords SCRIPTED_TESTS += grub_script_vars1 +SCRIPTED_TESTS += grub_script_for1 # 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 c8c610d7b..4436afbf1 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -106,6 +106,21 @@ struct grub_script_cmdif struct grub_script_cmd *exec_on_false; }; +/* A for statement. */ +struct grub_script_cmdfor +{ + struct grub_script_cmd cmd; + + /* The name used as looping variable. */ + struct grub_script_arg *name; + + /* The words loop iterates over. */ + struct grub_script_arglist *words; + + /* The command list executed in each loop. */ + struct grub_script_cmd *list; +}; + /* A menu entry generate statement. */ struct grub_script_cmd_menuentry { @@ -213,6 +228,12 @@ grub_script_create_cmdif (struct grub_parser_param *state, struct grub_script_cmd *exec_on_true, struct grub_script_cmd *exec_on_false); +struct grub_script_cmd * +grub_script_create_cmdfor (struct grub_parser_param *state, + struct grub_script_arg *name, + struct grub_script_arglist *words, + struct grub_script_cmd *list); + struct grub_script_cmd * grub_script_create_cmdmenu (struct grub_parser_param *state, struct grub_script_arglist *arglist, @@ -261,6 +282,7 @@ void grub_script_yyerror (struct grub_parser_param *, char const *); grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdblock (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd); +grub_err_t grub_script_execute_cmdfor (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd); /* Execute any GRUB pre-parsed command or script. */ diff --git a/script/execute.c b/script/execute.c index c956960da..aa6975fdd 100644 --- a/script/execute.c +++ b/script/execute.c @@ -282,6 +282,32 @@ grub_script_execute_cmdif (struct grub_script_cmd *cmd) return grub_script_execute_cmd (cmdif->exec_on_false); } +/* Execute a for statement. */ +grub_err_t +grub_script_execute_cmdfor (struct grub_script_cmd *cmd) +{ + int i; + int result; + char **args; + int argcount; + struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd; + + args = grub_script_execute_arglist_to_argv (cmdfor->words, &argcount); + if (!args) + return grub_errno; + + result = 0; + for (i = 0; i < argcount; i++) + { + grub_env_set (cmdfor->name->str, args[i]); + result = grub_script_execute_cmd (cmdfor->list); + grub_free (args[i]); + } + + grub_free (args); + return result; +} + /* Execute the menu entry generate statement. */ grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd) diff --git a/script/parser.y b/script/parser.y index b8d981866..26a6e3735 100644 --- a/script/parser.y +++ b/script/parser.y @@ -76,7 +76,7 @@ %token GRUB_PARSER_TOKEN_WORD "word" %type word argument arguments0 arguments1 -%type script_init script grubcmd ifcmd command +%type script_init script grubcmd ifcmd forcmd command %type commands1 menuentry statement %pure-parser @@ -175,6 +175,7 @@ grubcmd: word arguments0 /* A single command. */ command: grubcmd { $$ = $1; } | ifcmd { $$ = $1; } + | forcmd { $$ = $1; } ; /* A list of commands. */ @@ -238,3 +239,14 @@ ifcmd: if commands1 delimiters1 "then" commands1 delimiters1 "fi" grub_script_lexer_deref (state->lexerstate); } ; + +forcmd: "for" "name" + { + grub_script_lexer_ref (state->lexerstate); + } + "in" arguments0 delimiters1 "do" commands1 delimiters1 "done" + { + $$ = grub_script_create_cmdfor (state, $2, $5, $8); + grub_script_lexer_deref (state->lexerstate); + } +; diff --git a/script/script.c b/script/script.c index b2d870745..9142a8245 100644 --- a/script/script.c +++ b/script/script.c @@ -221,6 +221,30 @@ grub_script_create_cmdif (struct grub_parser_param *state, return (struct grub_script_cmd *) cmd; } +/* Create a command that functions as a for statement. */ +struct grub_script_cmd * +grub_script_create_cmdfor (struct grub_parser_param *state, + struct grub_script_arg *name, + struct grub_script_arglist *words, + struct grub_script_cmd *list) +{ + struct grub_script_cmdfor *cmd; + + grub_dprintf ("scripting", "cmdfor\n"); + + cmd = grub_script_malloc (state, sizeof (*cmd)); + if (! cmd) + return 0; + + cmd->cmd.exec = grub_script_execute_cmdfor; + cmd->cmd.next = 0; + cmd->name = name; + cmd->words = words; + cmd->list = list; + + return (struct grub_script_cmd *) cmd; +} + /* Create a command that adds a menu entry to the menu. Title is an argument that is parsed to generate a string that can be used as the title. The sourcecode for this entry is passed in SOURCECODE. diff --git a/tests/grub_script_for1.in b/tests/grub_script_for1.in new file mode 100644 index 000000000..e39a7664d --- /dev/null +++ b/tests/grub_script_for1.in @@ -0,0 +1,27 @@ +#! @builddir@/grub-shell-tester + +for x in one two 'three 3' "four 4" five six-6; do echo $x; done + +for x in one two 'three 3' "four 4" five six-6 +do + echo $x +done + +foo="1 2" +for x in ab${foo}cd; do echo $x; done +for x in "ab${foo}cd"; do echo $x; done + +a="one two three" +y=foo +echo $y +for y in $a; do + echo $y +done +echo $y + + +b="one two three" +for z in $b; do + echo $z +done +echo $z diff --git a/util/grub-script-check.c b/util/grub-script-check.c index 0ad24186d..3b3f5bd47 100644 --- a/util/grub-script-check.c +++ b/util/grub-script-check.c @@ -81,6 +81,12 @@ grub_script_execute_cmdif (struct grub_script_cmd *cmd __attribute__ ((unused))) return 0; } +grub_err_t +grub_script_execute_cmdfor (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd __attribute__ ((unused))) {