grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Bash pre-alpha


From: Serbinenko Vladimir
Subject: Re: Bash pre-alpha
Date: Mon, 31 Jan 2005 06:59:54 +0100
User-agent: Mozilla Thunderbird 1.0 (X11/20041206)

Here I send a patch for bash scripting. New version. Here it's not an incremental patch. it's a patch for current CVS version. Current problems:
Not enough testing
Badly commented.
Best wishes Serbinenko Vladimir
--------------------------------------------------------------------------
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x 'config*' -x kernel_syms.lst -x Makefile -x stamp-h -x symlist.c -x output.0 -x requests -x traces.0 -x '*.mk' -x cpu -x machine -x Entries --expand-tabs grub2/ChangeLog grub2ch/ChangeLog
--- grub2/ChangeLog    2005-01-29 23:01:54.000000000 +0100
+++ grub2ch/ChangeLog    2005-01-30 19:24:08.852259864 +0100
@@ -1,3 +1,38 @@
+2005-01-30 Serbinenko Vladimir <address@hidden>
+
+  * Scripting: new constructions: for((...;...;...)); do ...; done
+                                  for .. in ...; do ...; done
+                                  braces expansion
+               GCS cleanup
+               Integrating token spliting in scripting
+ Function script_expand is now split up in script_expand_braces,
+               script_expand_dollar and script_split_tokens
+               some bugfixing
+ +2005-01-29 Serbinenko Vladimir <address@hidden>
+
+        * include/grub/script.h: New type return reason
+        * normal/command.c : New commands: true,false, '.'
+        * normal/script.c:      Bug fixed
+ New keywords: until, while, break,continue,return + +2005-01-29 Serbinenko Vladimir <address@hidden>
+
+        Scripting support
+        * normal/script.c: New file
+        * include/grub/normal.h: New prototype
+        * include/grub/script.h: New file
+        * normal/script.c: Likewise
+ * normal/command.c : grub_command_execute: redirect to scripting engine + grub_exec_norm: Normal executing + grub_command_set: using script_env_set + grub_command_unset: Likewise + New commands: ':', echo, source, showmenu + Due to new menu syntax title command removed + * normal/main.c: get_line and read_config_file replaced by scripting
+                                        menu variable redeclared as global
+ * normal/menu.c: run_menu_entry: redirected to scripting engine + 2005-01-29 Yoshinori K. Okuji <address@hidden>

        * include/grub/misc.h (memmove): New prototype.
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x 'config*' -x kernel_syms.lst -x Makefile -x stamp-h -x symlist.c -x output.0 -x requests -x traces.0 -x '*.mk' -x cpu -x machine -x Entries --expand-tabs grub2/conf/i386-pc.rmk grub2ch/conf/i386-pc.rmk
--- grub2/conf/i386-pc.rmk    2005-01-21 22:32:03.000000000 +0100
+++ grub2ch/conf/i386-pc.rmk    2005-01-29 13:41:05.000000000 +0100
@@ -72,7 +72,7 @@
        partmap/pc.c partmap/apple.c                                    \
commands/terminal.c commands/boot.c commands/cmp.c commands/cat.c \ util/i386/pc/biosdisk.c fs/fat.c fs/ext2.c fs/ufs.c fs/minix.c fs/hfs.c fs/jfs.c fs/iso9660.c \ - normal/cmdline.c normal/command.c normal/main.c normal/menu.c normal/arg.c \ + normal/cmdline.c normal/command.c normal/script.c normal/main.c normal/menu.c normal/arg.c \ util/console.c util/grub-emu.c util/misc.c util/i386/pc/getroot.c disk/loopback.c
grub_emu_LDFLAGS = -lncurses

@@ -134,7 +134,7 @@
linux_mod_CFLAGS = $(COMMON_CFLAGS)

# For normal.mod.
-normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/main.c \
+normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/script.c normal/main.c \
        normal/menu.c normal/arg.c normal/i386/setjmp.S
normal_mod_CFLAGS = $(COMMON_CFLAGS)
normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x 'config*' -x kernel_syms.lst -x Makefile -x stamp-h -x symlist.c -x output.0 -x requests -x traces.0 -x '*.mk' -x cpu -x machine -x Entries --expand-tabs grub2/conf/powerpc-ieee1275.rmk grub2ch/conf/powerpc-ieee1275.rmk
--- grub2/conf/powerpc-ieee1275.rmk    2005-01-21 22:32:03.000000000 +0100
+++ grub2ch/conf/powerpc-ieee1275.rmk    2005-01-29 13:42:19.000000000 +0100
@@ -38,7 +38,7 @@
        partmap/amiga.c partmap/pc.c partmap/apple.c fs/fshelp.c        \
util/i386/pc/biosdisk.c fs/fat.c fs/ext2.c fs/ufs.c fs/minix.c fs/hfs.c \
        fs/jfs.c fs/iso9660.c \
-        normal/cmdline.c normal/command.c normal/main.c normal/menu.c   \
+ normal/cmdline.c normal/command.c normal/script.c normal/main.c normal/menu.c \
        normal/arg.c kern/partition.c   \
        util/console.c util/grub-emu.c util/misc.c util/i386/pc/getroot.c \
        kern/env.c disk/loopback.c commands/ls.c                \
@@ -108,7 +108,7 @@
linux_mod_CFLAGS = $(COMMON_CFLAGS)

# For normal.mod.
-normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/main.c \
+normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/script.c normal/main.c \
        normal/menu.c normal/arg.c normal/powerpc/setjmp.S
normal_mod_CFLAGS = $(COMMON_CFLAGS)
normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x 'config*' -x kernel_syms.lst -x Makefile -x stamp-h -x symlist.c -x output.0 -x requests -x traces.0 -x '*.mk' -x cpu -x machine -x Entries --expand-tabs grub2/include/grub/normal.h grub2ch/include/grub/normal.h
--- grub2/include/grub/normal.h    2005-01-21 22:32:03.000000000 +0100
+++ grub2ch/include/grub/normal.h    2005-01-30 11:57:04.000000000 +0100
@@ -141,7 +141,7 @@
void grub_normal_init_page (void);
int grub_arg_parse (grub_command_t parser, int argc, char **argv,
                    struct grub_arg_list *usr, char ***args, int *argnum);
-
+int grub_exec_norm(char**args,int num);

#ifdef GRUB_UTIL
void grub_normal_init (void);
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x 'config*' -x kernel_syms.lst -x Makefile -x stamp-h -x symlist.c -x output.0 -x requests -x traces.0 -x '*.mk' -x cpu -x machine -x Entries --expand-tabs grub2/include/grub/script.h grub2ch/include/grub/script.h
--- grub2/include/grub/script.h    1970-01-01 01:00:00.000000000 +0100
+++ grub2ch/include/grub/script.h    2005-01-30 12:13:54.000000000 +0100
@@ -0,0 +1,94 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003  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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef SCRIPT_H
+#define SCRIPT_H        1
+#define EXPAND_BUF_SIZE 1024
+#define BRACE_BUFFER 64
+
+#define SCRIPT_BRACK 0
+#define SCRIPT_LEFT 1
+#define SCRIPT_RIGHT 2
+#define SCRIPT_BIN 3
+#define SCRIPT_TERN 4
+#define SCRIPT_AND 5
+#define SCRIPT_OR 6
+#define SCRIPT_LEFTS SCRIPT_LEFT
+#define SCRIPT_ARGPART 7
+#define SCRIPT_LVALUE 8
+#define SCRIPT_RASSOC 16
+#define SCRIPT_NEEDLVALUEA 16
+struct script_oper{
+        int priority;
+        char seq[10];
+        int type;
+        char* (*func_do)(char*a,char*b,int opn);
+};
+struct braceset
+{
+        char*word;
+        int len;
+        struct braceset*next;
+};
+enum vartype {SCRIPT_STR,SCRIPT_VAR_NAME};
+enum returnreason {SCRIPT_NONE=0,SCRIPT_RETURN,SCRIPT_BREAK,SCRIPT_CONTINUE};
+extern struct script_oper script_opers[];
+int
+script_find_oper(char*exp,int searchleft);
+char*
+script_eval_arith(char*,enum vartype*);
+char*
+script_env_get(char*nm);
+void
+script_env_unset(char*nm);
+void
+script_env_set(char*nm,char*val);
+char*
+script_get_str(char*var,enum vartype tp);
+char*
+script_get_arrayelem(char*elem,char*indx);
+char*
+script_expand_dollar (char*exp);
+char*
+script_get_array(char*exp,char**cont,int contcnt);
+char*
+script_escape_string(char*str);
+void
+script_unescape(char*str);
+void
+script_del_arrayelem(char**arr,char*indx);
+void
+script_add_arrayelem(char**arr,char*indx,char*val);
+int
+script_find_pas(char cbeg,char cend,char *str);
+int
+script_get_strend(char*str);
+int
+script_execute(char*cmdline,grub_err_t(*getline)(char**),char**rest,enum returnreason*retres,int*depth);
+int
+script_list_execute( grub_menu_entry_t fn,enum returnreason*retres,int*depth);
+int
+script_exec_file (char*fname,int argc, char**argv);
+char**
+script_split_tokens(char*cmdline,int*argc,grub_err_t (* getline) (char **),char**end);
+grub_menu_t menu;
+#define EXPAND_DOLLAR 1
+#define EXPAND_BRACE 2
+#define EXPAND_ALL 3
+#endif /* ! SCRIPT_H*/
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x 'config*' -x kernel_syms.lst -x Makefile -x stamp-h -x symlist.c -x output.0 -x requests -x traces.0 -x '*.mk' -x cpu -x machine -x Entries --expand-tabs grub2/normal/command.c grub2ch/normal/command.c
--- grub2/normal/command.c    2004-09-17 11:36:52.000000000 +0200
+++ grub2ch/normal/command.c    2005-01-30 12:01:30.000000000 +0100
@@ -24,6 +24,7 @@
#include <grub/term.h>
#include <grub/env.h>
#include <grub/dl.h>
+#include <grub/script.h>

static grub_command_t grub_command_list;

@@ -120,31 +121,19 @@
      return grub_cmdline_get (">", *s, GRUB_MAX_CMDLINE, 0, 1);
    }

+  return script_execute(cmdline,cmdline_get,0,0,0);
+}
+int
+grub_exec_norm(char**args,int num)
+{
  grub_command_t cmd;
  grub_err_t ret = 0;
  char *pager;
-  int num;
-  char **args;
  struct grub_arg_list *state;
  struct grub_arg_option *parser;
  int maxargs = 0;
  char **arglist;
  int numargs;
-
-  if (grub_split_cmdline (cmdline, cmdline_get, &num, &args))
-    return 0;
- - /* In case of an assignment set the environment accordingly instead
-     of calling a function.  */
-  if (num == 0 && grub_strchr (args[0], '='))
-    {
-      char *val = grub_strchr (args[0], '=');
-      val[0] = 0;
-      grub_env_set (args[0], val + 1);
-      val[0] = '=';
-      return 0;
-    }
- cmd = grub_command_find (args[0]);
  if (! cmd)
    return -1;
@@ -162,11 +151,11 @@
  grub_memset (state, 0, sizeof (struct grub_arg_list) * maxargs);
  if (! (cmd->flags & GRUB_COMMAND_FLAG_NO_ARG_PARSE))
    {
-      if (grub_arg_parse (cmd, num, &args[1], state, &arglist, &numargs))
+      if (grub_arg_parse (cmd, num-1, &args[1], state, &arglist, &numargs))
        ret = (cmd->func) (state, numargs, arglist);
    }
  else
-    ret = (cmd->func) (state, num, &args[1]);
+    ret = (cmd->func) (state, num-1, &args[1]);
grub_free (state);

@@ -218,7 +208,7 @@
    }
val[0] = 0;
-  grub_env_set (var, val + 1);
+  script_env_set (var, val + 1);
  val[0] = '=';
  return 0;
}
@@ -231,7 +221,7 @@
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
                       "no environment variable specified");

-  grub_env_unset (args[0]);
+  script_env_unset (args[0]);
  return 0;
}

@@ -306,11 +296,70 @@
  return 0;
}

