+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.
common = tests/grub_script_shift.in;
};
+script = {
+ testcase;
+ name = grub_script_return;
+ common = tests/grub_script_return.in;
+};
+
program = {
testcase;
name = example_unit_test;
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
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)
{
ret = grub_script_execute (func->func);
+ function_return = 0;
active_loops = loops;
scope = old_scope;
return ret;
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;
}
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
{
grub_script_env_set (cmdfor->name->str, argv.args[i]);
result = grub_script_execute_cmd (cmdfor->list);
+ if (function_return)
+ break;
}
}
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;
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)
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
if (cmd_shift)
grub_unregister_command (cmd_shift);
cmd_shift = 0;
+
+ if (cmd_return)
+ grub_unregister_command (cmd_return);
+ cmd_return = 0;
}
/* 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;
--- /dev/null
+#! @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