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;
++
+ /* Scope for grub script functions. */
+ struct grub_script_scope
+ {
+ struct grub_script_argv argv;
+ };
static struct grub_script_scope *scope = 0;
- static char *
- grub_script_env_get (const char *name)
+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)) == 0 ||
+ (*p != '\0'))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad break");
+
+ active_breaks = grub_min (active_loops, count);
+ return GRUB_ERR_NONE;
+}
+
+ static int
+ grub_env_special (const char *name)
{
- char *p = 0;
- unsigned long num = 0;
+ if (grub_isdigit (name[0]) ||
+ grub_strcmp (name, "#") == 0 ||
+ grub_strcmp (name, "*") == 0 ||
+ grub_strcmp (name, "@") == 0)
+ return 1;
+ return 0;
+ }
- if (! scope)
- return grub_env_get (name);
+ static char **
+ grub_script_env_get (const char *name, grub_script_arg_type_t type)
+ {
+ int errors = 0;
+ struct grub_script_argv result = { 0, 0 };
- if (grub_isdigit (name[0]))
+ errors += grub_script_argv_next (&result);
+ if (! grub_env_special (name))
{
- num = grub_strtoul (name, &p, 10);
- if (p && *p == '\0')
+ char *v = grub_env_get (name);
+ if (v && v[0])
{
- if (num == 0)
- return 0; /* XXX no file name, for now. */
+ if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
+ errors += grub_script_argv_split_append (&result, v);
+ else
+ errors += grub_script_argv_append (&result, v);
+ }
+ }
+ else if (! scope)
+ errors += grub_script_argv_append (&result, 0);
+
+ else if (grub_strcmp (name, "#") == 0)
+ {
+ char buffer[ERRNO_DIGITS_MAX + 1];
+ grub_snprintf (buffer, sizeof (buffer), "%u", scope->argv.argc);
+ errors += grub_script_argv_append (&result, buffer);
+ }
+ else if (grub_strcmp (name, "*") == 0)
+ {
+ int i;
+
+ for (i = 0; ! errors && i < scope->argv.argc; i++)
+ if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
+ {
+ if (i != 0)
+ errors += grub_script_argv_next (&result);
+ errors += grub_script_argv_split_append (&result,
+ scope->argv.args[i]);
+ }
+ else
+ {
+ if (i != 0)
+ errors += grub_script_argv_append (&result, " ");
+ errors += grub_script_argv_append (&result,
+ scope->argv.args[i]);
+ }
+ }
+ else if (grub_strcmp (name, "@") == 0)
+ {
+ int i;
- return (num > scope->argc ? 0 : scope->args[num - 1]);
+ for (i = 0; ! errors && i < scope->argv.argc; i++)
+ {
+ if (i != 0)
+ errors += grub_script_argv_next (&result);
+
+ if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
+ errors += grub_script_argv_split_append (&result,
+ scope->argv.args[i]);
+ else
+ errors += grub_script_argv_append (&result,
+ scope->argv.args[i]);
}
- else
+ }
+ else
+ {
+ unsigned long num = grub_strtoul (name, 0, 10);
+ if (num == 0)
+ ; /* XXX no file name, for now. */
+
+ else if (num <= scope->argv.argc)
{
- grub_error (GRUB_ERR_BAD_ARGUMENT, "bad variabe name substitution");
- return 0;
+ if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
+ errors += grub_script_argv_split_append (&result,
+ scope->argv.args[num - 1]);
+ else
+ errors += grub_script_argv_append (&result,
+ scope->argv.args[num - 1]);
}
}
- else if (grub_strcmp (name, "#") == 0)
+
+ if (errors)
{
- static char buf[32]; /* Rewritten everytime. */
- grub_snprintf (buf, sizeof (buf), "%u", scope->argc);
- return buf;
+ grub_script_argv_free (&result);
+ return 0;
}
- else
- return grub_env_get (name);
+
+ return result.args;
}
static 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 *old_scope;
struct grub_script_scope new_scope;
- new_scope.argc = argc;
- new_scope.args = args;
- grub_list_push (GRUB_AS_LIST_P (&scope), GRUB_AS_LIST (&new_scope));
+ active_loops = 0;
+ new_scope.argv.argc = argc;
+ new_scope.argv.args = args;
+
+ old_scope = scope;
+ scope = &new_scope;
ret = grub_script_execute (func->func);
- grub_list_pop (GRUB_AS_LIST_P (&scope));
+ active_loops = loops;
+ scope = old_scope;
return ret;
}
{
int i;
int result;
- char **args;
- int argcount;
+ struct grub_script_argv argv;
struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd;
- args = grub_script_execute_arglist_to_argv (cmdfor->words, &argcount);
- if (!args)
+ if (grub_script_arglist_to_argv (cmdfor->words, &argv))
return grub_errno;
+ active_loops++;
result = 0;
- for (i = 0; i < argcount; i++)
+ for (i = 0; i < argv.argc; i++)
{
- grub_script_env_set (cmdfor->name->str, argv.args[i]);
- result = grub_script_execute_cmd (cmdfor->list);
+ if (! active_breaks)
+ {
- grub_script_env_set (cmdfor->name->str, args[i]);
++ grub_script_env_set (cmdfor->name->str, argv.args[i]);
+ result = grub_script_execute_cmd (cmdfor->list);
+ }
- grub_free (args[i]);
}
- grub_free (args);
+ if (active_breaks)
+ active_breaks--;
+
+ active_loops--;
+ grub_script_argv_free (&argv);
return result;
}