]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
break command support
authorBVK Chaitanya <bvk.groups@gmail.com>
Wed, 5 May 2010 10:04:26 +0000 (15:34 +0530)
committerBVK Chaitanya <bvk.groups@gmail.com>
Wed, 5 May 2010 10:04:26 +0000 (15:34 +0530)
conf/common.rmk
conf/tests.rmk
include/grub/script_sh.h
script/execute.c
script/main.c
tests/grub_script_break.in [new file with mode: 0644]
util/grub-script-check.c

index 4b39e9b71a1247e49a0598a8f287c7bb979e9282..ed96ce320a8d1c93d4f4a1d31e0daf04565636cc 100644 (file)
@@ -103,12 +103,12 @@ DISTCLEANFILES += grub_script.yy.c grub_script.yy.h
 # For grub-script-check.
 bin_UTILITIES += grub-script-check
 util/grub-script-check.c_DEPENDENCIES = grub_script_check_init.h
-grub_script_check_SOURCES = gnulib/progname.c gnulib/getdelim.c gnulib/getline.c \
-       util/grub-script-check.c util/misc.c util/mm.c \
-       script/main.c script/script.c script/function.c script/lexer.c \
-       kern/handler.c kern/err.c kern/parser.c kern/list.c \
-       kern/misc.c kern/env.c grub_script_check_init.c grub_script.tab.c \
-       grub_script.yy.c
+grub_script_check_SOURCES = gnulib/progname.c gnulib/getdelim.c                \
+       gnulib/getline.c util/grub-script-check.c util/misc.c           \
+       util/mm.c script/main.c script/script.c script/function.c       \
+       script/lexer.c kern/handler.c kern/err.c kern/parser.c          \
+       kern/list.c kern/misc.c kern/env.c kern/command.c               \
+       grub_script_check_init.c grub_script.tab.c grub_script.yy.c
 grub_script_check_CFLAGS = $(GNULIB_UTIL_CFLAGS)
 MOSTLYCLEANFILES += symlist.c kernel_syms.lst
 DEFSYMFILES += kernel_syms.lst
index 9144e552845b3a517dc7ff959b226bbfcc722e58..8af4207b77b8c1048528ba48cda66c59774c2a50 100644 (file)
@@ -74,6 +74,9 @@ grub_script_comments_SOURCES = tests/grub_script_comments.in
 check_SCRIPTS += grub_script_functions
 grub_script_functions_SOURCES = tests/grub_script_functions.in
 
+check_SCRIPTS += grub_script_break
+grub_script_break_SOURCES = tests/grub_script_break.in
+
 # List of tests to execute on "make check"
 # SCRIPTED_TESTS    = example_scripted_test
 # SCRIPTED_TESTS   += example_grub_script_test
@@ -91,6 +94,7 @@ SCRIPTED_TESTS += grub_script_final_semicolon
 SCRIPTED_TESTS += grub_script_dollar
 SCRIPTED_TESTS += grub_script_comments
 SCRIPTED_TESTS += grub_script_functions
+SCRIPTED_TESTS += grub_script_break
 
 # dependencies between tests and testing-tools
 $(SCRIPTED_TESTS): grub-shell grub-shell-tester
index 730aa30050e85670d054d70cbcfa559e58f09109..aee0a743fd8536599e34dcbb1e8926aa99c593e7 100644 (file)
@@ -23,6 +23,7 @@
 #include <grub/types.h>
 #include <grub/err.h>
 #include <grub/parser.h>
+#include <grub/command.h>
 
 struct grub_script_mem;
 
@@ -308,6 +309,9 @@ grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd);
 /* Execute any GRUB pre-parsed command or script.  */
 grub_err_t grub_script_execute (struct grub_script *script);
 
+/* Break command for loops.  */
+grub_err_t grub_script_break (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;
index 571b6785bfc13de1c49f4555463b515bb8f95eca..1f639e00ba0d0a58a30b2a880c5f0aba2f3ac84d 100644 (file)
    is sizeof (int) * 3, and one extra for a possible -ve sign.  */
 #define ERRNO_DIGITS_MAX  (sizeof (int) * 3 + 1)
 
+static unsigned long active_loops;
+static unsigned long active_breaks;
 static struct grub_script_scope *scope = 0;
 
+grub_err_t
+grub_script_break (grub_command_t cmd __attribute__((unused)),
+                  int argc, char *argv[])
+{
+  char *p = 0;
+  unsigned long count;
+
+  if (argc == 0)
+    count = 1;
+
+  else if ((argc > 1) ||
+          (count = grub_strtoul (argv[0], &p, 10)) > active_loops ||
+          (*p != '\0'))
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad break");
+
+  active_breaks = count;
+  return GRUB_ERR_NONE;
+}
+
 static char *
 grub_script_env_get (const char *name)
 {
@@ -242,8 +263,10 @@ grub_err_t
 grub_script_function_call (grub_script_function_t func, int argc, char **args)
 {
   grub_err_t ret = 0;
+  unsigned long loops = active_loops;
   struct grub_script_scope new_scope;
 
+  active_loops = 0;
   new_scope.argc = argc;
   new_scope.args = args;
   grub_list_push (GRUB_AS_LIST_P (&scope), GRUB_AS_LIST (&new_scope));
@@ -251,6 +274,7 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args)
   ret = grub_script_execute (func->func);
 
   grub_list_pop (GRUB_AS_LIST_P (&scope));
+  active_loops = loops;
   return ret;
 }
 
@@ -338,7 +362,7 @@ 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; cmd = cmd->next)
+  for (cmd = list->next; cmd && ! active_breaks; cmd = cmd->next)
     ret = grub_script_execute_cmd (cmd);
 
   return ret;
