]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
return command for functions
authorBVK Chaitanya <bvk@dbook>
Wed, 25 Aug 2010 14:05:52 +0000 (19:35 +0530)
committerBVK Chaitanya <bvk@dbook>
Wed, 25 Aug 2010 14:05:52 +0000 (19:35 +0530)
ChangeLog
Makefile.util.def
grub-core/script/execute.c
grub-core/script/main.c
include/grub/script_sh.h
tests/grub_script_return.in [new file with mode: 0644]

index 2db022484bc357e9cada96aa0c3e04bfd7c4a17c..0ce38240f4933843668534f4a1b38a8bcfe63140 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2010-08-25  BVK Chaitanya  <bvk.groups@gmail.com>
+
+       "return" command for GRUB script functions.
+
+       * grub-core/script/main.c: Register/unregister return command.
+       * grub-core/script/execute.c (grub_script_return): New function.
+       * include/grub/script_sh.h (grub_script_return): New prototype.
+
+       * tests/grub_script_return.in: New test for return command.
+       * Makefile.util.def: Rules for grub_script_return test.
+
 2010-08-23  BVK Chaitanya  <bvk.groups@gmail.com>
 
        New Automake based build system for GRUB.
index fd3428e766f9c7ac08838c0da9784a1f8e267027..4998bd254dee9dd5724cba0f0862293861a01a8d 100644 (file)
@@ -496,6 +496,12 @@ script = {
   common = tests/grub_script_shift.in;
 };
 
+script = {
+  testcase;
+  name = grub_script_return;
+  common = tests/grub_script_return.in;
+};
+
 program = {
   testcase;
   name = example_unit_test;
index 26a46b12b0d48d94dffa41f233fac7387b23e519..e78a41bb5db9a6327f32c6ee861fcba5e5382315 100644 (file)
@@ -33,6 +33,7 @@
 static unsigned long is_continue;
 static unsigned long active_loops;
 static unsigned long active_breaks;
+static unsigned long function_return;
 
 /* Scope for grub script functions.  */
 struct grub_script_scope
@@ -90,6 +91,30 @@ grub_script_shift (grub_command_t cmd __attribute__((unused)),
   return GRUB_ERR_NONE;
 }
 
+grub_err_t
+grub_script_return (grub_command_t cmd __attribute__((unused)),
+                   int argc, char *argv[])
+{
+  char *p;
+  unsigned long n;
+
+  if (! scope || argc > 1)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (argc == 0)
+    {
+      function_return = 1;
+      return grub_strtoul (grub_env_get ("?"), NULL, 10);
+    }
+
+  n = grub_strtoul (argv[0], &p, 10);
+  if (*p != '\0')
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  function_return = 1;
+  return n;
+}
+
 static int
 grub_env_special (const char *name)
 {
@@ -310,6 +335,7 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args)
 
   ret = grub_script_execute (func->func);
 
+  function_return = 0;
   active_loops = loops;
   scope = old_scope;
   return ret;
@@ -395,8 +421,16 @@ 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 && ! active_breaks; cmd = cmd->next)
-    ret = grub_script_execute_cmd (cmd);
+  for (cmd = list->next; cmd; cmd = cmd->next)
+    {
+      if (active_breaks)
+       break;
+
+      ret = grub_script_execute_cmd (cmd);
+
+      if (function_return)
+       break;
+    }
 
   return ret;
 }
