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;
+}
prev parent 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.