# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: address@hidden # target_branch: file:///home/bvk/Work/grub2/for-loop/ # testament_sha1: ab52b0aa586f2d8c04f5b84e8685bac20ce2d57c # timestamp: 2010-01-26 12:33:11 +0530 # base_revision_id: address@hidden # ukj4s8lpltdoslue # # Begin patch === added file 'ChangeLog.while-until-loops' --- ChangeLog.while-until-loops 1970-01-01 00:00:00 +0000 +++ ChangeLog.while-until-loops 2010-01-26 07:02:24 +0000 @@ -0,0 +1,20 @@ +2010-01-26 BVK Chaitanya + + While and until loops support to GRUB script. + + * include/grub/script_sh.h (grub_script_cmdwhile): New struct. + (grub_script_create_cmdwhile): New function prototype. + (grub_script_execute_cmdwhile): New function prototype. + * script/execute.c (grub_script_execute_cmdwhile): New function. + * script/parser.y (command): New commands. + (whilecmd): New grammar rule. + (untilcmd): New grammar rule. + * script/script.c (grub_script_create_cmdwhile): New function. + * util/grub-script-check.c (grub_script_execute_cmdwhile): New + function. + + * tests/grub_script_while1.in: New testcase. + * conf/tests.rmk: New testcase make rule. + + * commands/true.c (grub_cmd_false): Remove printing error message. + * commands/test.c (grub_cmd_test): Likewise. === modified file 'commands/test.c' --- commands/test.c 2010-01-03 22:05:07 +0000 +++ commands/test.c 2010-01-26 07:02:24 +0000 @@ -412,8 +412,7 @@ if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0) argc--; - return test_parse (args, &argn, argc) ? GRUB_ERR_NONE - : grub_error (GRUB_ERR_TEST_FAILURE, "false"); + return test_parse (args, &argn, argc) ? 0 : 1; } static grub_command_t cmd_1, cmd_2; === modified file 'commands/true.c' --- commands/true.c 2010-01-03 18:24:22 +0000 +++ commands/true.c 2010-01-26 07:02:24 +0000 @@ -34,7 +34,7 @@ int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused))) { - return grub_error (GRUB_ERR_TEST_FAILURE, "false"); + return 1; } static grub_command_t cmd_true, cmd_false; === modified file 'conf/tests.rmk' --- conf/tests.rmk 2010-01-23 05:33:41 +0000 +++ conf/tests.rmk 2010-01-26 07:02:24 +0000 @@ -53,6 +53,9 @@ check_SCRIPTS += grub_script_for1 grub_script_for1_SOURCES = tests/grub_script_for1.in +check_SCRIPTS += grub_script_while1 +grub_script_while1_SOURCES = tests/grub_script_while1.in + # List of tests to execute on "make check" # SCRIPTED_TESTS = example_scripted_test # SCRIPTED_TESTS += example_grub_script_test @@ -63,6 +66,7 @@ SCRIPTED_TESTS += grub_script_echo_keywords SCRIPTED_TESTS += grub_script_vars1 SCRIPTED_TESTS += grub_script_for1 +SCRIPTED_TESTS += grub_script_while1 # dependencies between tests and testing-tools $(SCRIPTED_TESTS): grub-shell grub-shell-tester === modified file 'include/grub/script_sh.h' --- include/grub/script_sh.h 2010-01-23 05:33:41 +0000 +++ include/grub/script_sh.h 2010-01-23 05:49:26 +0000 @@ -121,6 +121,21 @@ 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 { @@ -235,6 +250,12 @@ 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, char *sourcecode, @@ -283,6 +304,7 @@ 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. */ === modified file 'script/execute.c' --- script/execute.c 2010-01-23 05:33:41 +0000 +++ script/execute.c 2010-01-26 07:02:24 +0000 @@ -26,13 +26,24 @@ #include #include +/* Max digits for a char is 3 (0xFF is 255), similarly for an int it + is sizeof (int) * 3, and one extra for a possible -ve sign. */ +#define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1) + static grub_err_t grub_script_execute_cmd (struct grub_script_cmd *cmd) { + int ret; + char errnobuf[ERRNO_DIGITS_MAX + 1]; + if (cmd == 0) return 0; - return cmd->exec (cmd); + ret = cmd->exec (cmd); + + grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret); + grub_env_set ("?", errnobuf); + return ret; } /* Expand arguments in ARGLIST into multiple arguments. */ @@ -188,7 +199,6 @@ grub_err_t ret = 0; int argcount = 0; grub_script_function_t func = 0; - char errnobuf[18]; char *cmdname; /* Lookup the command. */ @@ -222,11 +232,7 @@ grub_env_set (assign, eq); } grub_free (assign); - - grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno); - grub_env_set ("?", errnobuf); - - return 0; + return grub_errno; } } @@ -241,9 +247,6 @@ grub_free (args[i]); grub_free (args); - grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret); - grub_env_set ("?", errnobuf); - return ret; } @@ -251,13 +254,14 @@ grub_err_t grub_script_execute_cmdblock (struct grub_script_cmd *cmd) { + int ret = 0; struct grub_script_cmdblock *cmdblock = (struct grub_script_cmdblock *) cmd; /* Loop over every command and execute it. */ for (cmd = cmdblock->cmdlist; cmd; cmd = cmd->next) - grub_script_execute_cmd (cmd); + ret = grub_script_execute_cmd (cmd); - return 0; + return ret; } /* Execute an if statement. */ @@ -308,6 +312,26 @@ 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) === modified file 'script/parser.y' --- script/parser.y 2010-01-23 05:33:41 +0000 +++ script/parser.y 2010-01-23 05:49:26 +0000 @@ -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 @@ ; /* 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 @@ 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); + } +; === modified file 'script/script.c' --- script/script.c 2010-01-23 05:33:41 +0000 +++ script/script.c 2010-01-23 05:49:26 +0000 @@ -245,6 +245,28 @@ 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. === added file 'tests/grub_script_while1.in' --- tests/grub_script_while1.in 1970-01-01 00:00:00 +0000 +++ tests/grub_script_while1.in 2010-01-26 07:02:47 +0000 @@ -0,0 +1,32 @@ +#! @builddir@/grub-shell-tester + +echo one +foo="" +while test "$foo" != "1111"; do foo="${foo}1"; echo "$foo"; done + +echo two +foo="" +while test "$foo" != "aaaa" +do + foo="${foo}a" + echo $foo +done + +foo="" +until test "$foo" = "1111"; do foo="${foo}1"; echo $foo; done +foo="" +until test "$foo" = "aaaa" +do + foo="${foo}a" + echo $foo +done + +# check "$?" in condition gets its value from while body commands +foo="" +false +while test "$?" != "0" +do + echo $foo + foo="${foo}1" + test "$foo" = "111111" +done === modified file 'util/grub-script-check.c' --- util/grub-script-check.c 2010-01-23 05:33:41 +0000 +++ util/grub-script-check.c 2010-01-23 05:49:26 +0000 @@ -88,6 +88,12 @@ } 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))) { return 0; # Begin bundle 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