@@ -380,14 +404,22 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
   if (!args)
     return grub_errno;
 
+  active_loops++;
   result = 0;
   for (i = 0; i < argcount; i++)
     {
-      grub_script_env_set (cmdfor->name->str, args[i]);
-      result = grub_script_execute_cmd (cmdfor->list);
+      if (! active_breaks)
+       {
+         grub_script_env_set (cmdfor->name->str, args[i]);
+         result = grub_script_execute_cmd (cmdfor->list);
+       }
       grub_free (args[i]);
     }
 
+  if (active_breaks)
+    active_breaks--;
+
+  active_loops--;
   grub_free (args);
   return result;
 }
@@ -400,6 +432,7 @@ grub_script_execute_cmdwhile (struct grub_script_cmd *cmd)
   int result;
   struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd;
 
+  active_loops++;
   result = 0;
   do {
     cond = grub_script_execute_cmd (cmdwhile->cond);
@@ -407,8 +440,16 @@ grub_script_execute_cmdwhile (struct grub_script_cmd *cmd)
       break;
 
     result = grub_script_execute_cmd (cmdwhile->list);
+
+    if (active_breaks)
+      {
+       active_breaks--;
+       break;
+      }
+
   } while (1); /* XXX Put a check for ^C here */
 
+  active_loops--;
   return result;
 }
 
index b5159dc7ddcd71a653f389c947f9938465ad754e..c30df1f2ddf500d4067d7302bd77f1ce85d76233 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <grub/dl.h>
+#include <grub/i18n.h>
 #include <grub/parser.h>
 #include <grub/script_sh.h>
 
@@ -49,6 +50,8 @@ static struct grub_parser grub_sh_parser =
 GRUB_MOD_INIT(sh)
 {
   grub_parser_register ("grub", &grub_sh_parser);
+  grub_register_command ("break", grub_script_break,
+                        N_("[n]"), N_("Exit from loops"));
 }
 
 GRUB_MOD_FINI(sh)
diff --git a/tests/grub_script_break.in b/tests/grub_script_break.in
new file mode 100644 (file)
index 0000000..bf265e8
--- /dev/null
@@ -0,0 +1,86 @@
+#! @builddir@/grub-shell-tester
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+# break without any arguments
+for i in 1 2 3 4 5 6 7 8 9 10
+do
+  echo $i
+  if test "$i" = 5
+  then
+    break
+  fi
+done
+
+# break with one
+for i in 1 2 3 4 5 6 7 8 9 10
+do
+  echo $i
+  if test "$i" = 5
+  then
+    break 1
+  fi
+done
+
+# break with loop count
+for i in 1 2 3 4 5
+do
+  for j in a b c d e f
+  do
+    echo "$i $j"
+    if test "$i" = 3
+    then
+      if test "$j" = d
+      then
+        break 2
+      fi
+    fi
+  done
+done
+
+# break into middle loop
+for i in 1 2 3 4 5
+do
+  for j in a b c d e f
+  do
+    echo "$i $j"
+    if test "$i" = 3
+    then
+      if test "$j" = d
+      then
+        break 1
+      fi
+    fi
+  done
+done
+
+# while and until loops
+a=
+while test "$a" != "aaaaaaa"
+do
+  a="a$a"
+  for i in 1 2 3 4
+  do
+    b=
+    until test "$b" = "bbbbb"
+    do
+      b="b$b"
+      echo "$a $i $b"
+      if test "$i" = 3; then echo "break 2"; break 2; fi
+    done
+  done
+done
+
index 3b7ab295d9e9feb8f9642fc7e71c8091f9929cc0..972a5fe1776453f0ccdfecc6949ce9d34bd56079 100644 (file)
@@ -57,6 +57,14 @@ grub_refresh (void)
   fflush (stdout);
 }
 
+grub_err_t
+grub_script_break (grub_command_t cmd __attribute__((unused)),
+                  int argc __attribute__((unused)),
+                  char *argv[] __attribute__((unused)))
+{
+  return 0;
+}
+
 char *
 grub_script_execute_argument_to_string (struct grub_script_arg *arg __attribute__ ((unused)))
 {