grub-devel
[Top][All Lists]
Advanced

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

Bash pre-alpha


From: Serbinenko Vladimir
Subject: Bash pre-alpha
Date: Sat, 29 Jan 2005 14:18:26 +0100
User-agent: Mozilla Thunderbird 1.0 (X11/20041206)

Here I prepared first preview version of bash scripting engine. I repeat *first preview version* That means I haven't really tested it nor cleaned up or commented. This version is only for discussions.
For now supported features are:
arrays both syntaxes i=([0]=7 ...) and i[0]
arithmetic expansion and ((...))
commands echo, ':',source
Function support:
[function ] name() { list; }
Menu entries support like
entry "<description>" { list; }
Now configuration file is parsed the same way as any script file or console entering menu is automatically shown after configfile is parsed or you can use showmenu command
In arithmetical expansion some additional commands are present:
i{9} means 10-th character of i
"i",'i' means string i
Associative arrays are supported: use
z['hello']=JJJ
This version is made in the goal to show my ideas and receive the critics. Please send your suggestions,critics and bug-reports.
Known bugs:
possible segmentation faults at incorrect constructions
Not complete GCS compilance
Some plans:
See TODO in script.c
commands clear menu and unregister_entry
Bug fixing
----------------------------------------------------------------------------------------------------------------------
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/ChangeLog ./grub2/ChangeLog
--- ./grub2b/ChangeLog    2005-01-29 13:37:07.000000000 +0100
+++ ./grub2/ChangeLog    2005-01-29 14:00:55.000000000 +0100
@@ -1,3 +1,18 @@
+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-22  Hollis Blanchard  <address@hidden>

* disk/powerpc/ieee1275/ofdisk.c (grub_ofdisk_open): Don't initialize diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/conf/i386-pc.rmk ./grub2/conf/i386-pc.rmk
--- ./grub2b/conf/i386-pc.rmk    2005-01-29 13:37:07.000000000 +0100
+++ ./grub2/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 '*~' --expand-tabs ./grub2b/conf/powerpc-ieee1275.rmk ./grub2/conf/powerpc-ieee1275.rmk --- ./grub2b/conf/powerpc-ieee1275.rmk 2005-01-29 13:37:07.000000000 +0100
+++ ./grub2/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 '*~' --expand-tabs ./grub2b/include/grub/normal.h ./grub2/include/grub/normal.h
--- ./grub2b/include/grub/normal.h    2005-01-29 13:37:07.000000000 +0100
+++ ./grub2/include/grub/normal.h    2005-01-29 13:43:42.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*exp);

#ifdef GRUB_UTIL
void grub_normal_init (void);
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/include/grub/script.h ./grub2/include/grub/script.h
--- ./grub2b/include/grub/script.h    1970-01-01 01:00:00.000000000 +0100
+++ ./grub2/include/grub/script.h    2005-01-29 12:25:56.000000000 +0100
@@ -0,0 +1,83 @@
+/*
+ *  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 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);
+};
+enum vartype {SCRIPT_STR,SCRIPT_VAR_NAME};
+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 (char*cmdline,grub_err_t (* getline) (char **),char**end,int flags);
+char*
+script_get_array(char*exp);
+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);
+int
+script_exec_file (char*fname,int argc, char**argv);
+int
+script_list_execute(grub_menu_entry_t fn);
+grub_menu_t menu;
+#define EXPAND_DOLLAR 1
+#define EXPAND_ALL 1
+#endif /* ! SCRIPT_H*/
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/normal/command.c ./grub2/normal/command.c
--- ./grub2b/normal/command.c    2005-01-29 13:37:08.000000000 +0100
+++ ./grub2/normal/command.c    2005-01-29 13:53:55.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,6 +121,11 @@
      return grub_cmdline_get (">", *s, GRUB_MAX_CMDLINE, 0, 1);
    }

+  return script_execute(cmdline,cmdline_get,0);
+}
+int
+grub_exec_norm(char*exp)
+{
  grub_command_t cmd;
  grub_err_t ret = 0;
  char *pager;
@@ -130,21 +136,14 @@
  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], '='))
+  grub_err_t dummy_get (char **s)
    {
-      char *val = grub_strchr (args[0], '=');
-      val[0] = 0;
-      grub_env_set (args[0], val + 1);
-      val[0] = '=';
+      *s = grub_malloc (3);
+      *s[0] = '\0';
      return 0;
    }
- + if (grub_split_cmdline (exp, dummy_get, &num, &args))
+        return 0;
  cmd = grub_command_find (args[0]);
  if (! cmd)
    return -1;
@@ -218,7 +218,7 @@
    }
