From 10523df4781740c499113bed7f1827f627f82cbf Mon Sep 17 00:00:00 2001 From: BVK Chaitanya Date: Sat, 23 Jan 2010 11:19:26 +0530 Subject: [PATCH] while and until loops support --- include/grub/script_sh.h | 22 ++++++++++++++++++++++ script/execute.c | 20 ++++++++++++++++++++ script/parser.y | 35 ++++++++++++++++++++++++++++++----- script/script.c | 22 ++++++++++++++++++++++ util/grub-script-check.c | 6 ++++++ 5 files changed, 100 insertions(+), 5 deletions(-) diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 4436afbf1..207b5fcbc 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -121,6 +121,21 @@ struct grub_script_cmdfor struct grub_script_cmd *list; }; +/* A while/until command. */ +struct grub_script_cmdwhile +{ + struct grub_script_cmd cmd; + + /* The command list used as condition. */ + struct grub_script_cmd *cond; + + /* The command list executed in each loop. */ + struct grub_script_cmd *list; + + /* The flag to indicate this as "until" loop. */ + int until; +}; + /* A menu entry generate statement. */ struct grub_script_cmd_menuentry { @@ -234,6 +249,12 @@ grub_script_create_cmdfor (struct grub_parser_param *state, struct grub_script_arglist *words, struct grub_script_cmd *list); +struct grub_script_cmd * +grub_script_create_cmdwhile (struct grub_parser_param *state, + struct grub_script_cmd *cond, + struct grub_script_cmd *list, + int is_an_until_loop); + struct grub_script_cmd * grub_script_create_cmdmenu (struct grub_parser_param *state, struct grub_script_arglist *arglist, @@ -283,6 +304,7 @@ 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_cmdwhile (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 aa6975fdd..b905de46f 100644 --- a/script/execute.c +++ b/script/execute.c @@ -308,6 +308,26 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) return result; } +/* Execute a "while" or "until" command. */ +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; + + result = 0; + do { + cond = grub_script_execute_cmd (cmdwhile->cond); + if ((cmdwhile->until && !cond) || (!cmdwhile->until && cond)) + break; + + result = grub_script_execute_cmd (cmdwhile->list); + } while (1); /* XXX Put a check for ^C here */ + + 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 26a6e3735..4d22ae400 100644 --- a/script/parser.y +++ b/script/parser.y @@ -76,8 +76,9 @@ %token GRUB_PARSER_TOKEN_WORD "word" %type word argument arguments0 arguments1 -%type script_init script grubcmd ifcmd forcmd command -%type commands1 menuentry statement +%type script_init script +%type grubcmd ifcmd forcmd whilecmd untilcmd +%type command commands1 menuentry statement %pure-parser %lex-param { struct grub_parser_param *state }; @@ -173,9 +174,11 @@ grubcmd: word arguments0 ; /* A single command. */ -command: grubcmd { $$ = $1; } - | ifcmd { $$ = $1; } - | forcmd { $$ = $1; } +command: grubcmd { $$ = $1; } + | ifcmd { $$ = $1; } + | forcmd { $$ = $1; } + | whilecmd { $$ = $1; } + | untilcmd { $$ = $1; } ; /* A list of commands. */ @@ -250,3 +253,25 @@ forcmd: "for" "name" grub_script_lexer_deref (state->lexerstate); } ; + +whilecmd: "while" + { + grub_script_lexer_ref (state->lexerstate); + } + commands1 delimiters1 "do" commands1 delimiters1 "done" + { + $$ = grub_script_create_cmdwhile (state, $3, $6, 0); + grub_script_lexer_deref (state->lexerstate); + } +; + +untilcmd: "until" + { + grub_script_lexer_ref (state->lexerstate); + } + commands1 delimiters1 "do" commands1 delimiters1 "done" + { + $$ = grub_script_create_cmdwhile (state, $3, $6, 1); + grub_script_lexer_deref (state->lexerstate); + } +; diff --git a/script/script.c b/script/script.c index 9142a8245..4c87d9491 100644 --- a/script/script.c +++ b/script/script.c @@ -245,6 +245,28 @@ grub_script_create_cmdfor (struct grub_parser_param *state, return (struct grub_script_cmd *) cmd; } +/* Create a "while" or "until" command. */ +struct grub_script_cmd * +grub_script_create_cmdwhile (struct grub_parser_param *state, + struct grub_script_cmd *cond, + struct grub_script_cmd *list, + int is_an_until_loop) +{ + struct grub_script_cmdwhile *cmd; + + cmd = grub_script_malloc (state, sizeof (*cmd)); + if (! cmd) + return 0; + + cmd->cmd.exec = grub_script_execute_cmdwhile; + cmd->cmd.next = 0; + cmd->cond = cond; + cmd->list = list; + cmd->until = is_an_until_loop; + + 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/util/grub-script-check.c b/util/grub-script-check.c index 3b3f5bd47..eb11988e3 100644 --- a/util/grub-script-check.c +++ b/util/grub-script-check.c @@ -87,6 +87,12 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd __attribute__ ((unused)) return 0; } +grub_err_t +grub_script_execute_cmdwhile (struct grub_script_cmd *cmd __attribute__ ((unused))) +{ + return 0; +} + grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd __attribute__ ((unused))) {