@@ -405,14 +439,17 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list)
 grub_err_t
 grub_script_execute_cmdif (struct grub_script_cmd *cmd)
 {
-  struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
+  int ret;
   char *result;
+  struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd;
 
   /* Check if the commands results in a true or a false.  The value is
      read from the env variable `?'.  */
-  grub_script_execute_cmd (cmdif->exec_to_evaluate);
-  result = grub_env_get ("?");
+  ret = grub_script_execute_cmd (cmdif->exec_to_evaluate);
+  if (function_return)
+    return ret;
 
+  result = grub_env_get ("?");
   grub_errno = GRUB_ERR_NONE;
 
   /* Execute the `if' or the `else' part depending on the value of
@@ -447,6 +484,8 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
        {
          grub_script_env_set (cmdfor->name->str, argv.args[i]);
          result = grub_script_execute_cmd (cmdfor->list);
+         if (function_return)
+           break;
        }
     }
 
@@ -462,18 +501,21 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
 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;
 
   active_loops++;
-  result = 0;
   do {
-    cond = grub_script_execute_cmd (cmdwhile->cond);
-    if (cmdwhile->until ? !cond : cond)
+    result = grub_script_execute_cmd (cmdwhile->cond);
+    if (function_return)
+      break;
+
+    if (cmdwhile->until ? !result : result)
       break;
 
     result = grub_script_execute_cmd (cmdwhile->list);
+    if (function_return)
+      break;
 
     if (active_breaks == 1 && is_continue)
       active_breaks = 0;
index ff714d060f28567a17a4492807a3240237b9d3c9..7caeb266121bc884a0febc3ef85549d02c826cd6 100644 (file)
@@ -44,6 +44,7 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline)
 static grub_command_t cmd_break;
 static grub_command_t cmd_continue;
 static grub_command_t cmd_shift;
+static grub_command_t cmd_return;
 
 void
 grub_script_init (void)
@@ -54,6 +55,8 @@ grub_script_init (void)
                                        N_("[n]"), N_("Continue loops"));
   cmd_shift = grub_register_command ("shift", grub_script_shift,
                                     N_("[n]"), N_("Shift positional parameters."));
+  cmd_return = grub_register_command ("return", grub_script_return,
+                                     N_("[n]"), N_("Return from a function."));
 }
 
 void
@@ -70,4 +73,8 @@ grub_script_fini (void)
   if (cmd_shift)
     grub_unregister_command (cmd_shift);
   cmd_shift = 0;
+
+  if (cmd_return)
+    grub_unregister_command (cmd_return);
+  cmd_return = 0;
 }
index 77e8073600ca70a303131d13e8e026738f6511a8..844ef7930e601d3cd8cce52918f755d7e4a27137 100644 (file)
@@ -321,6 +321,9 @@ grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]);
 /* SHIFT command for GRUB script.  */
 grub_err_t grub_script_shift (grub_command_t cmd, int argc, char *argv[]);
 
+/* RETURN command for functions.  */
+grub_err_t grub_script_return (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;
diff --git a/tests/grub_script_return.in b/tests/grub_script_return.in
new file mode 100644 (file)
index 0000000..712d1df
--- /dev/null
@@ -0,0 +1,134 @@
+#! @builddir@/grub-shell-tester
+
+# Run GRUB script in a Qemu instance
+# 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/>.
+
+function f1 {
+    return
+    echo one
+}
+f1
+
+function f2 {
+    true
+    return
+    echo one
+}
+if f2; then echo true; else echo false; fi
+
+function f3 {
+    false
+    return
+    echo one
+}
+if f3; then echo true; else echo false; fi
+
+function f4 {
+    true
+    return 1;
+    echo one
+}
+if f4; then echo true; else echo false; fi
+
+function f5 {
+    false
+    return 0;
+    echo one
+}
+if f5; then echo true; else echo false; fi
+
+function f6 {
+    echo one
+    if true; then
+       echo two
+       return 0
+    else
+       echo three
+       return 1
+    fi
+    echo four
+}
+if f6; then echo true; else echo false; fi
+
+function f7 {
+    if return 1; then
+       echo one
+    else
+       echo no
+    fi
+}
+if f7; then echo true; else echo false; fi
+
+function f8 {
+    echo one
+    for v in 1 2 3 4 5; do
+       echo $v
+       if test $v = 3; then return 1; fi
+    done
+    echo two
+}
+if f8; then echo true; else echo false; fi
+
+function f9 {
+    x=1
+    echo one
+    until test x = 11111111; do
+       echo $x
+       x="1$x"
+       if test $x = 1111; then return 0; fi
+    done
+    echo two
+}
+if f9; then echo true; else echo false; fi
+
+function f10 {
+    echo one
+    while return 0; do
+       echo two
+    done
+    echo three
+}
+if f10; then echo true; else echo false; fi
+
+function f11 {
+    f1
+    f2
+    f3
+    f4
+    f5
+    f6
+    f7
+    f8
+    f9
+    f10
+}
+if f11; then echo true; else echo false; fi
+
+function f12 {
+    echo one
+    f11
+    return 1
+    echo two
+}
+if f12; then echo true; else echo false; fi
+
+function f13 {
+    echo one
+    f12
+    echo two
+    return 0
+}
+if f13; then echo true; else echo false; fi