val[0] = 0;
-  grub_env_set (var, val + 1);
+  script_env_set (var, val + 1);
  val[0] = '=';
  return 0;
}
@@ -231,7 +231,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 +306,54 @@
  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]);
+  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;
+}
+
+
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 +372,16 @@

  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 ("showmenu", showmenu_command, GRUB_COMMAND_FLAG_BOTH,
+                         "showmenu", "Show menu.", 0);
}
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/normal/main.c ./grub2/normal/main.c
--- ./grub2b/normal/main.c    2005-01-29 13:37:08.000000000 +0100
+++ ./grub2/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 '*~' --expand-tabs ./grub2b/normal/menu.c ./grub2/normal/menu.c
--- ./grub2b/normal/menu.c    2005-01-29 13:37:08.000000000 +0100
+++ ./grub2/normal/menu.c    2005-01-29 14:00:10.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.  */

@@ -238,140 +239,7 @@
static int
run_menu (grub_menu_t menu, int nested)
{
-  int first, offset;
-  unsigned long saved_time;
- - first = 0;
-  offset = menu->default_entry;
-  if (offset > TERM_NUM_ENTRIES - 1)
-    {
-      first = offset - (TERM_NUM_ENTRIES - 1);
-      offset = TERM_NUM_ENTRIES - 1;
-    }
-
-  /* Initialize the time.  */
-  saved_time = grub_get_rtc ();
-
- refresh:
-  grub_setcursor (0);
-  init_page (nested, 0);
-  print_entries (menu, first, offset);
-  grub_refresh ();
-
-  while (1)
-    {
-      int c;
-
-      if (menu->timeout > 0)
-        {
-          unsigned long current_time;
-
-          current_time = grub_get_rtc ();
-          if (current_time - saved_time >= GRUB_TICKS_PER_SECOND)
-            {
-              menu->timeout--;
-              saved_time = current_time;
-            }
- - grub_gotoxy (0, TERM_HEIGHT - 3);
-          /* NOTE: Do not remove the trailing space characters.
-             They are required to clear the line.  */
-          grub_printf ("\
-   The highlighted entry will be booted automatically in %d seconds.    ",
-                       menu->timeout);
-          grub_gotoxy (TERM_CURSOR_X, TERM_FIRST_ENTRY_Y + offset);
-          grub_refresh ();
-        }
-
-      if (menu->timeout == 0)
-        return menu->default_entry;
- - if (grub_checkkey () >= 0 || menu->timeout < 0)
-        {
-          c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
- - if (menu->timeout >= 0)
-            {
-              grub_gotoxy (0, TERM_HEIGHT - 3);
-              grub_printf ("\
-                                                                        ");
-              menu->timeout = -1;
-              menu->fallback_entry = -1;
-              grub_gotoxy (TERM_CURSOR_X, TERM_FIRST_ENTRY_Y + offset);
-            }
- - switch (c)
-            {
-            case 16:
-            case '^':
-              if (offset > 0)
-                {
-                  print_entry (TERM_FIRST_ENTRY_Y + offset, 0,
-                               get_entry (menu, first + offset));
-                  offset--;
-                  print_entry (TERM_FIRST_ENTRY_Y + offset, 1,
-                               get_entry (menu, first + offset));
-                }
-              else if (first > 0)
-                {
-                  first--;
-                  print_entries (menu, first, offset);
-                }
-              break;
- - case 14:
-            case 'v':
-              if (menu->size > first + offset + 1)
-                {
-                  if (offset < TERM_NUM_ENTRIES - 1)
-                    {
-                      print_entry (TERM_FIRST_ENTRY_Y + offset, 0,
-                                   get_entry (menu, first + offset));
-                      offset++;
-                      print_entry (TERM_FIRST_ENTRY_Y + offset, 1,
-                                   get_entry (menu, first + offset));
-                    }
-                  else
-                    {
-                      first++;
-                      print_entries (menu, first, offset);
-                    }
-                }
-              break;
- - case '\n':
-            case '\r':
-            case 6:
-              grub_setcursor (1);
-              return first + offset;
- - case '\e':
-              if (nested)
-                {
-                  grub_setcursor (1);
-                  return -1;
-                }
-              break;
- - case 'c':
-              grub_setcursor (1);
-              grub_cmdline_run (1);
-              goto refresh;
-
-            case 'e':
-              edit_menu_entry (get_entry (menu, first + offset));
-              goto refresh;
- - default:
-              break;
-            }
- - grub_refresh ();
-        }
-    }
-
-  /* Never reach here.  */
-  return -1;
+  return script_list_execute(entry);
}

