Hi,

Attached patch adds while and until commands support to GRUB script.
It is also available in people/bvk/while-loop-support branch.   This
doesn't have any unit tests yet -- i am still thinking of how to break
out of the loop, after few iterations.  Also, i am not sure how to
handle Ctrl-C to break out of the loop, if at all we want to support
it :-(



thanks,
-- 
bvk.chaitanya
=== modified file 'ChangeLog.scripting'
--- ChangeLog.scripting 2009-12-26 04:07:41 +0000
+++ ChangeLog.scripting 2009-12-26 05:05:37 +0000
@@ -1,3 +1,17 @@
+2009-12-26  BVK Chaitanya  <bvk.gro...@gmail.com>
+
+       * include/grub/script_sh.h: New function prototypes for
+       grub_script_create_cmdwhile and grub_script_execute_cmdwhile.
+       * script/parser.y ("whilecmd"): New grammar rule for while
+       command.
+       ("untilcmd"): New grammar rule for until command.
+       * script/script.c (grub_script_create_cmdwhile): Creates a
+       while/until command object.
+       * script/execute.c (grub_script_execute_cmdwhile): Executes a
+       while/until command object.
+       * util/grub-script-check.c (grub_script_execute_cmdwhile): Dummy
+       stub for syntax checking while/until statements.
+
 2009-12-25  BVK Chaitanya  <bvk.gro...@gmail.com>
 
        * include/grub/script_sh.h (grub_script_arg_type_t): New types

=== modified file 'include/grub/script_sh.h'
--- include/grub/script_sh.h    2009-12-26 04:07:41 +0000
+++ include/grub/script_sh.h    2009-12-26 04:51:55 +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
 {
@@ -236,6 +251,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,
@@ -284,6 +305,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    2009-12-26 04:07:41 +0000
+++ script/execute.c    2009-12-26 04:45:21 +0000
@@ -296,6 +296,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     2009-12-26 03:51:24 +0000
+++ script/parser.y     2009-12-26 04:26:28 +0000
@@ -76,8 +76,9 @@
 %token <arg> GRUB_PARSER_TOKEN_WORD      "word"
 
 %type <arglist> word argument arguments0 arguments1
-%type <cmd> script_init script grubcmd ifcmd forcmd command
-%type <cmd> commands1 menuentry statement
+%type <cmd> script_init script
+%type <cmd> grubcmd ifcmd forcmd whilecmd untilcmd
+%type <cmd> command commands1 menuentry statement
 
 %pure-parser
 %error-verbose
@@ -179,9 +180,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. */
@@ -261,3 +264,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     2009-12-26 03:51:24 +0000
+++ script/script.c     2009-12-26 04:31:30 +0000
@@ -230,6 +230,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.

=== modified file 'util/grub-script-check.c'
--- util/grub-script-check.c    2009-12-26 03:51:24 +0000
+++ util/grub-script-check.c    2009-12-26 04:54:43 +0000
@@ -84,6 +84,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)
 {
   struct grub_script_cmd_menuentry *menu;

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to