+
+static grub_err_t
+echo_command (struct grub_arg_list *state __attribute__ ((unused)),
+                int argc,
+                char **args)
+{
+  int i;
+  for(i=0;i<argc;i++)
+        grub_printf ("%s ",args[i]);
+  grub_printf("\n");
+  return 0;
+}
+
+static grub_err_t
+empty_command (struct grub_arg_list *state __attribute__ ((unused)),
+                int argc __attribute__ ((unused)),
+                char **args __attribute__ ((unused)))
+{
+  return 0;
+}
+
+static grub_err_t
+source_command (struct grub_arg_list *state __attribute__ ((unused)),
+                int argc,
+                char **args)
+{
+  if(!argc)
+  {
+        grub_error(GRUB_ERR_BAD_ARGUMENT,"Filename expected");
+        return GRUB_ERR_BAD_ARGUMENT;
+  }
+  return script_exec_file(args[0],argc-1,args+1);
+}
+static grub_err_t
+showmenu_command (struct grub_arg_list *state __attribute__ ((unused)),
+                int argc __attribute__ ((unused)),
+                char **args __attribute__ ((unused)))
+{
+  if (menu->size)
+    grub_menu_run (menu, 0);
+  else
+    grub_cmdline_run (0);
+   return 0;
+}
+
+static grub_err_t
+true_command (struct grub_arg_list *state __attribute__ ((unused)),
+                int argc __attribute__ ((unused)),
+                char **args __attribute__ ((unused)))
+{
+   return 0;
+}
+
+static grub_err_t
+false_command (struct grub_arg_list *state __attribute__ ((unused)),
+                int argc __attribute__ ((unused)),
+                char **args __attribute__ ((unused)))
+{
+   return 1;
+}
+
void
grub_command_init (void)
{
-  /* This is a special command, because this never be called actually.  */
-  grub_register_command ("title", 0, GRUB_COMMAND_FLAG_TITLE, 0, 0, 0);

  grub_register_command ("rescue", rescue_command, GRUB_COMMAND_FLAG_BOTH,
                         "rescue", "Enter into the rescue mode.", 0);
@@ -329,4 +378,23 @@

  grub_register_command ("lsmod", lsmod_command, GRUB_COMMAND_FLAG_BOTH,
                         "lsmod", "Show loaded modules.", 0);
+
+  grub_register_command ("echo", echo_command, GRUB_COMMAND_FLAG_BOTH,
+                         "echo MESSAGE", "Print a message.", 0);
+
+  grub_register_command (":", empty_command, GRUB_COMMAND_FLAG_BOTH,
+                         ":", "Does nothing except expanding.", 0);
+ + grub_register_command ("source", source_command, GRUB_COMMAND_FLAG_BOTH, + "source FILE [ARGUMENTS ...]", "Execute script FILE.", 0);
+
+  grub_register_command (".", source_command, GRUB_COMMAND_FLAG_BOTH,
+ ". FILE [ARGUMENTS ...]", "Execute script FILE.", 0); + + grub_register_command ("showmenu", showmenu_command, GRUB_COMMAND_FLAG_BOTH,
+                         "showmenu", "Show menu.", 0);
+  grub_register_command ("true", true_command, GRUB_COMMAND_FLAG_BOTH,
+                         "true", "Return success.", 0);
+  grub_register_command ("false", false_command, GRUB_COMMAND_FLAG_BOTH,
+                         "false", "Return failure.", 0);
}
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x 'config*' -x kernel_syms.lst -x Makefile -x stamp-h -x symlist.c -x output.0 -x requests -x traces.0 -x '*.mk' -x cpu -x machine -x Entries --expand-tabs grub2/normal/main.c grub2ch/normal/main.c
--- grub2/normal/main.c    2004-08-21 15:54:22.000000000 +0200
+++ grub2ch/normal/main.c    2005-01-29 13:57:28.000000000 +0100
@@ -32,74 +32,6 @@

#define GRUB_DEFAULT_HISTORY_SIZE       50

-/* Read a line from the file FILE.  */
-static int
-get_line (grub_file_t file, char cmdline[], int max_len)
-{
-  char c;
-  int pos = 0;
-  int literal = 0;
-  int comment = 0;
-
-  while (1)
-    {
-      if (grub_file_read (file, &c, 1) != 1)
-        break;
-
-      /* Skip all carriage returns.  */
-      if (c == '\r')
-        continue;
-
-      /* Replace tabs with spaces.  */
-      if (c == '\t')
-        c = ' ';
-
-      /* The previous is a backslash, then...  */
-      if (literal)
-        {
-          /* If it is a newline, replace it with a space and continue.  */
-          if (c == '\n')
-            {
-              c = ' ';
-
-              /* Go back to overwrite the backslash.  */
-              if (pos > 0)
-                pos--;
-            }
-
-          literal = 0;
-        }
-
-      if (c == '\\')
-        literal = 1;
-
-      if (comment)
-        {
-          if (c == '\n')
-            comment = 0;
-        }
-      else if (pos == 0)
-        {
-          if (c == '#')
-            comment = 1;
-          else if (! grub_isspace (c))
-            cmdline[pos++] = c;
-        }
-      else
-        {
-          if (c == '\n')
-            break;
-
-          if (pos < max_len)
-            cmdline[pos++] = c;
-        }
-    }
-
-  cmdline[pos] = '\0';
- - return pos;
-}
-
static void
free_menu (grub_menu_t menu)
{
@@ -125,148 +57,6 @@
  grub_free (menu);
}

-/* Read the config file CONFIG and return a menu. If no entry is present,
-   return NULL.  */
-static grub_menu_t
-read_config_file (const char *config)
-{
-  grub_file_t file;
-  static char cmdline[GRUB_MAX_CMDLINE];
-  grub_menu_t menu;
-  grub_menu_entry_t *next_entry, cur_entry = 0;
-  grub_command_list_t *next_cmd, cur_cmd;
- - /* Try to open the config file. */
-  file = grub_file_open (config);
-  if (! file)
-    return 0;
-
-  /* Initialize the menu.  */
-  menu = (grub_menu_t) grub_malloc (sizeof (*menu));
-  if (! menu)
-    {
-      grub_file_close (file);
-      return 0;
-    }
-  menu->default_entry = 0;
-  menu->fallback_entry = -1;
-  menu->timeout = -1;
-  menu->size = 0;
-  menu->entry_list = 0;
-
-  next_entry = &(menu->entry_list);
-  next_cmd = 0;
- - /* Read each line. */
-  while (get_line (file, cmdline, sizeof (cmdline)))
-    {
-      grub_command_t cmd;
- - cmd = grub_command_find (cmdline);
-      grub_errno = GRUB_ERR_NONE;
-      if (! cmd)
-        {
-          grub_printf ("Unknown command `%s' is ignored.\n", cmdline);
-          continue;
-        }
-
-      if (cmd->flags & GRUB_COMMAND_FLAG_TITLE)
-        {
-          char *p;
- - cur_entry = (grub_menu_entry_t) grub_malloc (sizeof (*cur_entry));
-          if (! cur_entry)
-            goto fail;
-
-          p = grub_strchr (cmdline, ' ');
-          if (p)
-            cur_entry->title = grub_strdup (p);
-          else
-            cur_entry->title = grub_strdup ("");
- - if (! cur_entry->title)
-            {
-              grub_free (cur_entry);
-              goto fail;
-            }
- - cur_entry->num = 0;
-          cur_entry->command_list = 0;
-          cur_entry->next = 0;
- - *next_entry = cur_entry;
-          next_entry = &(cur_entry->next);
-
-          next_cmd = &(cur_entry->command_list);
- - menu->size++;
-        }
-      else if (! cur_entry)
-        {
-          /* Run the command if possible.  */
-          if (cmd->flags & GRUB_COMMAND_FLAG_MENU)
-            {
-              grub_command_execute (cmdline);
-              grub_print_error ();
-              grub_errno = GRUB_ERR_NONE;
-            }
-          else
-            {
-              grub_printf ("Invalid command `%s' is ignored.\n", cmdline);
-              continue;
-            }
-        }
-      else
-        {
-          cur_cmd = (grub_command_list_t) grub_malloc (sizeof (*cur_cmd));
-          if (! cur_cmd)
-            goto fail;
-
-          cur_cmd->command = grub_strdup (cmdline);
-          if (! cur_cmd->command)
-            {
-              grub_free (cur_cmd);
-              goto fail;
-            }
-
-          cur_cmd->next = 0;
- - *next_cmd = cur_cmd;
-          next_cmd = &(cur_cmd->next);
- - cur_entry->num++;
-        }
-    }
-
- fail:
-
-  grub_file_close (file);
-
-  /* If no entry was found or any error occurred, return NULL.  */
-  if (menu->size == 0 || grub_errno != GRUB_ERR_NONE)
-    {
-      free_menu (menu);
-      return 0;
-    }
-
-  /* Check values of the default entry and the fallback one.  */
-  if (menu->fallback_entry >= menu->size)
-    menu->fallback_entry = -1;
-
-  if (menu->default_entry < 0 || menu->default_entry >= menu->size)
-    {
-      if (menu->fallback_entry < 0)
-        menu->default_entry = 0;
-      else
-        {
-          menu->default_entry = menu->fallback_entry;
-          menu->fallback_entry = -1;
-        }
-    }
- - return menu;
-}
-
/* This starts the normal mode.  */
void
grub_enter_normal_mode (const char *config)
@@ -285,22 +75,32 @@
               PACKAGE_VERSION);
}

+struct grub_menu pre_menu=
+  {
+     .size=0,
+     .default_entry = 0,
+     .fallback_entry = -1,
+     .timeout = -1,
+     .entry_list = 0,
+  };
+
+grub_menu_t menu = &pre_menu;
+
/* Read the config file CONFIG and execute the menu interface or
   the command-line interface.  */
