All of lore.kernel.org
 help / color / mirror / Atom feed
From: Serbinenko Vladimir <serbinenko.vova@list.ru>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: Re: Bash pre-alpha
Date: Mon, 31 Jan 2005 06:59:54 +0100	[thread overview]
Message-ID: <41FDC95A.1090703@list.ru> (raw)
In-Reply-To: <41FBCFFC.8060507@list.ru>

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 <serbinenko.vova@list.ru>
+
+  * 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 <serbinenko.vova@list.ru>
+
+        * 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 <serbinenko.vova@list.ru>
+
+        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  <okuji@enbug.org>
 
         * 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 <serbinenko.vova@list.ru>
+ *
+ *  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[*] arr[@]
+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	other threads:[~2005-01-31  6:16 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-01-12  9:44 Feature suggestion to grub Aki Tossavainen
2005-01-22 14:03 ` Marco Gerards
2005-01-22 15:18   ` Yoshinori K. Okuji
2005-01-22 16:19     ` Aki Tossavainen
2005-01-22 17:35       ` Yoshinori K. Okuji
2005-01-29 13:18         ` Bash pre-alpha Serbinenko Vladimir
2005-01-29 14:08           ` Serbinenko Vladimir
2005-01-29 16:04             ` Marco Gerards
2005-01-29 18:03               ` Serbinenko Vladimir
2005-01-31  5:59                 ` Serbinenko Vladimir [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=41FDC95A.1090703@list.ru \
    --to=serbinenko.vova@list.ru \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.