/* Run a menu entry.  */
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/normal/script.c ./grub2/normal/script.c
--- ./grub2b/normal/script.c    1970-01-01 01:00:00.000000000 +0100
+++ ./grub2/normal/script.c    2005-01-29 13:07:27.000000000 +0100
@@ -0,0 +1,1983 @@
+/* script.c - scripting engine */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003  Free Software Foundation, Inc.
+ *  Copyright (C) 2003  NIIBE Yutaka <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:
+GCS cleanup
+cond expr [[ ... ]], [...]
+for,while,until
+
+beta:
+select,case
+local and function and script file parameters
+expansions:
+        braces{}
+        ${..:..},...
+        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;
+}
+
+char*
+script_strrchr(char*str,char c)
+{
+        char*expcur,*rtval=0;
+        for(expcur=str;*expcur;expcur++)
+        {
+                if(*expcur==c)
+                        rtval=expcur;
+                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_env_get(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;
+                enum vartype vtp;
+ char*tm=script_eval_arith(script_expand(eptr+1,0,0,EXPAND_DOLLAR),&vtp); + char*rtval=script_get_arrayelem(script_env_get(nm),script_get_str(tm,vtp));
+                *ptr=c;
+                *eptr=c2;
+                if(!rtval)
+                {
+                        rtval=grub_malloc(3);
+                        *rtval=0;
+                }
+                return rtval;
+        }
+        return grub_env_get(nm);
+}
+
+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 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(eptr+1,0,0,EXPAND_DOLLAR),&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(eptr+1,0,0,EXPAND_DOLLAR),&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;
+}
+
+char*
+script_get_array(char*exp)
+{
+        char*rtval=grub_malloc(3);
+        rtval[0]=0;
+        int ptr=0;
+        char*expcur=exp;
+        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;
+        }
+        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);
+                }
+        }
+        return rtval;
+}
+
+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 at line %d",*expcur);
+                                                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_expand (char*cmdline,grub_err_t (* getline) (char **),char**end,int flags)
+{
+  char *rd = (char *) cmdline;
+  char unputbuf;
+  int unput = 0;
+  char*rtval=grub_malloc(EXPAND_BUF_SIZE);
+  char *wto=rtval;
+  int wor=0,wand=0;
+  enum stat {STAT_NORM,STAT_QUOTE,STAT_DQUOTE,STAT_BQUOTE};
+  enum stat status=STAT_NORM;
+ + grub_err_t dummygetline(char**s)
+  {
+        **s=0;
+        return 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 (unput)
+        {
+          unput = 0;
+          return unputbuf;
+        }
+
+      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 unputc (char c)
+    {
+      unputbuf = c;
+      unput = 1;
+    }
+    void putchar(char c)
+      {
+        if((wto-rtval+1)%EXPAND_BUF_SIZE==0)
+          {
+                int delta=wto-rtval;
+                grub_realloc(rtval,wto-rtval+1+EXPAND_BUF_SIZE);
+                wto=rtval+delta;
+          }
+        *(wto++)=c;
+      }
+      void puts(char*str){
+        for(;*str;str++)
+                putchar(*str);
+      }
+        while(1)
+        {
+                char c;
+                c=getchar();
+ if((c==';' || c=='\n' || c=='#' ||(c=='|'&&wor)||(c=='&'&&wand)) && status==STAT_NORM)
+                        break;
+                if(wor)
+                {
+                        putchar('|');
+                        wor=0;
+                }
+                if(wand)
+                {
+                        putchar('&');
+                        wand=0;
+                }
+                if(c=='|')
+                {
+                        wor=1;
+                        continue;
+                }
+                if(c=='&')
+                {
+                        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;
+                }
+                if(c=='$' && status!=STAT_QUOTE && (flags&EXPAND_DOLLAR))
+                {
+                        char exp[1024];
+                        char *p=exp;
+                        c = getchar ();
+                        if(c=='(')
+                        {
+                                enum vartype vtp;
+                                //TODO: command expansion
+                                if((c=getchar())=='(')
+                                {
+                                        int brack=2;
+                                        for(;brack;)
+                                        {
+                                                char c=0;
+                                                int esc=0;
+                                                *(p++)=getchar();
+                                                if(*(p-1)=='(')
+                                                        brack++;
+                                                if(*(p-1)==')')
+                                                        brack--;
+                                                if(*(p-1)=='"')
+ for(c=*(p++)=getchar();esc || c!='"';esc=(c=='\\' &&!esc),c=*(p++)=getchar());
+                                                if(*(p-1)=='\'')
+ for(c=*(p++)=getchar();esc || c!='\'';esc=(c=='\\' &&!esc),c=*(p++)=getchar());
+                                        }
+                                }
+                                *(p-2)=0;
+ char*tm=script_eval_arith(script_expand(exp,0,0,EXPAND_DOLLAR),&vtp);
+                                puts(script_get_str(tm,vtp));
+                                *(p-2)=')';
+                        }
+                        else
+                        {
+                                if (c == '{')
+                                        while ((c = getchar ()) != '}')
+                                                *(p++) = c;
+                                else
+                                {
+ /* XXX: An env. variable can have characters and digits in + its name, are more characters allowed here? */ + while (c && (grub_isalpha (c) || grub_isdigit (c)))
+                                        {
+                                                *(p++) = c;
+                                                c = getchar ();
+                                        }
+                                        unputc (c);
+                                }
+                                *p = '\0';
+                                puts(script_env_get (exp));
+                        }
+                        continue;
+                  }
+                  putchar(c);
+        }
+        putchar(0);
+        if(end)
+                *end=rd?rd-1:0;
+        return rtval;
+}
+void
+script_parse_list(grub_menu_entry_t fnptr,char**cmd,grub_err_t(*getline)(char**),int no1stskip)
+{
+        grub_command_list_t listptr=0;char*lastcmd=*cmd,*bfrcmd=*cmd;
+ /* 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(!no1stskip)
+        {
+                while(grub_isspace((c=getchar())));
+                switch(c)
+                {
+                case '{':
+                        break;
+                case 'd':
+                        if(getchar()!='o')
+                                break;
+                        if(!script_islexend(getchar()))
+                                break;
+                        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;
+                while(grub_isspace(c=getchar()));
+                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))
+                                {
+                                        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;
+}
+int
+script_list_execute(    grub_menu_entry_t fn)
+{
+        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)
+        {
+                rtval=script_execute(cmdlist->command,getln,0);
+                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);
+        }
+        return ret;
+}
+int
+script_execute(char*cmdline,grub_err_t(*getline)(char**),char**rest)
+{
+        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;
+        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]))
+                        {
+                                if(!end || !*end)
+                                        getline(&end);
+                                ret=!script_execute(end,getline,&end);
+                        }
+                        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)
+                                rtval=script_list_execute(lst);
+                        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]))
+                                        {
+                                                if(!end || !*end)
+                                                        getline(&end);
+ crtval=!script_execute(end,getline,&end);
+                                        }
+                                        end+=4;
+                                }
+                                else
+                                        crtval=!ret;
+                                script_parse_list(lst,&end,getline,1);
+                                if(crtval)
+                                {
+                                        rtval=script_list_execute(lst);
+                                        ret=1;
+                                }
+                                script_free_list(lst);
+                        }
+                        end+=2;
+                        continue;
+                }
+                if(end[0]=='(' && end[1]=='(')
+                {
+ char*exp=script_expand(end,getline,&end,EXPAND_DOLLAR);
+                        while(grub_isspace(*exp))exp++;
+                        if(*exp=='(' && *(exp+1)=='(')
+                        {
+                                exp+=2;
+                                char*expend,c;
+                                char*ret;enum vartype vtp;
+                                expend=exp+script_find_pas('(',')',exp);
+                                c=*expend;
+                                *expend=0;
+                                ret=script_eval_arith(exp,&vtp);
+                                *expend=c;
+ rtval=!script_strtol(script_get_str(ret,vtp));
+                                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;
+                }
+                char*exp=script_expand(end,getline,&end,EXPAND_ALL);
+                while(grub_isspace(*exp))exp++;
+                char*expcur=exp;
+                {
+                        grub_menu_entry_t cur=funcs.entry_list;
+                        if(funcs.entry_list)
+                        {
+                                while(cur)
+                                {
+ if(!grub_memcmp(cur->title,expcur,grub_strlen(cur->title))&&script_islexend(expcur[grub_strlen(cur->title)]))
+                                                break;
+                                        cur=cur->next;
+                                }
+                                if(cur)
+                                {
+                                        expcur+=grub_strlen(cur->title);
+                                        rtval=script_list_execute(cur);
+                                        continue;
+                                }
+                        }
+                }
+ /* In case of an assignment set the environment accordingly instead
+                of calling a function.  */
+ while(*expcur && !grub_isspace(*expcur) && *expcur!='=')expcur++;
+                if (*expcur=='=')
+                {
+                        expcur[0] = 0;
+                        char*ptr2=expcur+1;
+                        char*endptr=exp+grub_strlen(exp)-1;
+                        int array=0;
+                        while(*ptr2 &&grub_isspace(*ptr2))ptr2++;
+                        while(grub_isspace(*endptr))
+                                endptr--;
+                        *(endptr+1)=0;
+                        if(ptr2[0]=='(')
+                                ptr2++,array=1;
+ script_env_set (exp, array?script_get_array(ptr2):ptr2);
+                        expcur[0] = '=';
+                        rtval=0;
+                        continue;
+                }
+                rtval=grub_exec_norm(exp);
+        }
+        return rtval;
+}





reply via email to

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