void
grub_normal_execute (const char *config, int nested)
{
-  grub_menu_t menu = 0;

  if (config)
    {
-      menu = read_config_file (config);
+      script_exec_file (config,0,0);

      /* Ignore any error.  */
      grub_errno = GRUB_ERR_NONE;
    }

-  if (menu)
+  if (menu->size)
    grub_menu_run (menu, nested);
  else
    grub_cmdline_run (nested);
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x 'config*' -x kernel_syms.lst -x Makefile -x stamp-h -x symlist.c -x output.0 -x requests -x traces.0 -x '*.mk' -x cpu -x machine -x Entries --expand-tabs grub2/normal/menu.c grub2ch/normal/menu.c
--- grub2/normal/menu.c    2005-01-22 14:29:18.000000000 +0100
+++ grub2ch/normal/menu.c    2005-01-29 17:07:57.000000000 +0100
@@ -23,6 +23,7 @@
#include <grub/loader.h>
#include <grub/mm.h>
#include <grub/machine/time.h>
+#include <grub/script.h>

/* FIXME: These below are all runaround.  */

@@ -378,35 +379,7 @@
static void
run_menu_entry (grub_menu_entry_t entry)
{
-  grub_command_list_t cl;
-
-  for (cl = entry->command_list; cl != 0; cl = cl->next)
-    {
-      grub_command_t c;
-
-      if (cl->command[0] == '\0')
-        /* Ignore an empty command line.  */
-        continue;
- - c = grub_command_find (cl->command);
-      if (! c)
-        break;
- - if (! (c->flags & GRUB_COMMAND_FLAG_CMDLINE))
-        {
-          grub_error (GRUB_ERR_INVALID_COMMAND,
-                      "invalid command `%s'",
-                      cl->command);
-          break;
-        }
- - if (! (c->flags & GRUB_COMMAND_FLAG_NO_ECHO))
-        grub_printf ("%s\n", cl->command);
- - if (grub_command_execute (cl->command) != 0)
-        break;
-    }
- + script_list_execute(entry,0,0);
  if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
    /* Implicit execution of boot, only if something is loaded.  */
    grub_command_execute ("boot");
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x 'config*' -x kernel_syms.lst -x Makefile -x stamp-h -x symlist.c -x output.0 -x requests -x traces.0 -x '*.mk' -x cpu -x machine -x Entries --expand-tabs grub2/normal/script.c grub2ch/normal/script.c
--- grub2/normal/script.c    1970-01-01 01:00:00.000000000 +0100
+++ grub2ch/normal/script.c    2005-01-30 19:01:35.000000000 +0100
@@ -0,0 +1,2539 @@
+/* script.c - scripting engine */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2005  Free Software Foundation, Inc.
+ *  Copyright (C) 2005  Vladimir Serbinenko <address@hidden>
+ *
+ *  This program 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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/env.h>
+#include <grub/script.h>
+#include <grub/file.h>
+
+/*TODO:
+alpha:
+cond expr [[ ... ]], [...]
+
+beta:
+line numbers
+select,case
+local, func args and script file parameters
+expansions:
+        ${..:..},...
+        pathname
+built-in coms
+built-in vars
+``,$()
+
+gamma:
+** +pipes
+subshell,(list)
+$'...' $"..." +arr[*] address@hidden
+redirecting
+*/
+
+struct grub_menu funcs={.default_entry=0,.fallback_entry=0,.timeout=0, //dummy values
+.size=0,
+.entry_list=0 //empty list
+  };
+
+char*
+script_dupstr(char*what)
+{
+        char*rtval=grub_malloc(grub_strlen(what)+1);
+        grub_memcpy(rtval,what,grub_strlen(what)+1);
+        return rtval;
+}
+
+static char*
+script_strchr_real(char*str,char c,int rr)
+{
+  char*expcur,*rtval=0;
+  for(expcur=str;*expcur;expcur++)
+    {
+      if(*expcur==c)
+        {
+          rtval=expcur;
+          if(!rr)
+            return rtval;
+        }
+      if(*expcur=='\\')
+        {
+          expcur+=2;
+          continue;
+        }
+      if(*expcur=='(')
+        {
+          expcur+=script_find_pas('(',')',expcur);
+          continue;
+        }
+      if(*expcur=='{')
+        {
+          expcur+=script_find_pas('{','}',expcur);
+          continue;
+        }
+      if(*expcur=='[')
+        {
+          expcur+=script_find_pas('[',']',expcur);
+          continue;
+        }
+      if(*expcur=='"' || *expcur=='\'')
+        {
+          expcur+=script_get_strend(expcur);
+          continue;
+        }
+    }
+  return rtval;
+}
+
+char*
+script_strrchr(char*str,char c)
+{
+  return script_strchr_real(str,c,1);
+}
+
+char*
+script_strchr(char*str,char c)
+{
+  return script_strchr_real(str,c,0);
+}
+
+char*
+script_env_get(char*nm)
+{
+  char*rtval;
+  if(script_strrchr(nm,'['))
+    {
+      char*eptr=script_strrchr(nm,'[');
+      char*ptr=eptr+1;
+      ptr+=script_find_pas('[',']',ptr);
+      char c=*ptr,c2=*eptr;
+      *ptr=0;
+      *eptr=0;
+      enum vartype vtp;
+      char*tm=script_eval_arith(script_expand_dollar(eptr+1),&vtp);
+ rtval=script_get_arrayelem(script_env_get(nm),script_get_str(tm,vtp));
+      *ptr=c;
+      *eptr=c2;
+    }
+  else
+    rtval=grub_env_get(nm);
+  if(!rtval)
+    {
+      rtval=grub_malloc(3);
+      *rtval=0;
+    }
+  return rtval;
+}
+
+int
+script_get_strend(char*str)
+{
+        char c=str[0];int i;
+        for(i=1;str[i]!=c && str[i];i++)
+                if(str[i]=='\\')
+                        i++;
+        return i;
+}
+
+/*Finds closing brace corresponding to specificied opening. +str must point to the first character after opening brace. +cbeg and cend must contain opening and closing brace respectivelly('(' and ')' or '{' and '}') +Return vale is so that str+value points to closing brace */
+
+int
+script_find_pas(char cbeg,char cend,char *str)
+{
+        int op=1,i;
+        for(i=0;op&&str[i];i++)
+    {
+                if(str[i]=='\\')
+        {
+          i+=2;
+          continue;
+        }
+      if(str[i]=='"' || str[i]=='\'')
+        {
+          i+=script_get_strend(str+i);
+          continue;
+        }
+      if(str[i]==cbeg)op++;
+      if(str[i]==cend)op--;
+          }
+        return op?i:i-1;
+}
+void
+script_env_unset(char*nm)
+{
+        if(script_strrchr(nm,'['))
+    {
+      char*eptr=script_strrchr(nm,'[');
+      char*ptr=eptr+1;
+      ptr+=script_find_pas('[',']',ptr);
+      char c=*ptr,c2=*eptr;
+      *ptr=0;
+      *eptr=0;
+      char*arr=script_env_get(nm);
+      if(!arr)
+        return;
+      enum vartype vtp;
+      char*tm=script_eval_arith(script_expand_dollar(eptr+1),&vtp);
+      script_del_arrayelem(&arr,script_get_str(tm,vtp));
+      grub_env_set(nm,arr);
+      *ptr=c;
+      *eptr=c2;
+      return ;
+    }
+        grub_env_unset(nm);
+}
+
+void
+script_env_set(char*nm,char*val)
+{
+        if(script_strrchr(nm,'['))
+    {
+      char*eptr=script_strrchr(nm,'[');
+      char*ptr=eptr+1;
+      ptr+=script_find_pas('[',']',ptr);
+      char c=*ptr,c2=*eptr;
+      *ptr=0;
+      *eptr=0;
+      char*arr=script_env_get(nm);
+      if(!arr)
+        {
+          arr=grub_malloc(3);
+          arr[0]=0;
+        }
+      else
+        arr=script_dupstr(arr);
+      enum vartype vtp;
+      char*tm=script_eval_arith(script_expand_dollar(eptr+1),&vtp);
+      script_add_arrayelem(&arr,script_get_str(tm,vtp),script_dupstr(val));
+      grub_env_set(nm,arr);
+      *ptr=c;
+      *eptr=c2;
+      return ;
+    }
+        grub_env_set(nm,val);
+}
+
+char*
+script_get_str(char*var,enum vartype tp)
+{
+        char*rtval;
+        switch(tp)
+    {
+    case SCRIPT_STR:
+      if(var)
+        return var;
+      rtval=grub_malloc(3);
+      *rtval=0;
+      return rtval;
+    case SCRIPT_VAR_NAME:
+        {
+          char*tmp;
+          tmp=script_env_get(var);
+          grub_free(var);
+          if(!tmp)
+            {
+              rtval=grub_malloc(sizeof(char));
+              rtval[0]=0;
+              return rtval;
+            }
+          rtval=grub_malloc(sizeof(char)*(grub_strlen(tmp)+1));
+          grub_memcpy(rtval,tmp,sizeof(char)*(grub_strlen(tmp)+1));
+          return rtval;
+        }
+    }
+        return 0;
+}
+
+int
+grub_strtol(char*exp,char**end,int base)
+{
+        while(grub_isspace(*exp))
+                exp++;
+        if(*exp=='-')
+                return -grub_strtoul(exp+1,end,base);
+        else
+                return grub_strtoul(exp,end,base);
+}
+
+int
+script_strtol(char*str)
+{
+        /*TODO: base#*/
+        char*end;
+ + int rtval=grub_strtol(str,&end,0);
+        grub_free(str);
+        return rtval;
+}
+
+char*
+script_ltostr(int vl){
+        char *s=grub_malloc(12*sizeof(char)),*t=s;
+        if(vl<0)
+                *(t++)='-',vl=-vl;
+        grub_sprintf(t,"%d",vl);
+        return s;
+}
+
+char*
+script_getnum(char**exp)
+{
+        return script_ltostr(grub_strtol(*exp,exp,0));
+}
+
+/*operator {}*/
+char*
+script_char_str(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        int n=script_strtol(b);
+        char *rtval=grub_malloc(3*sizeof(char));
+        rtval[1]=0;
+        rtval[0]=(n<0 || grub_strlen(a)>=(unsigned)n)?0:a[n];
+        return rtval;
+}
+
+int
+script_get_bool(char*a)
+{
+ int rtval=a && (grub_isdigit(a[0]) || (a[0]!='-' && !grub_isdigit(a[1]))) && grub_strcmp(a,"0")
+    && grub_strcmp(a,"-0");
+        grub_free(a);
+        return rtval;
+}
+
+/*Operator !*/
+char*
+script_bool_not(char*a,char*b __attribute__ ((unused)),int opn __attribute__ ((unused)))
+{
+        char *rtval=grub_malloc(3*sizeof(char));
+        rtval[1]=0;
+        if(!script_get_bool(a))
+                rtval[0]='1';
+        else
+                rtval[0]='0';
+        return rtval;
+}
+
+/*Operator ~*/
+char*
+script_bin_not(char*a,char*b __attribute__ ((unused)),int opn __attribute__ ((unused)))
+{
+        return script_ltostr(!script_strtol(a));
+}
+
+/*Unary -*/
+char*
+script_neg(char*a,char*b __attribute__ ((unused)),int opn __attribute__ ((unused)))
+{
+        return script_ltostr(-script_strtol(a));
+}
+/*Unary +*/
+char*
+script_pos(char*a,char*b __attribute__ ((unused)),int opn __attribute__ ((unused)))
+{
+        return script_ltostr(-script_strtol(a));
+}
+
+/*Binary +*/
+char*
+script_add(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        return script_ltostr(script_strtol(a)+script_strtol(b));
+}
+
+/*Binary +*/
+char*
+script_sub(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        return script_ltostr(script_strtol(a)-script_strtol(b));
+}
+
+/*Binary **/
+char*
+script_mult(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        return script_ltostr(script_strtol(a)*script_strtol(b));
+}
+
+/*Binary /*/
+char*
+script_div(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        return script_ltostr(script_strtol(a)/script_strtol(b));
+}
+
+/*Binary %*/
+char*
+script_mod(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        return script_ltostr(script_strtol(a)%script_strtol(b));
+}
+
+/*Binary <<*/
+char*
+script_binl(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        return script_ltostr(script_strtol(a)<<script_strtol(b));
+}
+
+/*Binary >>*/
+char*
+script_binr(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        return script_ltostr(script_strtol(a)>>script_strtol(b));
+}
+
+/*Operators >, <, <=, >=*/
+char*
+script_cmpop(char*a,char*b,int opn)
+{
+        char*rtval=grub_malloc(3*sizeof(char));
+        int cmpval=grub_strcmp(a,b);
+        if(script_opers[opn].seq[1]=='=' && cmpval==0)
+    {
+      rtval[0]='1';
+      return rtval;
+    }
+        if(script_opers[opn].seq[0]=='<')
+                rtval[0]=(cmpval<0)?'1':'0';
+        else
+                rtval[0]=(cmpval>0)?'1':'0';
+        return rtval;
+}
+
+/*Operators !=,==,<>*/
+char*
+script_eqop(char*a,char*b,int opn)
+{
+        int cnt=1;
+        char*rtval=grub_malloc(3*sizeof(char));
+        rtval[1]=0;
+        if(cnt && grub_strcmp(a,b)!=0)
+                cnt=0;
+        if(script_opers[opn].seq[0]=='!' || script_opers[opn].seq[0]=='<')
+                cnt=!cnt;
+        rtval[0]=cnt?'1':'0';
+        return rtval;
+}
+
+/*Binary  ^*/
+char*
+script_bxor(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        return script_ltostr(script_strtol(a)^script_strtol(b));
+}
+/*Binary  |*/
+char*
+script_bor(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        return script_ltostr(script_strtol(a)|script_strtol(b));
+}
+
+/*Binary  &*/
+char*
+script_band(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        return script_ltostr(script_strtol(a)&script_strtol(b));
+}
+
+/*logic xor*/
+char*
+script_logicxor(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        char *rtval=grub_malloc(3*sizeof(char));
+        rtval[1]=0;
+        if(script_get_bool(a)!=script_get_bool(b))
+                rtval[0]='1';
+        else
+                rtval[0]='0';
+        return rtval;
+}
+
+/*Operator ,*/
+char*
+script_comma(char*a __attribute__ ((unused)),char*b,
+                        int opn __attribute__ ((unused)))
+{
+        return b;
+}
+
+/*Operator =*/
+char*
+script_set(char*a, char*b,int opn __attribute__ ((unused)))
+{
+        script_env_set(a,b);
+        return a;
+}
+
+/*Operators  ...=*/
+char*
+script_setop(char*a, char*b,int opn)
+{
+        char tm[3]={0,0,0};
+        char*val=script_dupstr(a);
+        tm[0]=script_opers[opn].seq[0];
+        if(script_opers[opn].seq[1]!='=')
+                tm[1]=script_opers[opn].seq[1];
+        int op=script_find_oper(tm,0);
+ script_env_set(a,script_opers[op].func_do(script_get_str(val,SCRIPT_VAR_NAME),b,op));
+        return a;
+}
+
+/*Operator .*/
+char*
+script_concat(char*a,char*b,int opn __attribute__ ((unused)))
+{
+        grub_realloc(a,grub_strlen(a)+grub_strlen(b));
+        grub_memcpy(a+grub_strlen(a),b,grub_strlen(b)+1);
+        grub_free(b);
+        return a;
+}
+static char*
+script_incl(char*a,char*b __attribute__((unused)),int op __attribute__((unused)))
+{
+        int intval;
+        char*val=script_dupstr(a);
+ script_env_set(val,script_ltostr((intval=script_strtol(script_get_str(a,SCRIPT_VAR_NAME)))+1));
+        grub_free(val);
+        return script_ltostr(intval+1);
+}
+static char*
+script_decl(char*a,char*b __attribute__((unused)),int op __attribute__((unused)))
+{
+        int intval;
+        char*val=script_dupstr(a);
+ script_env_set(val,script_ltostr((intval=script_strtol(script_get_str(a,SCRIPT_VAR_NAME)))-1));
+        grub_free(val);
+        return script_ltostr(intval-1);
+}
+static char*
+script_incr(char*a,char*b __attribute__((unused)),int op __attribute__((unused)))
+{
+        int intval;
+        char*val=script_dupstr(a);
+ script_env_set(val,script_ltostr((intval=script_strtol(script_get_str(a,SCRIPT_VAR_NAME)))+1));
+        grub_free(val);
+        return script_ltostr(intval);
+}
+static char*
+script_decr(char*a,char*b __attribute__((unused)),int op __attribute__((unused)))
+{
+        int intval;
+        char*val=script_dupstr(a);
+ script_env_set(val,script_ltostr((intval=script_strtol(script_get_str(a,SCRIPT_VAR_NAME)))-1));
+        grub_free(val);
+        return script_ltostr(intval);
+}
+/*Array of possible operators*/
+struct script_oper script_opers[]={
+//{.priority=190, .seq="[", .func_do=script_elemarray, .type=SCRIPT_BRACK|SCRIPT_LVALUE},
+{.priority=190, .seq="{", .func_do=script_char_str, .type=SCRIPT_BRACK},
+{.priority=180, .seq="!", .func_do=script_bool_not, .type=SCRIPT_LEFT|SCRIPT_RASSOC}, +{.priority=180, .seq="~", .func_do=script_bin_not, .type=SCRIPT_LEFT|SCRIPT_RASSOC}, +{.priority=180, .seq="++", .func_do=script_incl, .type=SCRIPT_LEFT|SCRIPT_NEEDLVALUEA|SCRIPT_RASSOC}, +{.priority=180, .seq="++", .func_do=script_incr, .type=SCRIPT_RIGHT|SCRIPT_NEEDLVALUEA}, +{.priority=180, .seq="--", .func_do=script_decl, .type=SCRIPT_LEFT|SCRIPT_NEEDLVALUEA|SCRIPT_RASSOC}, +{.priority=180, .seq="--", .func_do=script_decr, .type=SCRIPT_RIGHT|SCRIPT_NEEDLVALUEA}, +{.priority=180, .seq="-", .func_do=script_neg, .type=SCRIPT_LEFT|SCRIPT_RASSOC}, +{.priority=180, .seq="+", .func_do=script_pos, .type=SCRIPT_LEFT|SCRIPT_RASSOC},
+{.priority=170, .seq="*", .func_do=script_mult, .type=SCRIPT_BIN},
+{.priority=170, .seq="/", .func_do=script_div, .type=SCRIPT_BIN},
+{.priority=170, .seq="%", .func_do=script_mod, .type=SCRIPT_BIN},
+{.priority=160, .seq="+", .func_do=script_add, .type=SCRIPT_BIN},
+{.priority=160, .seq="-", .func_do=script_sub, .type=SCRIPT_BIN},
+{.priority=160, .seq=".", .func_do=script_concat, .type=SCRIPT_BIN},
+{.priority=150, .seq=">>", .func_do=script_binr, .type=SCRIPT_BIN}, +{.priority=150, .seq="<<", .func_do=script_binl, .type=SCRIPT_BIN},
+{.priority=140, .seq="<=", .func_do=script_cmpop, .type=SCRIPT_BIN},
+{.priority=140, .seq="<", .func_do=script_cmpop, .type=SCRIPT_BIN},
+{.priority=140, .seq=">=", .func_do=script_cmpop, .type=SCRIPT_BIN},
+{.priority=140, .seq=">", .func_do=script_cmpop, .type=SCRIPT_BIN},
+{.priority=130, .seq="==", .func_do=script_eqop, .type=SCRIPT_BIN},
+{.priority=130, .seq="!=", .func_do=script_eqop, .type=SCRIPT_BIN},
+{.priority=130, .seq="<>", .func_do=script_eqop, .type=SCRIPT_BIN},
+{.priority=120, .seq="&", .func_do=script_band, .type=SCRIPT_BIN},
+{.priority=110, .seq="^", .func_do=script_bxor, .type=SCRIPT_BIN},
+{.priority=100, .seq="|", .func_do=script_bor, .type=SCRIPT_BIN},
+{.priority=90, .seq="&&", .func_do=0, .type=SCRIPT_AND},
+{.priority=80, .seq="||", .func_do=0, .type=SCRIPT_OR},
+{.priority=70, .seq="?", .func_do=0, .type=SCRIPT_TERN},//? :
+{.priority=60, .seq="=", .func_do=script_set, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq="+=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq="-=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq="*=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq="/=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq="%=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq="&=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq="^=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq="|=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq=">>=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq="<<=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, +{.priority=60, .seq=".=", .func_do=script_setop, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=40, .seq="and", .func_do=0, .type=SCRIPT_AND},
+{.priority=30, .seq="xor", .func_do=script_logicxor, .type=SCRIPT_BIN},
+{.priority=20, .seq="or", .func_do=0, .type=SCRIPT_OR},
+{.priority=10, .seq=",", .func_do=script_comma, .type=SCRIPT_BIN},
+};
+
+int
+script_islexend(char c)
+{
+        return !(c &&(grub_isalpha(c) ||grub_isdigit(c) ||c=='_'));
+}
+
+int
+script_isfuncbeg(char*str)
+{
+        while(*str && grub_isspace(*str))str++;
+        if(!*str)
+                return 0;
+ if(!grub_memcmp(str,"function",sizeof("function")-1) && script_islexend(str[sizeof("function")-1]))
+                return 1;
+ if(!grub_memcmp(str,"entry",sizeof("entry")-1) && script_islexend(str[sizeof("entry")-1]))
+                return 1;
+        while(*str && !script_islexend(*str))str++;
+        if(!*str)
+                return 0;
+        if(*str!='(')
+                return 0;
+        str++;
+        if(!*str)
+                return 0;
+        while(*str && grub_isspace(*str))str++;
+        if(!*str)
+                return 0;
+        if(*str!=')')
+                return 0;
+        return 1;
+}
+void
+script_skipfuncbeg(char**exp)
+{
+        while(**exp && grub_isspace(**exp))(*exp)++;
+ if(!grub_memcmp(*exp,"entry",sizeof("entry")-1) && script_islexend((*exp)[sizeof("entry")-1]))
+                *exp+=sizeof("entry")-1;
+ if(!grub_memcmp(*exp,"function",sizeof("function")-1) && script_islexend((*exp)[sizeof("function")-1]))
+                *exp+=sizeof("function")-1;
+        switch(**exp)
+    {
+    case '"':
+    case '\'':
+      *exp+=script_get_strend(*exp)+1;
+      break;
+    default:
+      while(!script_islexend(**exp))
+        (*exp)++;
+    }
+        while(grub_isspace(**exp))(*exp)++;
+        if(**exp=='(')(*exp)++;//skip (
+        while(grub_isspace(**exp))(*exp)++;
+        if(**exp==')')(*exp)++;//skip )
+}
+
+
+int
+script_find_oper(char*exp,int searchleft)
+{
+        unsigned i, lenfound=0;int foundn=-1;
+        for(i=0;i<sizeof(script_opers)/sizeof(script_opers[0]);i++)
+                if(grub_strlen(script_opers[i].seq)>lenfound &&
+ ((searchleft==((script_opers[i].type&SCRIPT_ARGPART)==SCRIPT_LEFT)) || (searchleft==2)) + && !grub_memcmp(script_opers[i].seq,exp,grub_strlen(script_opers[i].seq)) + &&(script_islexend(exp[grub_strlen(script_opers[i].seq)-1]
+      ||script_islexend(exp[grub_strlen(script_opers[i].seq)]))))
+ foundn=i,lenfound=grub_strlen(script_opers[i].seq);
+        return foundn;
+}
+
+char*
+script_list_arrayelems(char**elem)
+{
+        char*indxbeg,*indxend;
+        if(!**elem)
+                return 0;
+        while(grub_isspace(**elem))(*elem)++;
+        if(**elem!='[')
+                return 0;
+        (*elem)++;
+        if(**elem!='\'')
+                return 0;
+        indxbeg=*elem+1;
+        *elem+=script_get_strend(*elem);
+        indxend=*elem;
+        (*elem)++;
+        if(**elem!=']')
+                return 0;
+        (*elem)++;
+        if(**elem!='=')
+                return 0;
+        (*elem)++;
+        if(**elem!='\'')
+                return 0;
+        *elem+=script_get_strend(*elem);
+        (*elem)++;
+        char*rtval=grub_malloc(indxend-indxbeg+1);
+        grub_memcpy(rtval,indxbeg,indxend-indxbeg);
+        rtval[indxend-indxbeg]=0;
+        return rtval;
+}
+char*
+script_get_arrayelem(char*elem,char*indx)
+{
+        char*escindx=script_escape_string(indx);
+        grub_free(indx);
+        char*indxbeg,*indxend;
+        char*valbeg=0,*valend=0;
+        while(1)
+    {
+      if(!*elem)
+        return 0;
+      while(grub_isspace(*elem))elem++;
+      if(*elem!='[')
+        return 0;
+      elem++;
+      if(*elem!='\'')
+        return 0;
+      indxbeg=elem+1;
+      elem+=script_get_strend(elem);
+      indxend=elem;
+      elem++;
+      if(*elem!=']')
+        return 0;
+      elem++;
+      if(*elem!='=')
+        return 0;
+      elem++;
+      if(*elem!='\'')
+        return 0;
+      valbeg=elem+1;
+      elem+=script_get_strend(elem);
+      valend=elem;
+      elem++;
+ if((unsigned)(indxend-indxbeg)==grub_strlen(escindx) && !grub_memcmp(indxbeg,escindx,indxend-indxbeg))
+        {
+          char*rtval=grub_malloc(valend-valbeg+1);
+          grub_memcpy(rtval,valbeg,valend-valbeg);
+          rtval[valend-valbeg]=0;
+          script_unescape(rtval);
+          return rtval;
+        }
+    }
+}
+#define STR_BUFFER 256
+char*
+script_escape_string(char*str)
+{
+        char*res=grub_malloc(STR_BUFFER),*rptr=res;
+        char*ptr=str;
+        while(*ptr)
+    {
+      if((rptr-res+2)%STR_BUFFER==0)
+        {
+          int delta=rptr-res;
+          res=grub_realloc(res,rptr-res+2+STR_BUFFER);
+          rptr=res+delta;
+        }
+      if(*ptr=='\'' || *ptr=='\\')
+        *(rptr++)='\\';
+      *(rptr++)=*(ptr++);
+    }
+        *(rptr++)=*(ptr++);
+        return res;
+}
+void
+script_del_arrayelem(char**arr,char*indx)
+{
+        char*escindx=script_escape_string(indx);
+        grub_free(indx);
+        char*arptr=*arr;
+        char*prevarptr=*arr;
+        char*curindx;
+        int wfnd=0;
+        while(*arptr)
+    {
+      prevarptr=arptr;
+      curindx=script_list_arrayelems(&arptr);
+      if(!curindx)
+        break;
+      if(!grub_strcmp(escindx,curindx))
+        {
+          grub_free(curindx);
+          wfnd=1;
+          break;
+        }
+      grub_free(curindx);
+    }
+        if(wfnd)
+                while(*arptr)
+                        *(prevarptr++)=*(arptr++);
+        else
+                prevarptr=arptr;
+        int delta=prevarptr-*arr;
+        *arr=grub_realloc(*arr,delta+1);
+        (*arr)[delta]=0;
+}
+void
+script_add_arrayelem(char**arr,char*indx,char*val)
+{
+        char*escval=script_escape_string(val);
+        char*escindx=script_escape_string(indx);
+        grub_free(indx);
+        grub_free(val);
+        char*arptr=*arr;
+        char*prevarptr=*arr;
+        char*curindx;
+        int wfnd=0;
+        while(*arptr)
+    {
+      prevarptr=arptr;
+      curindx=script_list_arrayelems(&arptr);
+      if(!curindx)
+        break;
+      if(!grub_strcmp(escindx,curindx))
+        {
+          grub_free(curindx);
+          wfnd=1;
+          break;
+        }
+      grub_free(curindx);
+    }
+        if(wfnd)
+                while(*arptr)
+                        *(prevarptr++)=*(arptr++);
+        else
+                prevarptr=arptr;
+        int delta=prevarptr-*arr;
+ *arr=grub_realloc(*arr,delta+grub_strlen(escindx)+grub_strlen(escval)+9);
+        char*ptr=*arr+delta;
+        ptr[0]=' ';
+        ptr[1]='[';
+        ptr[2]='\'';
+        ptr+=3;
+        grub_memcpy(ptr,escindx,grub_strlen(escindx));
+        ptr+=grub_strlen(escindx);
+        ptr[0]='\'';
+        ptr[1]=']';
+        ptr[2]='=';
+        ptr[3]='\'';
+        ptr+=4;
+        grub_memcpy(ptr,escval,grub_strlen(escval));
+        ptr+=grub_strlen(escval);
+        ptr[0]='\'';
+        ptr[1]=0;
+}
+
+void
+script_unescape(char*str)
+{
+        char*to=str,*from=str;
+        while(*from)
+    {
+      if(*to=='\\')
+        {
+          from++;
+          switch(*(from++))
+            {
+            case 'n':
+              *(to++)='\n';
+              break;
+            case 'r':
+              *(to++)='\r';
+              break;
+            case 't':
+              *(to++)='\t';
+              break;
+            case 'x':
+              *(to++)=grub_strtoul(from,&from,16);
+              break;
+            default:
+              if(*(from-1)>='0' && *(from-1)<='7')
+                {
+                  *(to++)=grub_strtoul(from-1,&from,16);
+                  break;
+                }
+              *(to++)=*(from-1);
+            }
+        }
+      *(to++)=*(from++);
+    }
+        *to=0;
+}
+
+char*
+script_get_singlestring(char**exp)
+{
+        char*rtval=grub_malloc(STR_BUFFER);
+        int j;
+        for(j=0;**exp!='\'' && **exp;(*exp)++)
+    {
+      if((j+1)%STR_BUFFER==0)
+        rtval=grub_realloc(rtval,j+1+STR_BUFFER);
+      if(**exp=='\\')
+        {
+          switch(*((*exp)++))
+            {
+            case '\n':
+              break;
+            case '\'':
+            case '\\':
+              rtval[j++]=**exp;
+              break;
+            default:
+              rtval[j++]='\\';
+              rtval[j++]=**exp;
+            }
+        }
+      else
+        rtval[j++]=**exp;
+    }
+        rtval[j]=0;
+        (*exp)++;
+        return rtval;
+}
+
+char*
+script_get_doublestring(char**exp)
+{
+        char*rtval=grub_malloc(STR_BUFFER);
+        int j;char *end;
+        for(j=0;**exp!='"' && **exp!=0;(*exp)++,j++)
+    {
+      if((j+1)%STR_BUFFER==0)
+        rtval=grub_realloc(rtval,j+1+STR_BUFFER);
+      if(**exp=='\\')
+        {
+          switch(*(*exp+1))
+            {
+            case '\n':
+              j--;
+              break;
+            case 'n':
+              rtval[j]='\n';
+              break;
+            case 'r':
+              rtval[j]='\r';
+              break;
+            case 'x':
+              rtval[j]=grub_strtoul(*exp+2,&end,16);
+              *exp=end-2;
+              break;
+            case 't':
+              rtval[j]='\t';
+ break; + case '\'':
+            case '\\':
+            case '"':
+            case '$':
+              rtval[j]=*(*exp+1);
+              break;
+            default:
+              if(*(*exp+1)>='0' && *(*exp+1)<='7')
+                {
+                  rtval[j]=grub_strtoul(*exp+1,&end,8);
+                  *exp=end-2;
+                }
+              else
+                {
+                  rtval[j]='\\';
+                  (*exp)--;
+                }
+            }
+          (*exp)++;
+        }
+      else
+        rtval[j]=**exp;
+    }
+        rtval[j]=0;
+        (*exp)++;
+        return rtval;
+}
+#if 0 //Some problems with GRUB device notation
+char*
+script_get_array(char*exp,char**cont,int contcnt)
+{
+  char*rtval=grub_malloc(3);
+  rtval[0]=0;
+  int ptr=0;
+  char*expcur=script_dupstr(exp);
+  char*exp0;
+  int maxindx=-1;
+  void arr_putc(char c)
+    {
+      if((ptr+2)%STR_BUFFER==0)
+        rtval=grub_realloc(rtval,(ptr+2)+STR_BUFFER);
+      rtval[ptr++]=c;
+    }
+  char**ct;
+  for(ct=cont;ct-cont<contcnt;ct++)
+    {
+      expcur=grub_realloc(expcur,grub_strlen(expcur)+grub_strlen(*ct)+1);
+      expcur[grub_strlen(expcur)+grub_strlen(*ct)]=0;
+      grub_memcpy(expcur+grub_strlen(expcur),*ct,grub_strlen(*ct));
+    }
+  exp0=expcur;
+  while(*expcur && *expcur!=')')
+    {
+      char*indx;
+      if(grub_isspace(*expcur))
+        {
+          expcur++;
+          continue;
+        }
+      if(*expcur=='[')
+        {
+          char*expend=expcur+1+script_find_pas('[',']',expcur+1);
+          char c=*expend;
+          char*end;
+          enum vartype vtp;
+          *expend=0;
+          char*tm=script_eval_arith(expcur+1,&vtp);
+          indx=script_get_str(tm,vtp);
+          char *t=indx;
+          int z=-1;
+          while(*t && grub_isdigit(*t))t++;
+          if(!*t)
+            z=grub_strtoul(indx,&end,0);
+          if(z>maxindx)
+            maxindx=z;
+          *expend=c;
+          expcur=expend+1;
+          while(grub_isspace(*expcur))expcur++;
+          expcur++;
+        }
+      else
+        indx=script_ltostr(++maxindx);
+      while(grub_isspace(*expcur))
+        expcur++;
+        {
+          char *expbeg=expcur;
+          int brack=0;
+          while((!grub_isspace(*expcur)&&*expcur!=')') || brack!=0)
+          {
+            if(*expcur=='\\')
+            {
+              expcur+=2;
+              continue;
+            }
+            if(*expcur=='(' || *expcur=='[' || *expcur=='{')
+              brack++;
+            if(*expcur==')' || *expcur==']' || *expcur=='}')
+              brack--;
+            if(*expcur=='"' || *expcur=='\'')
+              expcur+=script_get_strend(expcur);
+            expcur++;
+          }
+          char*expcpy=grub_malloc(expcur-expbeg+1);
+          grub_memcpy(expcpy,expbeg,expcur-expbeg);
+          expcpy[expcur-expbeg]=0;
+          script_unescape(expcpy);
+          script_add_arrayelem(&rtval,indx,expcpy);
+        }
+    }
+ grub_free(exp0); + return rtval;
+}
+#endif
+char*
+script_eval_arith(char*exp,enum vartype*vtp)
+{
+        char*cur=0;
+        char*expcur=exp;
+        *vtp=SCRIPT_STR;
+        while(*expcur)
+    {
+      if(!*expcur)
+        return cur;
+      if(grub_isspace(*expcur))
+        {
+          expcur++;
+          continue;
+        }
+      int op=script_find_oper(expcur,!cur);
+      if(op!=-1)
+        {
+          int newop=0,unary;char*tern1=expcur;
+          char*expbeg;
+          expcur+=grub_strlen(script_opers[op].seq);
+          expbeg=expcur;
+          switch(script_opers[op].type&SCRIPT_ARGPART)
+            {
+            case SCRIPT_BRACK:
+ expcur+=script_find_pas(script_opers[op].seq[0],(script_opers[op].seq[0]=='['?']':'}'),expcur);
+              break;
+            case SCRIPT_RIGHT:
+              break;
+            case SCRIPT_TERN:
+              for(;*expcur;expcur++)
+                {
+                  if(*expcur==':')
+                    break;
+ if(grub_isalpha(*expcur)||grub_isdigit(*expcur)||*expcur=='_')
+                    unary=0;
+                  if(*expcur=='(')
+                    expcur+=script_find_pas('(',')',expcur),unary=0;
+                  if(*expcur=='{')
+                    expcur+=script_find_pas('{','}',expcur),unary=0;
+                  if(*expcur=='[')
+                    expcur+=script_find_pas('[',']',expcur),unary=0;
+                  if(*expcur=='"' || *expcur=='\'')
+                    {
+                      expcur+=script_get_strend(expcur),unary=0;
+                      continue;
+                    }
+                }
+              tern1=expcur;
+              expcur++;
+            case SCRIPT_LEFT:
+            case SCRIPT_BIN:
+            case SCRIPT_AND:
+            case SCRIPT_OR:
+              unary=1;
+              for(;*expcur;expcur++)
+                {
+                  newop=script_find_oper(expcur,unary);
+                  if(newop!=-1 &&!unary)
+                    unary=1;
+ if(newop!=-1 && (script_opers[newop].priority<script_opers[op].priority || + (script_opers[newop].priority==script_opers[op].priority
+                    && !(script_opers[op].type&SCRIPT_RASSOC)) ) )
+                    break;
+ if(grub_isalpha(*expcur)||grub_isdigit(*expcur)||*expcur=='_')
+                    unary=0;
+                  if(*expcur=='(')
+                    {
+                      expcur+=script_find_pas('(',')',expcur),unary=0;
+                      continue;
+                    }
+                  if(*expcur=='{')
+                    {
+                      expcur+=script_find_pas('{','}',expcur),unary=0;
+                      continue;
+                    }
+                  if(*expcur=='[')
+                    {
+                      expcur+=script_find_pas('[',']',expcur),unary=0;
+                      continue;
+                    }
+                  if(*expcur=='"' || *expcur=='\'')
+                    {
+                      expcur+=script_get_strend(expcur),unary=0;
+                      continue;
+                    }
+                }
+            }
+          char c=*expcur;
+          *expcur=0;
+          switch(script_opers[op].type&SCRIPT_ARGPART)
+            {
+            case SCRIPT_TERN:
+              {
+                char c2;
+                int ncur=script_get_bool(script_get_str(cur,*vtp));
+                if(ncur)
+                  {
+                    c2=*tern1;
+                    *tern1=0;
+                    cur=script_eval_arith(expbeg,vtp);
+                    *tern1=c2;
+                  }
+                else
+                  cur=script_eval_arith(tern1+1,vtp);
+              }
+              break;
+            case SCRIPT_OR:
+            case SCRIPT_AND:
+              {
+                int ncur=script_get_bool(script_get_str(cur,*vtp));
+ if(ncur==((script_opers[op].type&SCRIPT_ARGPART)==SCRIPT_AND))
+                  {
+                    cur=script_eval_arith(expbeg,vtp);
+                    ncur=script_get_bool(script_get_str(cur,*vtp));
+                  }
+                cur=script_ltostr(ncur);
+                *vtp=SCRIPT_STR;
+              }
+              break;
+            case SCRIPT_RIGHT:
+              {
+ if((script_opers[op].type&SCRIPT_NEEDLVALUEA) && *vtp==SCRIPT_STR)
+                  {
+ grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: Lvalue needed for %s",script_opers[op].seq);
+                    return 0;
+                  }
+                cur=script_opers[op].func_do(
+ (script_opers[op].type&SCRIPT_NEEDLVALUEA)?cur:script_get_str(cur,*vtp),0,op);
+              }
+ *vtp=(script_opers[op].type&SCRIPT_LVALUE)?SCRIPT_VAR_NAME:SCRIPT_STR;
+              break;
+            default:
+              {
+                enum vartype rtype;
+                char*right=script_eval_arith(expbeg,&rtype);
+                if(!right)
+                  {
+ grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected end of expression");
+                    return 0;
+                  }
+                if((script_opers[op].type&SCRIPT_ARGPART)==SCRIPT_LEFT)
+                  {
+ if((script_opers[op].type&SCRIPT_NEEDLVALUEA) && rtype==SCRIPT_STR)
+                      {
+ grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: Lvalue needed for %s",script_opers[op].seq);
+                        return 0;
+                      }
+                    cur=script_opers[op].func_do(
+ (script_opers[op].type&SCRIPT_NEEDLVALUEA)?right:script_get_str(right,rtype),0,op);
+                  }
+                else
+                  {
+ if((script_opers[op].type&SCRIPT_NEEDLVALUEA) && *vtp==SCRIPT_STR)
+                      {
+ grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: Lvalue needed for %s",script_opers[op].seq);
+                        return 0;
+                      }
+                    cur=script_opers[op].func_do(
+ (script_opers[op].type&SCRIPT_NEEDLVALUEA)?cur:script_get_str(cur,*vtp),
+                      script_get_str(right,rtype),op);
+                  }
+                }
+ *vtp=(script_opers[op].type&SCRIPT_LVALUE)?SCRIPT_VAR_NAME:SCRIPT_STR;
+              break;
+            }
+          *expcur=c;
+          if((script_opers[op].type&SCRIPT_ARGPART)==SCRIPT_BRACK)
+            expcur++;
+          continue;
+        }
+      if(grub_isalpha(*expcur))
+        {
+          char*nmbeg=expcur;
+          char t;
+ while(grub_isalpha(*expcur) || grub_isdigit(*expcur) || *expcur=='_')
+            expcur++;
+          t=*expcur;
+          *expcur=0;
+          *vtp=SCRIPT_VAR_NAME;
+          cur=grub_malloc(expcur-nmbeg+1);
+          grub_memcpy(cur,nmbeg,expcur-nmbeg+1);
+          *expcur=t;
+          continue;
+        }
+      if(*expcur=='(')
+        {
+          expcur++;
+          char*expbeg=expcur;
+          char c;
+          expcur+=script_find_pas('(',')',expbeg);
+          c=*expcur;
+          *expcur=0;
+          cur=script_eval_arith(expbeg,vtp);
+          *expcur=c;
+          if(*expcur)
+            expcur++;
+          continue;
+        }
+      if(*expcur=='[')
+        {
+          expcur++;
+          char*expbeg=expcur;
+          char c;
+          char *indx;
+          enum vartype rttype;
+          expcur+=script_find_pas('[',']',expbeg);
+          c=*expcur;
+          *expcur=0;
+          char*tm=script_eval_arith(expbeg,&rttype);
+          indx=script_escape_string(script_get_str(tm,rttype));
+          *expcur=c;
+          if(*expcur)
+            expcur++;
+          if(*vtp==SCRIPT_VAR_NAME)
+            {
+              int curlen=grub_strlen(cur),indxlen=grub_strlen(indx);
+              cur=grub_realloc(cur,curlen+indxlen+5);
+              cur[curlen]='[';
+              cur[curlen+1]='\'';
+              grub_memcpy(cur+curlen+2,indx,indxlen);
+              cur[curlen+2+indxlen]='\'';
+              cur[curlen+3+indxlen]=']';
+              cur[curlen+4+indxlen]=0;
+            }
+          continue;
+        }
+      if(grub_isdigit(*expcur))
+        {
+          cur=script_getnum(&expcur);
+          continue;
+        }
+      if(*expcur=='"')
+        {
+          expcur++;
+          cur=script_get_doublestring(&expcur);
+          *vtp=SCRIPT_STR;
+          continue;
+        }
+      if(*expcur=='\'')
+        {
+          expcur++;
+          cur=script_get_singlestring(&expcur);
+          *vtp=SCRIPT_STR;
+          continue;
+        }
+    }
+        return cur;
+}
+
+char**
+script_split_tokens(char*cmdline,int*argc,grub_err_t (* getline) (char **),char**end)
+{
+  char *rd = (char *) cmdline;
+  char**argret=grub_malloc(sizeof(char*));
+  int wor=0,wand=0;
+ enum stat {STAT_NORM,STAT_QUOTE,STAT_DQUOTE,STAT_DOLLAR_BRACK,STAT_DOLLAR_BRACE};
+  enum stat status=STAT_NORM;
+  int ptr=0;
+  int esc=0;
+  int brack=0;
+  int fbrack=0;
+  int wasd=0;
+  int wnw=1;//1 at the begin of word, 0 otherwise
+ /* Get one character from the commandline.  If the caller reads
+     beyond the end of the string a new line will be read.  This
+     function will not chech for errors, the caller has to check for
+     grub_errno.  */
+  char getchar (void)
+    {
+      int c;
+
+      if (! rd)
+        {
+          if(getline)
+            getline (&rd);
+          else
+            return 0;
+          /* Error is ignored here, the caller will check for this
+          when it reads beyond the EOL.  */
+          c = *(rd)++;
+          return c;
+        }
+ + c = *(rd)++;
+      if (! c)
+       {
+        rd = 0;
+        return '\n';
+       }
+
+      return c;
+    }
+  void putchar(char c)
+    {
+      if(!wnw || !grub_isspace(c))
+        {
+          if((ptr+1)%EXPAND_BUF_SIZE==0)
+ argret[*argc]=grub_realloc(argret[*argc],ptr+1+EXPAND_BUF_SIZE);
+          (argret[*argc])[ptr++]=c;
+        }
+      wnw=0;
+    }
+  void newword()
+    {
+      if(ptr)
+        {
+          putchar(0);
+          argret=grub_realloc(argret,(*argc+2)*sizeof(char*));
+          argret[++(*argc)]=grub_malloc(EXPAND_BUF_SIZE);
+          ptr=0;
+          wnw=1;
+        }
+    }
+  *argc=0;
+  argret[0]=grub_malloc(EXPAND_BUF_SIZE);
+ + while(1)
+    {
+      char c;
+      c=getchar();
+      if(wasd&&c=='{' && status==STAT_NORM && fbrack==-1)
+        status=STAT_DOLLAR_BRACE;
+      if(wasd&&c=='(' && status==STAT_NORM && fbrack==-1)
+        {
+          brack=0;
+          status=STAT_DOLLAR_BRACK;
+        }
+      if(c==')' && !esc && brack==1 && status==STAT_DOLLAR_BRACK)
+        {
+          status=STAT_NORM;
+          brack=0;
+          putchar(c);
+          newword();
+          continue;
+        }
+      if(c=='}' && !esc && status==STAT_DOLLAR_BRACE)
+        {
+          status=STAT_NORM;
+          brack=0;
+          putchar(c);
+          newword();
+          continue;
+        }
+      wasd=(c=='$');
+      if(wnw&&grub_isspace(c)&&c!='\n')
+        continue;
+      wnw=0;
+      if(fbrack!=-1 && fbrack!=2 && c=='(')
+        fbrack++;
+      if(c!='(' && fbrack!=2)
+        fbrack=-1;
+      if(c=='(' && (status==STAT_NORM||status==STAT_DOLLAR_BRACK))
+        brack++;
+      if(c==')' && (status==STAT_NORM ||status==STAT_DOLLAR_BRACK))
+        brack--;
+      if(!esc && status==STAT_NORM
+        && (grub_isspace(c) || c==';' || c=='<' || c=='>')
+        && !brack && fbrack==-1)
+          {
+            newword();
+            if(c==';' || c=='\n')
+              break;
+            if(!grub_isspace(c))
+              {
+                putchar(c);
+                newword();
+              }
+            continue;
+          }
+ if(!esc && (c=='#'||(c=='|'&&wor)||(c=='&'&&wand)) && status==STAT_NORM && fbrack==-1)
+        break;
+      if(!brack && fbrack!=-1)
+        break;
+      if(wor)
+        {
+          newword();
+          putchar('|');
+          newword();
+          wor=0;
+        }
+      if(wand)
+        {
+          newword();
+          putchar('&');
+          newword();
+          wand=0;
+        }
+      if(c=='|' && fbrack==-1)
+        {
+          wor=1;
+          continue;
+        }
+      if(c=='&'&& fbrack==-1)
+        {
+          wand=1;
+          continue;
+        }
+      if(c=='"'&&(status==STAT_NORM ||status==STAT_DQUOTE))
+        {
+          putchar(c);
+          status=STAT_DQUOTE-status;
+          continue;
+        }
+      if(c=='\''&&(status==STAT_NORM ||status==STAT_QUOTE))
+        {
+          putchar(c);
+          status=STAT_QUOTE-status;
+          continue;
+        }
+      if(c=='\\')
+        {
+          putchar(c);
+          putchar(getchar());
+          continue;
+        }
+      putchar(c);
+    }
+  if(fbrack!=-1)
+    {
+      char c;
+      while(grub_isspace(c=getchar()) && c!='\n');
+    }
+  if(end)
+    *end=rd?rd-1:0;
+  putchar(0);
+  if(ptr!=1)(*argc)++;
+  return argret;
+}
+
+char**
+script_expand_braces(char**argv,int*argc)
+{
+  char**argret=0;int argcret=0;
+  void brace_putch(struct braceset*where,char c)
+    {
+      struct braceset*cur=where;
+      while(cur)
+       {
+         if((cur->len+1)%BRACE_BUFFER==0)
+           cur->word=grub_realloc(cur->word,cur->len+1+BRACE_BUFFER);
+         cur->word[cur->len++]=c;
+         cur=cur->next;
+       }
+    }
+  void brace_fuse(struct braceset*first,struct braceset*second)
+    {
+      struct braceset*ptr1=first,*ptr2;char*frstch; int frstlen;
+      while(ptr1)
+        {
+          ptr2=second;
+ ptr1->word=grub_realloc(ptr1->word,ptr1->len+ptr2->len+BRACE_BUFFER);
+          frstch=ptr1->word;
+          frstlen=ptr1->len;
+          grub_memcpy(ptr1->word+ptr1->len,ptr2->word,ptr2->len);
+          ptr1->len+=ptr2->len;
+          ptr2=ptr2->next;
+          while(ptr2)
+            {
+              struct braceset*new=grub_malloc(sizeof(*new));
+              new->word=grub_malloc(frstlen+ptr2->len+BRACE_BUFFER);
+              new->len=frstlen+ptr2->len;
+              grub_memcpy(new->word,frstch,frstlen);
+              grub_memcpy(new->word+frstlen,ptr2->word,ptr2->len);
+              new->next=ptr1->next;
+              ptr1->next=new;
+              ptr1=ptr1->next;
+              ptr2=ptr2->next;
+            }
+          ptr1=ptr1->next;
+        }
+    }
+  struct braceset*expand_brace(char**exp)
+    {
+      int cnt=0;
+      int esc=0;
+      int wasdol=0;
+      struct braceset*cur=grub_malloc(sizeof(*cur));
+      struct braceset*ret=cur;
+      cur->next=0;
+      cur->len=0;
+      cur->word=grub_malloc(BRACE_BUFFER);
+ for(;**exp && (esc || **exp!='}');esc=(**exp=='\\')&&!esc,wasdol=(**exp=='$'),(*exp)++)
+        {
+          if(**exp=='\'' || **exp=='"')
+          {
+            char*optr=*exp;
+            *exp+=script_get_strend(*exp);
+            while(optr<*exp)
+              brace_putch(cur,*((*exp)++));
+          }
+          if(**exp==',' && !esc)
+            {
+              struct braceset**nextptr=&ret;
+              while(*nextptr)nextptr=&(*nextptr)->next;
+              cur=grub_malloc(sizeof(*cur));
+              *nextptr=cur;
+              cur->next=0;
+              cur->len=0;
+              cur->word=grub_malloc(BRACE_BUFFER);
+              cnt++;
+              continue;
+            }
+ if(**exp=='{' && !wasdol && *(*exp+1+script_find_pas('{','}',*exp+1))=='}' && !esc)
+            {
+              (*exp)++;
+              brace_fuse(cur,expand_brace(exp));
+              continue;
+            }
+          brace_putch(cur,**exp);
+        }
+      if(!cnt) /*Incorrect brace restore '{' and '}'*/
+        {
+          cur=ret;
+          while(cur)
+            {
+              char*oldword=cur->word;
+              cur->len+=2;
+              cur->word=grub_malloc(cur->len);
+              cur->word[0]='{';
+              grub_memcpy(cur->word+1,oldword,cur->len-2);
+              cur->word[cur->len-1]='}';
+              cur=cur->next;
+            }
+        }
+      return ret;
+    }
+  int i;
+  for(i=0;i<*argc;i++)
+    {
+      struct braceset*brcs=grub_malloc(sizeof(*brcs)),*cur;
+      brcs->next=0;
+      brcs->len=0;
+      brcs->word=grub_malloc(BRACE_BUFFER);
+      char*ptr;
+      int esc=0;
+      int wasdol=0;
+      for(ptr=argv[i];*ptr;esc=(*ptr=='\\')&&!esc,wasdol=(*ptr=='$'),ptr++)
+        {
+          if(*ptr=='\'' || *ptr=='"')
+          {
+            char*optr=ptr;
+            ptr+=script_get_strend(ptr);
+            while(optr<ptr)
+              brace_putch(brcs,*(optr++));
+          }
+ if(*ptr=='{' && !wasdol && *(ptr+1+script_find_pas('{','}',ptr+1))=='}' && !esc)
+            {
+              ptr++;
+              brace_fuse(brcs,expand_brace(&ptr));
+              continue;
+            }
+          brace_putch(brcs,*ptr);
+        }
+      cur=brcs;
+      while(cur)
+        {
+          argret=grub_realloc(argret,sizeof(char*)*(argcret+1));
+          cur->word=grub_realloc(cur->word,cur->len+1);
+          cur->word[cur->len]=0;
+          argret[argcret++]=cur->word;
+          cur=cur->next;
+        }
+    }
+  *argc=argcret;
+  return argret;
+}
+
+char*
+script_expand_dollar (char*exp)
+{
+  char*ptr=exp;
+  char*rtval=grub_malloc(EXPAND_BUF_SIZE);
+  int wto=0;
+  rtval[0]=0;
+  void putchar(char c)
+    {
+      if((wto+1)%EXPAND_BUF_SIZE==0)
+        {
+          grub_realloc(rtval,wto+1+EXPAND_BUF_SIZE);
+        }
+      rtval[wto++]=c;
+    }
+  void puts(char*str)
+    {
+      for(;*str;str++)
+        putchar(*str);
+    }
+  for(ptr=exp;*ptr;ptr++)
+    {
+      if(*ptr=='\\' && *(ptr+1))
+        {
+          putchar(*(ptr++));
+          putchar(*ptr);
+          continue;
+        }
+      if(*ptr=='"' || *ptr=='\'')
+        {
+          char *optr=ptr;
+          ptr+=script_get_strend(ptr);
+          while(optr<=ptr)
+            putchar(*(optr++));
+          continue;
+        }
+      if(*ptr=='$')
+        {
+          ptr++;
+          char *expr=ptr;
+          if(*ptr=='(')
+            {
+              enum vartype vtp;
+              if(*(++ptr)=='(')
+                {
+                  char c;
+                  ptr++;
+                  ptr+=script_find_pas('(',')',ptr);
+                  c=*ptr;
+                  *ptr=0;
+ char*tm=script_eval_arith(script_expand_dollar(expr+2),&vtp);
+                  puts(script_get_str(tm,vtp));
+                  *ptr=c;
+                  ptr++;
+                  ptr+=script_find_pas('(',')',ptr);
+                }
+            }
+          else
+            {
+              if (*ptr == '{')
+                {
+                  ptr++;
+                  expr++;
+                  while (*ptr != '}')
+                    ptr++;
+                }
+              else
+                {
+ /* XXX: An env. variable can have characters and digits in
+                  its name, are more characters allowed here?  */
+ while (*ptr && (grub_isalpha (*ptr) || grub_isdigit (*ptr)))
+                    ptr++;
+                }
+              char c;
+              c=*ptr;
+              *ptr=0;
+              puts(script_env_get (expr));
+              *ptr=c;
+              if(c!='}')ptr--;
+            }
+          continue;
+        }
+      putchar(*ptr);
+    }
+  putchar(0);
+  return rtval;
+}
+void
+script_parse_list(grub_menu_entry_t fnptr,char**cmd,grub_err_t(*getline)(char**),int flgs)
+{
+        grub_command_list_t listptr=0;char*lastcmd=*cmd,*bfrcmd=0;
+ /* Get one character from the commandline.  If the caller reads
+     beyond the end of the string a new line will be read.  This
+     function will not chech for errors, the caller has to check for
+     grub_errno.  */
+  char getchar (void)
+    {
+      int c;
+
+      if (! *cmd)
+              {
+                if(getline)
+                  {
+                        if(listptr)
+ listptr->next=grub_malloc(sizeof(*listptr));
+                        getline (cmd);
+                          lastcmd=*cmd;
+                          if(listptr)
+                            {
+                                    listptr=listptr->next;
+                                    listptr->next=0;
+                  listptr->command=grub_malloc(grub_strlen(*cmd)+2);
+                  grub_memcpy(listptr->command,*cmd,grub_strlen(*cmd)+1);
+                            }
+                  }
+                else
+                        return 0;
+                fnptr->num++;
+ + /* Error is ignored here, the caller will check for this
+                 when it reads beyond the EOL.  */
+          c = *(*cmd)++;
+          return c;
+ } +
+      c = *(*cmd)++;
+      if (! c)
+              {
+                bfrcmd=*cmd;
+                *cmd = 0;
+                return '\n';
+              }
+
+      return c;
+    }
+  void skip_oper()
+    {
+      int esc=0;char c;
+      while(1)
+        {
+          c=getchar();
+          if((c=='\n'||c==';') && !esc)
+            break;
+          if(c=='"' && !esc)
+            {
+              while((c=getchar())&& (c!='"' ||esc))
+                esc=(c=='\\')&&!esc;
+              continue;
+            }
+          if(c=='\'' && !esc)
+            {
+              while((c=getchar())&& (c!='\'' ||esc))
+                esc=(c=='\\')&&!esc;
+              continue;
+            }
+        }
+    }
+        char c;int brack=1;int lmin=0;
+        if(!(flgs&1))
+    {
+      while(grub_isspace((c=getchar())));
+      switch(c)
+        {
+        case '{':
+          break;
+        default:
+          grub_error(GRUB_ERR_BAD_ARGUMENT,"unexpected %c '{' expected",c);
+          return;
+        }
+    }
+        listptr=grub_malloc(sizeof(*listptr));
+        listptr->command=grub_malloc(grub_strlen(*cmd)+2);
+        listptr->next=0;
+        fnptr->command_list=listptr;
+        grub_memcpy(listptr->command,*cmd,grub_strlen(*cmd)+1);
+        while(brack)
+    {
+      lmin=0;
+      c=getchar();
+      if(grub_isspace(c))
+        continue;
+      if(c=='\n' || c==';')
+        continue;
+      if(c=='}')
+        {
+          brack--;
+          continue;
+        }
+      if(c=='{')
+        {
+          brack++;
+          continue;
+        }
+      if(c=='i')
+        {
+          if((c=getchar())=='f' && script_islexend(c=getchar()))
+            {
+              brack++;
+              continue;
+            }
+          else
+            {
+              if(c!=';' && c!='\n')
+                skip_oper();
+              continue;
+            }
+        }
+      if(c=='f')
+        {
+          if((c=getchar())=='i' && script_islexend(c=getchar()))
+            {
+              brack--;
+              lmin=3;
+              continue;
+            }
+          else
+            {
+              if(c!=';' && c!='\n')
+                skip_oper();
+              continue;
+            }
+        }
+      if(c=='d')
+        {
+          if((c=getchar())=='o')
+            {
+              c=getchar();
+              if(script_islexend(c))
+                {
+                  if((flgs&2) && brack==1)
+                    {
+                      lmin=3;
+                      break;
+                    }
+                  brack++;
+                  continue;
+                }
+ if(c=='n' && (c=getchar())=='e' && script_islexend(c=getchar()))
+                {
+                  brack--;
+                  continue;
+                }
+              if(c!=';' && c!='\n')
+                skip_oper();
+              continue;
+            }
+          else
+            {
+              if(c!=';' && c!='\n')
+                skip_oper();
+              continue;
+            }
+        }
+      if(c=='e'&& brack==1)
+        {
+          while(1)
+            {
+              if((c=getchar())!='l')
+                break;
+              c=getchar();
+              if(c=='s')
+                {
+                  if((c=getchar())!='e' || !script_islexend(c=getchar()))
+                    break;
+                  brack=0;
+                  lmin=5;
+                  break;
+                }
+              if(c=='i')
+                {
+                  if((c=getchar())!='f' || !script_islexend(c=getchar()))
+                    break;
+                  brack=0;
+                  lmin=5;
+                  break;
+                }
+            }
+          if(c!='\n' && c!=';'&& brack)
+            skip_oper();
+          continue;
+        }
+      if(script_isfuncbeg(*cmd))
+        {
+          script_skipfuncbeg(cmd);
+          continue;
+        }
+      skip_oper();
+    }
+        if(*cmd)
+    {
+      (*cmd)-=lmin;
+      listptr->command[(*cmd)-lastcmd]=0;
+    }
+        if(!*cmd&& lmin)
+    {
+      *cmd=bfrcmd-lmin;
+      listptr->command[grub_strlen(listptr->command)-lmin+1]=0;
+    }
+}
+int
+script_list_execute( grub_menu_entry_t fn,enum returnreason*retres,int*depth)
+{
+        grub_command_list_t cmdlist=fn->command_list;
+        grub_err_t getln(char**s)
+    {
+      if(cmdlist&& cmdlist->next)
+        {
+          cmdlist=cmdlist->next;
+          *s=cmdlist->command;
+        }
+      else
+        *s=0;
+      return 0;
+    }
+        int rtval=0;
+        while(cmdlist)
+    {
+      enum returnreason rt=SCRIPT_NONE;
+ if(cmdlist->command[0])rtval=script_execute(cmdlist->command,getln,0,&rt,depth);
+      if(retres)
+        *retres=rt;
+      if(rt)
+        return rtval;
+      if(cmdlist)
+        cmdlist=cmdlist->next;
+    }
+        return rtval;
+}
+void
+script_free_list(grub_menu_entry_t arg)
+{
+        grub_command_list_t lst=arg->command_list,last;
+        while(lst)
+    {
+      grub_free(lst->command);
+      last=lst;
+      lst=lst->next;
+      grub_free(last);
+    }
+        grub_free(arg);
+}
+int
+script_exec_file (char*fname,int argc, char**argv)
+{
+        grub_file_t file;char*lastalloc=0;
+        grub_err_t getln(char**s)
+    {
+      *s=grub_malloc(GRUB_MAX_CMDLINE);
+      if(lastalloc)
+        grub_free(lastalloc);
+      lastalloc=*s;
+      char c;
+      int pos = 0;
+      int literal = 0;
+      int comment = 0;
+      while (1)
+        {
+          if (grub_file_read (file, &c, 1) != 1)
+            break;
+
+          /* Skip all carriage returns.  */
+          if (c == '\r')
+            continue;
+
+          /* Replace tabs with spaces.  */
+          if (c == '\t')
+            c = ' ';
+
+          /* The previous is a backslash, then...  */
+          if (literal)
+            {
+ /* If it is a newline, replace it with a space and continue. */
+              if (c == '\n')
+                {
+                  c = ' ';
+ + /* Go back to overwrite the backslash. */
+                  if (pos > 0)
+                pos--;
+                }
+ + literal = 0;
+            }
+
+            if (c == '\\')
+              literal = 1;
+
+            if (comment)
+              {
+                if (c == '\n')
+                    comment = 0;
+              }
+            else if (pos == 0)
+              {
+                  if (c == '#')
+                      comment = 1;
+                  else if (! grub_isspace (c))
+                      (*s)[pos++] = c;
+              }
+            else
+              {
+                  if (c == '\n')
+                      break;
+ + if (pos < GRUB_MAX_CMDLINE)
+                      (*s)[pos++] = c;
+              }
+ } + if(pos==0)
+        {
+          grub_free(*s);
+          *s=0;
+        }
+      else
+        (*s)[pos] = '\0';
+      return 0;
+    }
+        char*ln;int ret=0;
+        file=grub_file_open(fname);
+        if(!file)
+                return grub_errno;
+        while(1)
+    {
+      getln(&ln);
+      if(!ln)
+        break;
+      ret=script_execute(ln,getln,0,0,0);
+    }
+        return ret;
+}
+int
+script_execute(char*cmdline,grub_err_t(*getline)(char**),char**rest,enum returnreason*retres,int*depth)
+{
+        int rtval=0,semdel=0;
+        int invrtval=0;
+        char*end=cmdline;
+        int skip_spaces()
+    {
+      if(!end)
+        return 0;
+      do
+        {
+          if(!*end)
+            getline(&end);
+          if(!end)
+            return 0;
+          while(*end && grub_isspace(*end))
+            end++;
+        }
+      while(!*end);
+      return 1;
+    }
+        if(rest)*rest=0;
+        if(retres)
+                *retres=SCRIPT_NONE;
+        while(1)
+    {
+      if(invrtval)
+        rtval=!rtval;
+      invrtval=0;
+      if(!end || !*end  || *end=='#' || *end=='\n')
+        break;
+      if(*end=='|' && !rtval)
+        break;
+      if(*end=='&' && rtval)
+        break;
+      semdel=(*end==';');
+      if(*end==';' || *end=='|' ||*end=='&')
+        end++;
+      if(!*end &&semdel)
+        break;
+      if(!skip_spaces())return rtval;
+      if(*end=='!')
+        invrtval=1,end++;
+      if(!skip_spaces())return rtval;
+      if(*end=='{')
+        end++;
+      if(!skip_spaces())return rtval;
+      if(*end=='}')
+        end++;
+      while(*end && grub_isspace(*end))
+        end++;
+      if(!*end)
+        break;
+      if((!grub_memcmp(end,"then",4) && script_islexend(end[4]))
+        ||(!grub_memcmp(end,"else",4) && script_islexend(end[4]))
+        ||(!grub_memcmp(end,"elif",4) && script_islexend(end[4]))
+        ||(!grub_memcmp(end,"done",4) && script_islexend(end[4]))
+        ||(!grub_memcmp(end,"fi",2) && script_islexend(end[2])))
+        {
+          if(rest)
+            *rest=end;
+          break;
+        }
+      if(end[0]=='i' && end[1]=='f'&& script_islexend(end[2]))
+        {
+          int ret=0,crtval=0;
+          end+=2;
+ while(!end || !*end || grub_memcmp(end,"then",4)|| !script_islexend(end[4]))
+            {
+              enum returnreason rt;
+              if(!end || !*end)
+                getline(&end);
+              if(*end)
+                {
+                  ret=!script_execute(end,getline,&end,&rt,depth);
+                  if(retres)
+                    *retres=rt;
+                  if(rt)
+                    return rtval;
+                }
+            }
+          grub_menu_entry_t lst=grub_malloc(sizeof(*lst));
+          lst->num=0;
+          lst->title=0;
+          lst->next=0;
+          end+=4;
+          script_parse_list(lst,&end,getline,1);
+          if(ret)
+            {
+              enum returnreason rt;
+              rtval=script_list_execute(lst,&rt,depth);
+              script_free_list(lst);
+              if(retres)
+                *retres=rt;
+              if(rt)
+                return rtval;
+            }
+          script_free_list(lst);
+          while((!grub_memcmp(end,"else",4)&&script_islexend(end[4]))
+            ||(!grub_memcmp(end,"elif",4)&&script_islexend(end[4])))
+            {
+              lst=grub_malloc(sizeof(*lst));
+              lst->num=0;
+              lst->title=0;
+              lst->next=0;
+              lst->command_list=0;
+              end+=4;
+              if(!ret&& !grub_memcmp(end-4,"elif",4))
+                {
+ while(!end || !*end || grub_memcmp(end,"then",4)|| !script_islexend(end[4]))
+                    {
+                      enum returnreason rt;
+                      if(!end || !*end)
+                        getline(&end);
+                      if(*end)
+                        {
+                          ret=!script_execute(end,getline,&end,&rt,depth);
+                          if(retres)
+                            *retres=rt;
+                          if(rt)
+                            return rtval;
+                        }
+                    }
+                  end+=4;
+                }
+              else
+                crtval=!ret;
+              script_parse_list(lst,&end,getline,1);
+              if(crtval)
+                {
+                  enum returnreason rt;
+                  rtval=script_list_execute(lst,&rt,depth);
+                  script_free_list(lst);
+                  if(retres)
+                    *retres=rt;
+                  if(rt)
+                    return rtval;
+                  ret=1;
+                }
+                else
+                  script_free_list(lst);
+            }
+          end+=2;
+          continue;
+        }
+ if(!grub_memcmp(end,"for",sizeof("for")-1)&& script_islexend(end[sizeof("for")-1]))
+        {
+          char* nmbeg;
+          end+=sizeof("for")-1;
+          if(!skip_spaces())
+            return rtval;
+          if(*end=='(')
+            {
+              char**exps;char*exp1,*exp2,*exp3;int argc;
+              enum vartype vtp;
+              grub_menu_entry_t lst=grub_malloc(sizeof(*lst));
+              exps=script_split_tokens(end,&argc,getline,&end);
+              exp1=*exps+2;
+              exp2=script_strchr(exp1,';')+1;
+              if(!(exp2-1))
+                {
+                  grub_error(GRUB_ERR_BAD_ARGUMENT,"; expected");
+                  return rtval;
+ } + *(exp2-1)=0;
+              exp3=script_strchr(exp2,';')+1;
+              if(!(exp3-1))
+                {
+                  grub_error(GRUB_ERR_BAD_ARGUMENT,"; expected");
+                  return rtval;
+ } + *(exp3-1)=0; + exp3[grub_strlen(exp3)-1]=0; + end++;
+              if(!skip_spaces())
+                return rtval;
+ if(grub_memcmp(end,"do",2) || !script_islexend(end[2])) + {
+                  grub_error(GRUB_ERR_BAD_ARGUMENT,"do expected");
+                  return rtval;
+                }
+              end+=2;
+              script_parse_list(lst,&end,getline,1);
+              char*exptm,*ret;
+              exptm=script_expand_dollar(exp1);
+ script_eval_arith(exptm,&vtp); + grub_free(exptm);
+              while(1)
+                {
+                  int dpth;
+                  exptm=script_expand_dollar(exp2);
+                  ret=script_eval_arith(exptm,&vtp);
+                  grub_free(exptm);
+                  if(!script_get_bool(script_get_str(ret,vtp)))
+                    break;
+                  enum returnreason rt;
+                  rtval=script_list_execute(lst,&rt,&dpth);
+                  if(retres)
+ *retres=((rt==SCRIPT_CONTINUE||rt==SCRIPT_BREAK)&&dpth==1)?SCRIPT_NONE:rt;
+                  if(depth)
+                    *depth=dpth-1;
+ if(rt && (rt!=SCRIPT_CONTINUE||dpth!=1)&&(rt!=SCRIPT_BREAK||dpth!=1))
+                    return rtval;
+                  if(rt==SCRIPT_BREAK)
+                    break;
+                  exptm=script_expand_dollar(exp3);
+ script_eval_arith(exptm,&vtp); + grub_free(exptm); + }
+              grub_free(exps);
+              grub_free(exp1-2);
+              script_free_list(lst);
+              continue;
+            }
+          else
+            {
+              grub_menu_entry_t lst=grub_malloc(sizeof(*lst));
+              nmbeg=end;
+              while(*end && !grub_isspace(*end))end++;
+              char*name=grub_malloc(end-nmbeg+1);
+              grub_memcpy(name,nmbeg,end-nmbeg);
+              name[end-nmbeg]=0;
+              if(!skip_spaces())
+ return rtval; + if(grub_memcmp(end,"in",2) || !script_islexend(end[2])) + {
+                  grub_error(GRUB_ERR_BAD_ARGUMENT,"in expected");
+                  return rtval;
+                }
+              end+=2;
+              if(!skip_spaces())
+ return rtval; + int argc,i,argco; + char**exps=script_split_tokens(end,&argc,getline,&end),**exp2,**tmp;
+              argco=argc;
+              exp2=script_expand_braces(exps,&argc);
+              for(tmp=exps;tmp-exps<argco;tmp++)
+                grub_free(*tmp);
+              grub_free(exps);
+              exps=exp2;
+              if(*end!=';')
+                {
+                  grub_error(GRUB_ERR_BAD_ARGUMENT,"; expected");
+                  return rtval;
+                }
+              end++;
+              if(!skip_spaces())
+                return rtval;
+ if(grub_memcmp(end,"do",2) || !script_islexend(end[2])) + {
+                  grub_error(GRUB_ERR_BAD_ARGUMENT,"do expected");
+                  return rtval;
+                }
+              end+=2;
+              script_parse_list(lst,&end,getline,1);
+              for(i=0;i<argc;i++)
+                {
+                  enum returnreason rt;int dpth;
+                  script_env_set(script_dupstr(name),exps[i]);
+                  rtval=script_list_execute(lst,&rt,&dpth);
+                  if(retres)
+ *retres=((rt==SCRIPT_CONTINUE||rt==SCRIPT_BREAK)&&dpth==1)?SCRIPT_NONE:rt;
+                  if(depth)
+                    *depth=dpth-1;
+ if(rt && (rt!=SCRIPT_CONTINUE||dpth!=1)&&(rt!=SCRIPT_BREAK||dpth!=1))
+                    return rtval;
+                  if(rt==SCRIPT_BREAK)
+                    break;
+                }
+              grub_free(name);
+              for(tmp=exps;tmp-exps<argc;tmp++)
+                grub_free(*tmp);
+              grub_free(exps);
+              script_free_list(lst);
+              continue;
+            }
+        }
+ if((!grub_memcmp(end,"while",sizeof("while")-1)&& script_islexend(end[sizeof("while")-1])) + ||(!grub_memcmp(end,"until",sizeof("until")-1)&& script_islexend(end[sizeof("until")-1])))
+        {
+          int invrt=(*end=='u');
+          end+=sizeof("while")-1;
+          grub_menu_entry_t condlst=grub_malloc(sizeof(*condlst));
+          grub_menu_entry_t lst=grub_malloc(sizeof(*lst));
+          condlst->num=0;
+          condlst->title=0;
+          condlst->next=0;
+          script_parse_list(condlst,&end,getline,3);
+          lst->num=0;
+          lst->title=0;
+          lst->next=0;
+          end+=2;
+          script_parse_list(lst,&end,getline,1);
+          while(1)
+            {
+              enum returnreason rt;
+              int ret=script_list_execute(condlst,&rt,depth),dpth;
+              if(retres)
+                *retres=rt;
+              if(rt)
+                return rtval;
+              if((!ret)==invrt)
+                break;
+              rtval=script_list_execute(lst,&rt,&dpth);
+              if(retres)
+ *retres=((rt==SCRIPT_CONTINUE||rt==SCRIPT_BREAK)&&dpth==1)?SCRIPT_NONE:rt;
+              if(depth)
+                *depth=dpth-1;
+ if(rt && (rt!=SCRIPT_CONTINUE||dpth!=1)&&(rt!=SCRIPT_BREAK||dpth!=1))
+                return rtval;
+              if(rt==SCRIPT_BREAK)
+                break;
+            }
+          script_free_list(lst);
+          script_free_list(condlst);
+          continue;
+        }
+      if (script_isfuncbeg(end))
+        {
+          grub_menu_t baseptr=&funcs;
+          grub_menu_entry_t bbptr,bptr2;
+          char*name=0;
+          while(grub_isspace(*end))end++;
+ if(!grub_memcmp(end,"entry",sizeof("entry")-1) && script_islexend(end[sizeof("entry")-1]))
+            end+=sizeof("entry")-1,baseptr=menu;
+          while(grub_isspace(*end))end++;
+ if(!grub_memcmp(end,"function",sizeof("function")-1) && script_islexend(end[sizeof("function")-1]))
+            end+=sizeof("function")-1;
+          while(grub_isspace(*end))end++;
+          switch(*end)
+            {
+            case '"':
+              end++;
+              name=script_get_doublestring(&end);
+              break;
+            case '\'':
+              end++;
+              name=script_get_singlestring(&end);
+              break;
+            default:
+              name=grub_malloc(64);//Must be enough
+              char*ptr=name;
+              while(!script_islexend(*end))
+                *(ptr++)=*(end++);
+              *ptr=0;
+            }
+          while(grub_isspace(*end))end++;
+          if(*end=='(')end++;//skip (
+          while(grub_isspace(*end))end++;
+          if(*end==')')end++;//skip )
+          while(grub_isspace(*end))end++;
+          baseptr->size++;
+          bbptr=bptr2=baseptr->entry_list;
+          while(bptr2)bbptr=bptr2,bptr2=bptr2->next;
+          bptr2=grub_malloc(sizeof(struct grub_menu_entry));
+          if(bbptr)
+            bbptr->next=bptr2;
+          else
+            baseptr->entry_list=bptr2;
+          bptr2->title=name;
+          bptr2->num=0;
+          bptr2->next=0;
+          script_parse_list(bptr2,&end,getline,0);
+          continue;
+        }
+      int argc,argco;
+      char**exps=script_split_tokens(end,&argc,getline,&end),**exp2,**tmp;
+      if(argc==1 && (exps[0])[0]=='(' && (exps[0])[1]=='(')
+        {
+          char*exp=script_expand_dollar(exps[0])+2;
+          char*expend,c;
+          char*ret;enum vartype vtp;
+          expend=exp+grub_strlen(exp)-1;
+          c=*expend;
+          *expend=0;
+          ret=script_eval_arith(exp,&vtp);
+          *expend=c;
+          rtval=!script_get_bool(script_get_str(ret,vtp));
+          continue;
+        }
+      argco=argc;
+      exp2=script_expand_braces(exps,&argc);
+      for(tmp=exps;tmp-exps<argco;tmp++)
+        grub_free(*tmp);
+      grub_free(exps);
+      exps=exp2;
+      for(tmp=exps;tmp-exps<argc;tmp++)
+        {
+          char*t;
+          t=*tmp;
+          *tmp=script_expand_dollar(*tmp);
+          grub_free(t);
+        }
+      if(!grub_strcmp("return",exps[0]))
+        {
+          if(*(exps[1])=='-' ||grub_isdigit(*(exps[1])))
+            rtval=grub_strtol(exps[1],0,0);
+          if(retres)
+            *retres=SCRIPT_RETURN;
+          return rtval;
+        }
+      if(!grub_strcmp("continue",exps[0]))
+        {
+          if(depth)
+            *depth=1;
+          if(depth && (*(exps[1])=='-' ||grub_isdigit(*(exps[1])) ))
+            *depth=grub_strtol(exps[1],0,0);;
+          if(retres)
+            *retres=SCRIPT_CONTINUE;
+          return rtval;
+        }
+      if(!grub_strcmp("break",exps[0]))
+        {
+          if(depth)
+            *depth=1;
+          if(depth && (*(exps[1])=='-' ||grub_isdigit(*(exps[1])) ))
+            *depth=grub_strtol(exps[1],0,0);;
+          if(retres)
+            *retres=SCRIPT_CONTINUE;
+          return rtval;
+        }
+      /* In case of an assignment set the environment accordingly instead
+      of calling a function.  */
+      if (script_strchr(exps[0],'='))
+        {
+          char*expcur=script_strchr(exps[0],'=');
+          expcur[0] = 0;
+          char*ptr2=expcur+1;
+  #if 0
+ int array=0; + // if(ptr2[0]=='(')
+    //        array=1;
+  #endif
+          script_env_set (exps[0], ptr2);
+          expcur[0] = '=';
+          rtval=0;
+          continue;
+        }
+      int i;
+      for(i=0;i<argc;i++)
+        {
+          char*wfrom=exps[i],*wto=exps[i];
+          while(*wfrom)
+            {
+              if(*wfrom=='\\')
+                {
+                  *(wto++)=*(++wfrom);
+                  wfrom++;
+                  continue;
+                }
+              if(*wfrom=='\'' || *wfrom=='"')
+                {
+                  wfrom++;
+                  continue;
+                }
+              *(wto++)=*(wfrom++);
+            }
+          *wto=0;
+        }
+        {
+          grub_menu_entry_t cur=funcs.entry_list;
+          if(funcs.entry_list)
+            {
+              while(cur)
+                {
+                  if(!grub_strcmp(cur->title,exps[0]))
+                    break;
+                  cur=cur->next;
+                }
+              if(cur)
+                {
+                  rtval=script_list_execute(cur,0,0);
+                  continue;
+                }
+            }
+        }
+      rtval=grub_exec_norm(exps,argc);
+    }
+        return rtval;
+}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]