* Feature suggestion to grub
@ 2005-01-12 9:44 Aki Tossavainen
2005-01-22 14:03 ` Marco Gerards
0 siblings, 1 reply; 10+ messages in thread
From: Aki Tossavainen @ 2005-01-12 9:44 UTC (permalink / raw)
To: grub-devel
This is something I've been wondering a while, but would it be possible to
build a "failsafe" system for grub which would work as follows:
When grub loads an image and starts it, it'll write into a well-known
location value (say: 0), which means that the boot has not succeeded. Then
the booted system could write using a tool into the same location a value
(say: 1), which means that the boot succeeded. If the computer is booted
before the value has been changed, grub would choose next option or
failsafe
option to boot.
Does this sound like something that could be made?
---------------
Aki Tossavainen
cmouse@desteem.org
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Feature suggestion to grub
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
0 siblings, 1 reply; 10+ messages in thread
From: Marco Gerards @ 2005-01-22 14:03 UTC (permalink / raw)
To: The development of GRUB 2
Aki Tossavainen <cmouse@desteem.org> writes:
> This is something I've been wondering a while, but would it be possible to
> build a "failsafe" system for grub which would work as follows:
>
> When grub loads an image and starts it, it'll write into a well-known
> location value (say: 0), which means that the boot has not succeeded. Then
> the booted system could write using a tool into the same location a value
> (say: 1), which means that the boot succeeded. If the computer is booted
> before the value has been changed, grub would choose next option or
> failsafe
> option to boot.
>
> Does this sound like something that could be made?
Scripting is on the TODO, it is likely that for GRUB 2 such things
will be made possible. I have no idea yet how this will work...
--
Marco
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Feature suggestion to grub
2005-01-22 14:03 ` Marco Gerards
@ 2005-01-22 15:18 ` Yoshinori K. Okuji
2005-01-22 16:19 ` Aki Tossavainen
0 siblings, 1 reply; 10+ messages in thread
From: Yoshinori K. Okuji @ 2005-01-22 15:18 UTC (permalink / raw)
To: The development of GRUB 2
On Saturday 22 January 2005 15:03, Marco Gerards wrote:
> Aki Tossavainen <cmouse@desteem.org> writes:
> > This is something I've been wondering a while, but would it be
> > possible to build a "failsafe" system for grub which would work as
> > follows:
> >
> > When grub loads an image and starts it, it'll write into a
> > well-known location value (say: 0), which means that the boot has
> > not succeeded. Then the booted system could write using a tool into
> > the same location a value (say: 1), which means that the boot
> > succeeded. If the computer is booted before the value has been
> > changed, grub would choose next option or failsafe
> > option to boot.
> >
> > Does this sound like something that could be made?
>
> Scripting is on the TODO, it is likely that for GRUB 2 such things
> will be made possible. I have no idea yet how this will work...
GRUB Legacy already has this feature.
Okuji
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Feature suggestion to grub
2005-01-22 15:18 ` Yoshinori K. Okuji
@ 2005-01-22 16:19 ` Aki Tossavainen
2005-01-22 17:35 ` Yoshinori K. Okuji
0 siblings, 1 reply; 10+ messages in thread
From: Aki Tossavainen @ 2005-01-22 16:19 UTC (permalink / raw)
To: The development of GRUB 2
Um. Sorry, but I seem to be missing something here..
Yes there is failsafe option, but afaik it only affects when the kernel
cannot be booted. What if the kernel panics after it has been started for
example because it cannot mount root fs? How do you tell grub to boot the
next kernel next time?
----------
Aki Tossavainen
On Sat, 22 Jan 2005, Yoshinori K. Okuji wrote:
> On Saturday 22 January 2005 15:03, Marco Gerards wrote:
> > Aki Tossavainen <cmouse@desteem.org> writes:
> > > This is something I've been wondering a while, but would it be
> > > possible to build a "failsafe" system for grub which would work as
> > > follows:
> > >
> > > When grub loads an image and starts it, it'll write into a
> > > well-known location value (say: 0), which means that the boot has
> > > not succeeded. Then the booted system could write using a tool into
> > > the same location a value (say: 1), which means that the boot
> > > succeeded. If the computer is booted before the value has been
> > > changed, grub would choose next option or failsafe
> > > option to boot.
> > >
> > > Does this sound like something that could be made?
> >
> > Scripting is on the TODO, it is likely that for GRUB 2 such things
> > will be made possible. I have no idea yet how this will work...
>
> GRUB Legacy already has this feature.
>
> Okuji
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Feature suggestion to grub
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
0 siblings, 1 reply; 10+ messages in thread
From: Yoshinori K. Okuji @ 2005-01-22 17:35 UTC (permalink / raw)
To: The development of GRUB 2
On Saturday 22 January 2005 17:19, Aki Tossavainen wrote:
> Um. Sorry, but I seem to be missing something here..
> Yes there is failsafe option, but afaik it only affects when the
> kernel cannot be booted. What if the kernel panics after it has been
> started for example because it cannot mount root fs? How do you tell
> grub to boot the next kernel next time?
You must look at the CVS version. I haven't made a release after that
feature was added.
Okuji
^ permalink raw reply [flat|nested] 10+ messages in thread
* Bash pre-alpha
2005-01-22 17:35 ` Yoshinori K. Okuji
@ 2005-01-29 13:18 ` Serbinenko Vladimir
2005-01-29 14:08 ` Serbinenko Vladimir
0 siblings, 1 reply; 10+ messages in thread
From: Serbinenko Vladimir @ 2005-01-29 13:18 UTC (permalink / raw)
To: The development of GRUB 2
Here I prepared first preview version of bash scripting engine. I repeat
*first preview version*
That means I haven't really tested it nor cleaned up or commented. This
version is only for discussions.
For now supported features are:
arrays both syntaxes i=([0]=7 ...) and i[0]
arithmetic expansion and ((...))
commands echo, ':',source
Function support:
[function ] name() { list; }
Menu entries support like
entry "<description>" { list; }
Now configuration file is parsed the same way as any script file or
console entering
menu is automatically shown after configfile is parsed or you can use
showmenu command
In arithmetical expansion some additional commands are present:
i{9} means 10-th character of i
"i",'i' means string i
Associative arrays are supported: use
z['hello']=JJJ
This version is made in the goal to show my ideas and receive the
critics. Please send your suggestions,critics and bug-reports.
Known bugs:
possible segmentation faults at incorrect constructions
Not complete GCS compilance
Some plans:
See TODO in script.c
commands clear menu and unregister_entry
Bug fixing
----------------------------------------------------------------------------------------------------------------------
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/ChangeLog
./grub2/ChangeLog
--- ./grub2b/ChangeLog 2005-01-29 13:37:07.000000000 +0100
+++ ./grub2/ChangeLog 2005-01-29 14:00:55.000000000 +0100
@@ -1,3 +1,18 @@
+2005-01-29 Serbinenko Vladimir <serbinenko.vov@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-22 Hollis Blanchard <hollis@penguinppc.org>
* disk/powerpc/ieee1275/ofdisk.c (grub_ofdisk_open): Don't
initialize
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/conf/i386-pc.rmk
./grub2/conf/i386-pc.rmk
--- ./grub2b/conf/i386-pc.rmk 2005-01-29 13:37:07.000000000 +0100
+++ ./grub2/conf/i386-pc.rmk 2005-01-29 13:41:05.000000000 +0100
@@ -72,7 +72,7 @@
partmap/pc.c partmap/apple.c \
commands/terminal.c commands/boot.c commands/cmp.c
commands/cat.c \
util/i386/pc/biosdisk.c fs/fat.c fs/ext2.c fs/ufs.c fs/minix.c
fs/hfs.c fs/jfs.c fs/iso9660.c \
- normal/cmdline.c normal/command.c normal/main.c normal/menu.c
normal/arg.c \
+ normal/cmdline.c normal/command.c normal/script.c normal/main.c
normal/menu.c normal/arg.c \
util/console.c util/grub-emu.c util/misc.c
util/i386/pc/getroot.c disk/loopback.c
grub_emu_LDFLAGS = -lncurses
@@ -134,7 +134,7 @@
linux_mod_CFLAGS = $(COMMON_CFLAGS)
# For normal.mod.
-normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/main.c \
+normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/script.c
normal/main.c \
normal/menu.c normal/arg.c normal/i386/setjmp.S
normal_mod_CFLAGS = $(COMMON_CFLAGS)
normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
diff -b -B -r -u -E -N -x '*~' --expand-tabs
./grub2b/conf/powerpc-ieee1275.rmk ./grub2/conf/powerpc-ieee1275.rmk
--- ./grub2b/conf/powerpc-ieee1275.rmk 2005-01-29 13:37:07.000000000
+0100
+++ ./grub2/conf/powerpc-ieee1275.rmk 2005-01-29 13:42:19.000000000 +0100
@@ -38,7 +38,7 @@
partmap/amiga.c partmap/pc.c partmap/apple.c fs/fshelp.c \
util/i386/pc/biosdisk.c fs/fat.c fs/ext2.c fs/ufs.c fs/minix.c
fs/hfs.c \
fs/jfs.c fs/iso9660.c \
- normal/cmdline.c normal/command.c normal/main.c normal/menu.c \
+ normal/cmdline.c normal/command.c normal/script.c normal/main.c
normal/menu.c \
normal/arg.c kern/partition.c \
util/console.c util/grub-emu.c util/misc.c util/i386/pc/getroot.c \
kern/env.c disk/loopback.c commands/ls.c \
@@ -108,7 +108,7 @@
linux_mod_CFLAGS = $(COMMON_CFLAGS)
# For normal.mod.
-normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/main.c \
+normal_mod_SOURCES = normal/cmdline.c normal/command.c normal/script.c
normal/main.c \
normal/menu.c normal/arg.c normal/powerpc/setjmp.S
normal_mod_CFLAGS = $(COMMON_CFLAGS)
normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
diff -b -B -r -u -E -N -x '*~' --expand-tabs
./grub2b/include/grub/normal.h ./grub2/include/grub/normal.h
--- ./grub2b/include/grub/normal.h 2005-01-29 13:37:07.000000000 +0100
+++ ./grub2/include/grub/normal.h 2005-01-29 13:43:42.000000000 +0100
@@ -141,7 +141,7 @@
void grub_normal_init_page (void);
int grub_arg_parse (grub_command_t parser, int argc, char **argv,
struct grub_arg_list *usr, char ***args, int *argnum);
-
+int grub_exec_norm(char*exp);
#ifdef GRUB_UTIL
void grub_normal_init (void);
diff -b -B -r -u -E -N -x '*~' --expand-tabs
./grub2b/include/grub/script.h ./grub2/include/grub/script.h
--- ./grub2b/include/grub/script.h 1970-01-01 01:00:00.000000000 +0100
+++ ./grub2/include/grub/script.h 2005-01-29 12:25:56.000000000 +0100
@@ -0,0 +1,83 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003 Free Software Foundation, Inc.
+ *
+ * GRUB is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef SCRIPT_H
+#define SCRIPT_H 1
+#define EXPAND_BUF_SIZE 1024
+
+#define SCRIPT_BRACK 0
+#define SCRIPT_LEFT 1
+#define SCRIPT_RIGHT 2
+#define SCRIPT_BIN 3
+#define SCRIPT_TERN 4
+#define SCRIPT_AND 5
+#define SCRIPT_OR 6
+#define SCRIPT_LEFTS SCRIPT_LEFT
+#define SCRIPT_ARGPART 7
+#define SCRIPT_LVALUE 8
+#define SCRIPT_RASSOC 16
+#define SCRIPT_NEEDLVALUEA 16
+struct script_oper{
+ int priority;
+ char seq[10];
+ int type;
+ char* (*func_do)(char*a,char*b,int opn);
+};
+enum vartype {SCRIPT_STR,SCRIPT_VAR_NAME};
+extern struct script_oper script_opers[];
+int
+script_find_oper(char*exp,int searchleft);
+char*
+script_eval_arith(char*,enum vartype*);
+char*
+script_env_get(char*nm);
+void
+script_env_unset(char*nm);
+void
+script_env_set(char*nm,char*val);
+char*
+script_get_str(char*var,enum vartype tp);
+char*
+script_get_arrayelem(char*elem,char*indx);
+char*
+script_expand (char*cmdline,grub_err_t (* getline) (char
**),char**end,int flags);
+char*
+script_get_array(char*exp);
+char*
+script_escape_string(char*str);
+void
+script_unescape(char*str);
+void
+script_del_arrayelem(char**arr,char*indx);
+void
+script_add_arrayelem(char**arr,char*indx,char*val);
+int
+script_find_pas(char cbeg,char cend,char *str);
+int
+script_get_strend(char*str);
+int
+script_execute(char*cmdline,grub_err_t(*getline)(char**),char**rest);
+int
+script_exec_file (char*fname,int argc, char**argv);
+int
+script_list_execute(grub_menu_entry_t fn);
+grub_menu_t menu;
+#define EXPAND_DOLLAR 1
+#define EXPAND_ALL 1
+#endif /* ! SCRIPT_H*/
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/normal/command.c
./grub2/normal/command.c
--- ./grub2b/normal/command.c 2005-01-29 13:37:08.000000000 +0100
+++ ./grub2/normal/command.c 2005-01-29 13:53:55.000000000 +0100
@@ -24,6 +24,7 @@
#include <grub/term.h>
#include <grub/env.h>
#include <grub/dl.h>
+#include <grub/script.h>
static grub_command_t grub_command_list;
@@ -120,6 +121,11 @@
return grub_cmdline_get (">", *s, GRUB_MAX_CMDLINE, 0, 1);
}
+ return script_execute(cmdline,cmdline_get,0);
+}
+int
+grub_exec_norm(char*exp)
+{
grub_command_t cmd;
grub_err_t ret = 0;
char *pager;
@@ -130,21 +136,14 @@
int maxargs = 0;
char **arglist;
int numargs;
-
- if (grub_split_cmdline (cmdline, cmdline_get, &num, &args))
- return 0;
-
- /* In case of an assignment set the environment accordingly instead
- of calling a function. */
- if (num == 0 && grub_strchr (args[0], '='))
+ grub_err_t dummy_get (char **s)
{
- char *val = grub_strchr (args[0], '=');
- val[0] = 0;
- grub_env_set (args[0], val + 1);
- val[0] = '=';
+ *s = grub_malloc (3);
+ *s[0] = '\0';
return 0;
}
-
+ if (grub_split_cmdline (exp, dummy_get, &num, &args))
+ return 0;
cmd = grub_command_find (args[0]);
if (! cmd)
return -1;
@@ -218,7 +218,7 @@
}
val[0] = 0;
- grub_env_set (var, val + 1);
+ script_env_set (var, val + 1);
val[0] = '=';
return 0;
}
@@ -231,7 +231,7 @@
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"no environment variable specified");
- grub_env_unset (args[0]);
+ script_env_unset (args[0]);
return 0;
}
@@ -306,11 +306,54 @@
return 0;
}
+
+static grub_err_t
+echo_command (struct grub_arg_list *state __attribute__ ((unused)),
+ int argc,
+ char **args)
+{
+ int i;
+ for(i=0;i<argc;i++)
+ grub_printf ("%s ",args[i]);
+ return 0;
+}
+
+static grub_err_t
+empty_command (struct grub_arg_list *state __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ return 0;
+}
+
+static grub_err_t
+source_command (struct grub_arg_list *state __attribute__ ((unused)),
+ int argc,
+ char **args)
+{
+ if(!argc)
+ {
+ grub_error(GRUB_ERR_BAD_ARGUMENT,"Filename expected");
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+ return script_exec_file(args[0],argc-1,args+1);
+}
+static grub_err_t
+showmenu_command (struct grub_arg_list *state __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ if (menu->size)
+ grub_menu_run (menu, 0);
+ else
+ grub_cmdline_run (0);
+ return 0;
+}
+
+
void
grub_command_init (void)
{
- /* This is a special command, because this never be called actually. */
- grub_register_command ("title", 0, GRUB_COMMAND_FLAG_TITLE, 0, 0, 0);
grub_register_command ("rescue", rescue_command, GRUB_COMMAND_FLAG_BOTH,
"rescue", "Enter into the rescue mode.", 0);
@@ -329,4 +372,16 @@
grub_register_command ("lsmod", lsmod_command, GRUB_COMMAND_FLAG_BOTH,
"lsmod", "Show loaded modules.", 0);
+
+ grub_register_command ("echo", echo_command, GRUB_COMMAND_FLAG_BOTH,
+ "echo MESSAGE", "Print a message.", 0);
+
+ grub_register_command (":", empty_command, GRUB_COMMAND_FLAG_BOTH,
+ ":", "Does nothing except expanding.", 0);
+
+ grub_register_command ("source", source_command, GRUB_COMMAND_FLAG_BOTH,
+ "source FILE [ARGUMENTS ...]", "Execute script
FILE.", 0);
+
+ grub_register_command ("showmenu", showmenu_command,
GRUB_COMMAND_FLAG_BOTH,
+ "showmenu", "Show menu.", 0);
}
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/normal/main.c
./grub2/normal/main.c
--- ./grub2b/normal/main.c 2005-01-29 13:37:08.000000000 +0100
+++ ./grub2/normal/main.c 2005-01-29 13:57:28.000000000 +0100
@@ -32,74 +32,6 @@
#define GRUB_DEFAULT_HISTORY_SIZE 50
-/* Read a line from the file FILE. */
-static int
-get_line (grub_file_t file, char cmdline[], int max_len)
-{
- char c;
- int pos = 0;
- int literal = 0;
- int comment = 0;
-
- while (1)
- {
- if (grub_file_read (file, &c, 1) != 1)
- break;
-
- /* Skip all carriage returns. */
- if (c == '\r')
- continue;
-
- /* Replace tabs with spaces. */
- if (c == '\t')
- c = ' ';
-
- /* The previous is a backslash, then... */
- if (literal)
- {
- /* If it is a newline, replace it with a space and continue. */
- if (c == '\n')
- {
- c = ' ';
-
- /* Go back to overwrite the backslash. */
- if (pos > 0)
- pos--;
- }
-
- literal = 0;
- }
-
- if (c == '\\')
- literal = 1;
-
- if (comment)
- {
- if (c == '\n')
- comment = 0;
- }
- else if (pos == 0)
- {
- if (c == '#')
- comment = 1;
- else if (! grub_isspace (c))
- cmdline[pos++] = c;
- }
- else
- {
- if (c == '\n')
- break;
-
- if (pos < max_len)
- cmdline[pos++] = c;
- }
- }
-
- cmdline[pos] = '\0';
-
- return pos;
-}
-
static void
free_menu (grub_menu_t menu)
{
@@ -125,148 +57,6 @@
grub_free (menu);
}
-/* Read the config file CONFIG and return a menu. If no entry is present,
- return NULL. */
-static grub_menu_t
-read_config_file (const char *config)
-{
- grub_file_t file;
- static char cmdline[GRUB_MAX_CMDLINE];
- grub_menu_t menu;
- grub_menu_entry_t *next_entry, cur_entry = 0;
- grub_command_list_t *next_cmd, cur_cmd;
-
- /* Try to open the config file. */
- file = grub_file_open (config);
- if (! file)
- return 0;
-
- /* Initialize the menu. */
- menu = (grub_menu_t) grub_malloc (sizeof (*menu));
- if (! menu)
- {
- grub_file_close (file);
- return 0;
- }
- menu->default_entry = 0;
- menu->fallback_entry = -1;
- menu->timeout = -1;
- menu->size = 0;
- menu->entry_list = 0;
-
- next_entry = &(menu->entry_list);
- next_cmd = 0;
-
- /* Read each line. */
- while (get_line (file, cmdline, sizeof (cmdline)))
- {
- grub_command_t cmd;
-
- cmd = grub_command_find (cmdline);
- grub_errno = GRUB_ERR_NONE;
- if (! cmd)
- {
- grub_printf ("Unknown command `%s' is ignored.\n", cmdline);
- continue;
- }
-
- if (cmd->flags & GRUB_COMMAND_FLAG_TITLE)
- {
- char *p;
-
- cur_entry = (grub_menu_entry_t) grub_malloc (sizeof
(*cur_entry));
- if (! cur_entry)
- goto fail;
-
- p = grub_strchr (cmdline, ' ');
- if (p)
- cur_entry->title = grub_strdup (p);
- else
- cur_entry->title = grub_strdup ("");
-
- if (! cur_entry->title)
- {
- grub_free (cur_entry);
- goto fail;
- }
-
- cur_entry->num = 0;
- cur_entry->command_list = 0;
- cur_entry->next = 0;
-
- *next_entry = cur_entry;
- next_entry = &(cur_entry->next);
-
- next_cmd = &(cur_entry->command_list);
-
- menu->size++;
- }
- else if (! cur_entry)
- {
- /* Run the command if possible. */
- if (cmd->flags & GRUB_COMMAND_FLAG_MENU)
- {
- grub_command_execute (cmdline);
- grub_print_error ();
- grub_errno = GRUB_ERR_NONE;
- }
- else
- {
- grub_printf ("Invalid command `%s' is ignored.\n", cmdline);
- continue;
- }
- }
- else
- {
- cur_cmd = (grub_command_list_t) grub_malloc (sizeof (*cur_cmd));
- if (! cur_cmd)
- goto fail;
-
- cur_cmd->command = grub_strdup (cmdline);
- if (! cur_cmd->command)
- {
- grub_free (cur_cmd);
- goto fail;
- }
-
- cur_cmd->next = 0;
-
- *next_cmd = cur_cmd;
- next_cmd = &(cur_cmd->next);
-
- cur_entry->num++;
- }
- }
-
- fail:
-
- grub_file_close (file);
-
- /* If no entry was found or any error occurred, return NULL. */
- if (menu->size == 0 || grub_errno != GRUB_ERR_NONE)
- {
- free_menu (menu);
- return 0;
- }
-
- /* Check values of the default entry and the fallback one. */
- if (menu->fallback_entry >= menu->size)
- menu->fallback_entry = -1;
-
- if (menu->default_entry < 0 || menu->default_entry >= menu->size)
- {
- if (menu->fallback_entry < 0)
- menu->default_entry = 0;
- else
- {
- menu->default_entry = menu->fallback_entry;
- menu->fallback_entry = -1;
- }
- }
-
- return menu;
-}
-
/* This starts the normal mode. */
void
grub_enter_normal_mode (const char *config)
@@ -285,22 +75,32 @@
PACKAGE_VERSION);
}
+struct grub_menu pre_menu=
+ {
+ .size=0,
+ .default_entry = 0,
+ .fallback_entry = -1,
+ .timeout = -1,
+ .entry_list = 0,
+ };
+
+grub_menu_t menu = &pre_menu;
+
/* Read the config file CONFIG and execute the menu interface or
the command-line interface. */
void
grub_normal_execute (const char *config, int nested)
{
- grub_menu_t menu = 0;
if (config)
{
- menu = read_config_file (config);
+ script_exec_file (config,0,0);
/* Ignore any error. */
grub_errno = GRUB_ERR_NONE;
}
- if (menu)
+ if (menu->size)
grub_menu_run (menu, nested);
else
grub_cmdline_run (nested);
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/normal/menu.c
./grub2/normal/menu.c
--- ./grub2b/normal/menu.c 2005-01-29 13:37:08.000000000 +0100
+++ ./grub2/normal/menu.c 2005-01-29 14:00:10.000000000 +0100
@@ -23,6 +23,7 @@
#include <grub/loader.h>
#include <grub/mm.h>
#include <grub/machine/time.h>
+#include <grub/script.h>
/* FIXME: These below are all runaround. */
@@ -238,140 +239,7 @@
static int
run_menu (grub_menu_t menu, int nested)
{
- int first, offset;
- unsigned long saved_time;
-
- first = 0;
- offset = menu->default_entry;
- if (offset > TERM_NUM_ENTRIES - 1)
- {
- first = offset - (TERM_NUM_ENTRIES - 1);
- offset = TERM_NUM_ENTRIES - 1;
- }
-
- /* Initialize the time. */
- saved_time = grub_get_rtc ();
-
- refresh:
- grub_setcursor (0);
- init_page (nested, 0);
- print_entries (menu, first, offset);
- grub_refresh ();
-
- while (1)
- {
- int c;
-
- if (menu->timeout > 0)
- {
- unsigned long current_time;
-
- current_time = grub_get_rtc ();
- if (current_time - saved_time >= GRUB_TICKS_PER_SECOND)
- {
- menu->timeout--;
- saved_time = current_time;
- }
-
- grub_gotoxy (0, TERM_HEIGHT - 3);
- /* NOTE: Do not remove the trailing space characters.
- They are required to clear the line. */
- grub_printf ("\
- The highlighted entry will be booted automatically in %d seconds. ",
- menu->timeout);
- grub_gotoxy (TERM_CURSOR_X, TERM_FIRST_ENTRY_Y + offset);
- grub_refresh ();
- }
-
- if (menu->timeout == 0)
- return menu->default_entry;
-
- if (grub_checkkey () >= 0 || menu->timeout < 0)
- {
- c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
-
- if (menu->timeout >= 0)
- {
- grub_gotoxy (0, TERM_HEIGHT - 3);
- grub_printf ("\
- ");
- menu->timeout = -1;
- menu->fallback_entry = -1;
- grub_gotoxy (TERM_CURSOR_X, TERM_FIRST_ENTRY_Y + offset);
- }
-
- switch (c)
- {
- case 16:
- case '^':
- if (offset > 0)
- {
- print_entry (TERM_FIRST_ENTRY_Y + offset, 0,
- get_entry (menu, first + offset));
- offset--;
- print_entry (TERM_FIRST_ENTRY_Y + offset, 1,
- get_entry (menu, first + offset));
- }
- else if (first > 0)
- {
- first--;
- print_entries (menu, first, offset);
- }
- break;
-
- case 14:
- case 'v':
- if (menu->size > first + offset + 1)
- {
- if (offset < TERM_NUM_ENTRIES - 1)
- {
- print_entry (TERM_FIRST_ENTRY_Y + offset, 0,
- get_entry (menu, first + offset));
- offset++;
- print_entry (TERM_FIRST_ENTRY_Y + offset, 1,
- get_entry (menu, first + offset));
- }
- else
- {
- first++;
- print_entries (menu, first, offset);
- }
- }
- break;
-
- case '\n':
- case '\r':
- case 6:
- grub_setcursor (1);
- return first + offset;
-
- case '\e':
- if (nested)
- {
- grub_setcursor (1);
- return -1;
- }
- break;
-
- case 'c':
- grub_setcursor (1);
- grub_cmdline_run (1);
- goto refresh;
-
- case 'e':
- edit_menu_entry (get_entry (menu, first + offset));
- goto refresh;
-
- default:
- break;
- }
-
- grub_refresh ();
- }
- }
-
- /* Never reach here. */
- return -1;
+ return script_list_execute(entry);
}
/* Run a menu entry. */
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2b/normal/script.c
./grub2/normal/script.c
--- ./grub2b/normal/script.c 1970-01-01 01:00:00.000000000 +0100
+++ ./grub2/normal/script.c 2005-01-29 13:07:27.000000000 +0100
@@ -0,0 +1,1983 @@
+/* script.c - scripting engine */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2003 NIIBE Yutaka <gniibe@m17n.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/env.h>
+#include <grub/script.h>
+#include <grub/file.h>
+
+/*TODO:
+alpha:
+GCS cleanup
+cond expr [[ ... ]], [...]
+for,while,until
+
+beta:
+select,case
+local and function and script file parameters
+expansions:
+ braces{}
+ ${..:..},...
+ pathname
+built-in coms
+built-in vars
+``,$()
+
+gamma:
+**
+pipes
+subshell,(list)
+$'...' $"..."
+arr[*] 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;
+}
+
+char*
+script_strrchr(char*str,char c)
+{
+ char*expcur,*rtval=0;
+ for(expcur=str;*expcur;expcur++)
+ {
+ if(*expcur==c)
+ rtval=expcur;
+ if(*expcur=='\\')
+ {
+ expcur+=2;
+ continue;
+ }
+ if(*expcur=='(')
+ {
+ expcur+=script_find_pas('(',')',expcur);
+ continue;
+ }
+ if(*expcur=='{')
+ {
+ expcur+=script_find_pas('{','}',expcur);
+ continue;
+ }
+ if(*expcur=='[')
+ {
+ expcur+=script_find_pas('[',']',expcur);
+ continue;
+ }
+ if(*expcur=='"' || *expcur=='\'')
+ {
+ expcur+=script_get_strend(expcur);
+ continue;
+ }
+ }
+ return rtval;
+}
+
+char*
+script_env_get(char*nm)
+{
+ if(script_strrchr(nm,'['))
+ {
+ char*eptr=script_strrchr(nm,'[');
+ char*ptr=eptr+1;
+ ptr+=script_find_pas('[',']',ptr);
+ char c=*ptr,c2=*eptr;
+ *ptr=0;
+ *eptr=0;
+ enum vartype vtp;
+
char*tm=script_eval_arith(script_expand(eptr+1,0,0,EXPAND_DOLLAR),&vtp);
+
char*rtval=script_get_arrayelem(script_env_get(nm),script_get_str(tm,vtp));
+ *ptr=c;
+ *eptr=c2;
+ if(!rtval)
+ {
+ rtval=grub_malloc(3);
+ *rtval=0;
+ }
+ return rtval;
+ }
+ return grub_env_get(nm);
+}
+
+int
+script_get_strend(char*str)
+{
+ char c=str[0];int i;
+ for(i=1;str[i]!=c && str[i];i++)
+ if(str[i]=='\\')
+ i++;
+ return i;
+}
+
+/*Finds closing brace corresponding to specificied opening.
+str must point to the first character after opening brace.
+cbeg and cend must contain opening and closing brace respectivelly('('
and ')' or '{' and '}')
+Return vale is so that str+value points to closing brace */
+
+int
+script_find_pas(char cbeg,char cend,char *str)
+{
+ int op=1,i;
+ for(i=0;op&&str[i];i++)
+ {
+ if(str[i]=='\\')
+ {
+ i+=2;
+ continue;
+ }
+ if(str[i]=='"' || str[i]=='\'')
+ {
+ i+=script_get_strend(str+i);
+ continue;
+ }
+ if(str[i]==cbeg)op++;
+ if(str[i]==cend)op--;
+ }
+ return i-1;
+}
+void
+script_env_unset(char*nm)
+{
+ if(script_strrchr(nm,'['))
+ {
+ char*eptr=script_strrchr(nm,'[');
+ char*ptr=eptr+1;
+ ptr+=script_find_pas('[',']',ptr);
+ char c=*ptr,c2=*eptr;
+ *ptr=0;
+ *eptr=0;
+ char*arr=script_env_get(nm);
+ if(!arr)
+ return;
+ enum vartype vtp;
+
char*tm=script_eval_arith(script_expand(eptr+1,0,0,EXPAND_DOLLAR),&vtp);
+ script_del_arrayelem(&arr,script_get_str(tm,vtp));
+ grub_env_set(nm,arr);
+ *ptr=c;
+ *eptr=c2;
+ return ;
+ }
+ grub_env_unset(nm);
+}
+
+void
+script_env_set(char*nm,char*val)
+{
+ if(script_strrchr(nm,'['))
+ {
+ char*eptr=script_strrchr(nm,'[');
+ char*ptr=eptr+1;
+ ptr+=script_find_pas('[',']',ptr);
+ char c=*ptr,c2=*eptr;
+ *ptr=0;
+ *eptr=0;
+ char*arr=script_env_get(nm);
+ if(!arr)
+ {
+ arr=grub_malloc(3);
+ arr[0]=0;
+ }
+ else
+ arr=script_dupstr(arr);
+ enum vartype vtp;
+
char*tm=script_eval_arith(script_expand(eptr+1,0,0,EXPAND_DOLLAR),&vtp);
+
script_add_arrayelem(&arr,script_get_str(tm,vtp),script_dupstr(val));
+ grub_env_set(nm,arr);
+ *ptr=c;
+ *eptr=c2;
+ return ;
+ }
+ grub_env_set(nm,val);
+}
+
+char*
+script_get_str(char*var,enum vartype tp)
+{
+ char*rtval;
+ switch(tp)
+ {
+ case SCRIPT_STR:
+ if(var)
+ return var;
+ rtval=grub_malloc(3);
+ *rtval=0;
+ return rtval;
+ case SCRIPT_VAR_NAME:
+ {
+ char*tmp;
+ tmp=script_env_get(var);
+ grub_free(var);
+ if(!tmp){
+ rtval=grub_malloc(sizeof(char));
+ rtval[0]=0;
+ return rtval;
+ }
+
rtval=grub_malloc(sizeof(char)*(grub_strlen(tmp)+1));
+
grub_memcpy(rtval,tmp,sizeof(char)*(grub_strlen(tmp)+1));
+ return rtval;
+ }
+ }
+ return 0;
+}
+
+int
+grub_strtol(char*exp,char**end,int base)
+{
+ while(grub_isspace(*exp))
+ exp++;
+ if(*exp=='-')
+ return -grub_strtoul(exp+1,end,base);
+ else
+ return grub_strtoul(exp,end,base);
+}
+
+int
+script_strtol(char*str)
+{
+ /*TODO: base#*/
+ char*end;
+
+ int rtval=grub_strtol(str,&end,0);
+ grub_free(str);
+ return rtval;
+}
+
+char*
+script_ltostr(int vl){
+ char *s=grub_malloc(12*sizeof(char)),*t=s;
+ if(vl<0)
+ *(t++)='-',vl=-vl;
+ grub_sprintf(t,"%d",vl);
+ return s;
+}
+
+char*
+script_getnum(char**exp)
+{
+ return script_ltostr(grub_strtol(*exp,exp,0));
+}
+
+/*operator {}*/
+char*
+script_char_str(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ int n=script_strtol(b);
+ char *rtval=grub_malloc(3*sizeof(char));
+ rtval[1]=0;
+ rtval[0]=(n<0 || grub_strlen(a)>=(unsigned)n)?0:a[n];
+ return rtval;
+}
+
+int
+script_get_bool(char*a)
+{
+ int rtval=a && (grub_isdigit(a[0]) || (a[0]!='-' &&
!grub_isdigit(a[1]))) && grub_strcmp(a,"0") && grub_strcmp(a,"-0");
+ grub_free(a);
+ return rtval;
+}
+
+/*Operator !*/
+char*
+script_bool_not(char*a,char*b __attribute__ ((unused)),int opn
__attribute__ ((unused)))
+{
+ char *rtval=grub_malloc(3*sizeof(char));
+ rtval[1]=0;
+ if(!script_get_bool(a))
+ rtval[0]='1';
+ else
+ rtval[0]='0';
+ return rtval;
+}
+
+/*Operator ~*/
+char*
+script_bin_not(char*a,char*b __attribute__ ((unused)),int opn
__attribute__ ((unused)))
+{
+ return script_ltostr(!script_strtol(a));
+}
+
+/*Unary -*/
+char*
+script_neg(char*a,char*b __attribute__ ((unused)),int opn __attribute__
((unused)))
+{
+ return script_ltostr(-script_strtol(a));
+}
+/*Unary +*/
+char*
+script_pos(char*a,char*b __attribute__ ((unused)),int opn __attribute__
((unused)))
+{
+ return script_ltostr(-script_strtol(a));
+}
+
+/*Binary +*/
+char*
+script_add(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ return script_ltostr(script_strtol(a)+script_strtol(b));
+}
+
+/*Binary +*/
+char*
+script_sub(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ return script_ltostr(script_strtol(a)-script_strtol(b));
+}
+
+/*Binary **/
+char*
+script_mult(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ return script_ltostr(script_strtol(a)*script_strtol(b));
+}
+
+/*Binary /*/
+char*
+script_div(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ return script_ltostr(script_strtol(a)/script_strtol(b));
+}
+
+/*Binary %*/
+char*
+script_mod(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ return script_ltostr(script_strtol(a)%script_strtol(b));
+}
+
+/*Binary <<*/
+char*
+script_binl(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ return script_ltostr(script_strtol(a)<<script_strtol(b));
+}
+
+/*Binary >>*/
+char*
+script_binr(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ return script_ltostr(script_strtol(a)>>script_strtol(b));
+}
+
+/*Operators >, <, <=, >=*/
+char*
+script_cmpop(char*a,char*b,int opn)
+{
+ char*rtval=grub_malloc(3*sizeof(char));
+ int cmpval=grub_strcmp(a,b);
+ if(script_opers[opn].seq[1]=='=' && cmpval==0)
+ {
+ rtval[0]='1';
+ return rtval;
+ }
+ if(script_opers[opn].seq[0]=='<')
+ rtval[0]=(cmpval<0)?'1':'0';
+ else
+ rtval[0]=(cmpval>0)?'1':'0';
+ return rtval;
+}
+
+/*Operators !=,==,<>*/
+char*
+script_eqop(char*a,char*b,int opn)
+{
+ int cnt=1;
+ char*rtval=grub_malloc(3*sizeof(char));
+ rtval[1]=0;
+ if(cnt && grub_strcmp(a,b)!=0)
+ cnt=0;
+ if(script_opers[opn].seq[0]=='!' || script_opers[opn].seq[0]=='<')
+ cnt=!cnt;
+ rtval[0]=cnt?'1':'0';
+ return rtval;
+}
+
+/*Binary ^*/
+char*
+script_bxor(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ return script_ltostr(script_strtol(a)^script_strtol(b));
+}
+/*Binary |*/
+char*
+script_bor(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ return script_ltostr(script_strtol(a)|script_strtol(b));
+}
+
+/*Binary &*/
+char*
+script_band(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ return script_ltostr(script_strtol(a)&script_strtol(b));
+}
+
+/*logic xor*/
+char*
+script_logicxor(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ char *rtval=grub_malloc(3*sizeof(char));
+ rtval[1]=0;
+ if(script_get_bool(a)!=script_get_bool(b))
+ rtval[0]='1';
+ else
+ rtval[0]='0';
+ return rtval;
+}
+
+/*Operator ,*/
+char*
+script_comma(char*a __attribute__ ((unused)),char*b,
+ int opn __attribute__ ((unused)))
+{
+ return b;
+}
+
+/*Operator =*/
+char*
+script_set(char*a, char*b,int opn __attribute__ ((unused)))
+{
+ script_env_set(a,b);
+ return a;
+}
+
+/*Operators ...=*/
+char*
+script_setop(char*a, char*b,int opn)
+{
+ char tm[3]={0,0,0};
+ char*val=script_dupstr(a);
+ tm[0]=script_opers[opn].seq[0];
+ if(script_opers[opn].seq[1]!='=')
+ tm[1]=script_opers[opn].seq[1];
+ int op=script_find_oper(tm,0);
+
script_env_set(a,script_opers[op].func_do(script_get_str(val,SCRIPT_VAR_NAME),b,op));
+ return a;
+}
+
+/*Operator .*/
+char*
+script_concat(char*a,char*b,int opn __attribute__ ((unused)))
+{
+ grub_realloc(a,grub_strlen(a)+grub_strlen(b));
+ grub_memcpy(a+grub_strlen(a),b,grub_strlen(b)+1);
+ grub_free(b);
+ return a;
+}
+static char*
+script_incl(char*a,char*b __attribute__((unused)),int op
__attribute__((unused)))
+{
+ int intval;
+ char*val=script_dupstr(a);
+
script_env_set(val,script_ltostr((intval=script_strtol(script_get_str(a,SCRIPT_VAR_NAME)))+1));
+ grub_free(val);
+ return script_ltostr(intval+1);
+}
+static char*
+script_decl(char*a,char*b __attribute__((unused)),int op
__attribute__((unused)))
+{
+ int intval;
+ char*val=script_dupstr(a);
+
script_env_set(val,script_ltostr((intval=script_strtol(script_get_str(a,SCRIPT_VAR_NAME)))-1));
+ grub_free(val);
+ return script_ltostr(intval-1);
+}
+static char*
+script_incr(char*a,char*b __attribute__((unused)),int op
__attribute__((unused)))
+{
+ int intval;
+ char*val=script_dupstr(a);
+
script_env_set(val,script_ltostr((intval=script_strtol(script_get_str(a,SCRIPT_VAR_NAME)))+1));
+ grub_free(val);
+ return script_ltostr(intval);
+}
+static char*
+script_decr(char*a,char*b __attribute__((unused)),int op
__attribute__((unused)))
+{
+ int intval;
+ char*val=script_dupstr(a);
+
script_env_set(val,script_ltostr((intval=script_strtol(script_get_str(a,SCRIPT_VAR_NAME)))-1));
+ grub_free(val);
+ return script_ltostr(intval);
+}
+/*Array of possible operators*/
+struct script_oper script_opers[]={
+//{.priority=190, .seq="[", .func_do=script_elemarray,
.type=SCRIPT_BRACK|SCRIPT_LVALUE},
+{.priority=190, .seq="{", .func_do=script_char_str, .type=SCRIPT_BRACK},
+{.priority=180, .seq="!", .func_do=script_bool_not,
.type=SCRIPT_LEFT|SCRIPT_RASSOC},
+{.priority=180, .seq="~", .func_do=script_bin_not,
.type=SCRIPT_LEFT|SCRIPT_RASSOC},
+{.priority=180, .seq="++", .func_do=script_incl,
.type=SCRIPT_LEFT|SCRIPT_NEEDLVALUEA|SCRIPT_RASSOC},
+{.priority=180, .seq="++", .func_do=script_incr,
.type=SCRIPT_RIGHT|SCRIPT_NEEDLVALUEA},
+{.priority=180, .seq="--", .func_do=script_decl,
.type=SCRIPT_LEFT|SCRIPT_NEEDLVALUEA|SCRIPT_RASSOC},
+{.priority=180, .seq="--", .func_do=script_decr,
.type=SCRIPT_RIGHT|SCRIPT_NEEDLVALUEA},
+{.priority=180, .seq="-", .func_do=script_neg,
.type=SCRIPT_LEFT|SCRIPT_RASSOC},
+{.priority=180, .seq="+", .func_do=script_pos,
.type=SCRIPT_LEFT|SCRIPT_RASSOC},
+{.priority=170, .seq="*", .func_do=script_mult, .type=SCRIPT_BIN},
+{.priority=170, .seq="/", .func_do=script_div, .type=SCRIPT_BIN},
+{.priority=170, .seq="%", .func_do=script_mod, .type=SCRIPT_BIN},
+{.priority=160, .seq="+", .func_do=script_add, .type=SCRIPT_BIN},
+{.priority=160, .seq="-", .func_do=script_sub, .type=SCRIPT_BIN},
+{.priority=160, .seq=".", .func_do=script_concat, .type=SCRIPT_BIN},
+{.priority=150, .seq=">>", .func_do=script_binr, .type=SCRIPT_BIN},
+{.priority=150, .seq="<<", .func_do=script_binl, .type=SCRIPT_BIN},
+{.priority=140, .seq="<=", .func_do=script_cmpop, .type=SCRIPT_BIN},
+{.priority=140, .seq="<", .func_do=script_cmpop, .type=SCRIPT_BIN},
+{.priority=140, .seq=">=", .func_do=script_cmpop, .type=SCRIPT_BIN},
+{.priority=140, .seq=">", .func_do=script_cmpop, .type=SCRIPT_BIN},
+{.priority=130, .seq="==", .func_do=script_eqop, .type=SCRIPT_BIN},
+{.priority=130, .seq="!=", .func_do=script_eqop, .type=SCRIPT_BIN},
+{.priority=130, .seq="<>", .func_do=script_eqop, .type=SCRIPT_BIN},
+{.priority=120, .seq="&", .func_do=script_band, .type=SCRIPT_BIN},
+{.priority=110, .seq="^", .func_do=script_bxor, .type=SCRIPT_BIN},
+{.priority=100, .seq="|", .func_do=script_bor, .type=SCRIPT_BIN},
+{.priority=90, .seq="&&", .func_do=0, .type=SCRIPT_AND},
+{.priority=80, .seq="||", .func_do=0, .type=SCRIPT_OR},
+{.priority=70, .seq="?", .func_do=0, .type=SCRIPT_TERN},//? :
+{.priority=60, .seq="=", .func_do=script_set,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq="+=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq="-=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq="*=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq="/=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq="%=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq="&=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq="^=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq="|=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq=">>=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq="<<=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=60, .seq=".=", .func_do=script_setop,
.type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
+{.priority=40, .seq="and", .func_do=0, .type=SCRIPT_AND},
+{.priority=30, .seq="xor", .func_do=script_logicxor, .type=SCRIPT_BIN},
+{.priority=20, .seq="or", .func_do=0, .type=SCRIPT_OR},
+{.priority=10, .seq=",", .func_do=script_comma, .type=SCRIPT_BIN},
+};
+
+int
+script_islexend(char c)
+{
+ return !(c &&(grub_isalpha(c) ||grub_isdigit(c) ||c=='_'));
+}
+
+int
+script_isfuncbeg(char*str)
+{
+ while(*str && grub_isspace(*str))str++;
+ if(!*str)
+ return 0;
+ if(!grub_memcmp(str,"function",sizeof("function")-1) &&
script_islexend(str[sizeof("function")-1]))
+ return 1;
+ if(!grub_memcmp(str,"entry",sizeof("entry")-1) &&
script_islexend(str[sizeof("entry")-1]))
+ return 1;
+ while(*str && !script_islexend(*str))str++;
+ if(!*str)
+ return 0;
+ if(*str!='(')
+ return 0;
+ str++;
+ if(!*str)
+ return 0;
+ while(*str && grub_isspace(*str))str++;
+ if(!*str)
+ return 0;
+ if(*str!=')')
+ return 0;
+ return 1;
+}
+void
+script_skipfuncbeg(char**exp)
+{
+ while(**exp && grub_isspace(**exp))(*exp)++;
+ if(!grub_memcmp(*exp,"entry",sizeof("entry")-1) &&
script_islexend((*exp)[sizeof("entry")-1]))
+ *exp+=sizeof("entry")-1;
+ if(!grub_memcmp(*exp,"function",sizeof("function")-1) &&
script_islexend((*exp)[sizeof("function")-1]))
+ *exp+=sizeof("function")-1;
+ switch(**exp)
+ {
+ case '"':
+ case '\'':
+ *exp+=script_get_strend(*exp)+1;
+ break;
+ default:
+ while(!script_islexend(**exp))
+ (*exp)++;
+ }
+ while(grub_isspace(**exp))(*exp)++;
+ if(**exp=='(')(*exp)++;//skip (
+ while(grub_isspace(**exp))(*exp)++;
+ if(**exp==')')(*exp)++;//skip )
+}
+
+
+int
+script_find_oper(char*exp,int searchleft)
+{
+ unsigned i, lenfound=0;int foundn=-1;
+ for(i=0;i<sizeof(script_opers)/sizeof(script_opers[0]);i++)
+ if(grub_strlen(script_opers[i].seq)>lenfound &&
+
((searchleft==((script_opers[i].type&SCRIPT_ARGPART)==SCRIPT_LEFT)) ||
(searchleft==2))
+ &&
!grub_memcmp(script_opers[i].seq,exp,grub_strlen(script_opers[i].seq))
+
&&(script_islexend(exp[grub_strlen(script_opers[i].seq)-1]
||script_islexend(exp[grub_strlen(script_opers[i].seq)]))))
+
foundn=i,lenfound=grub_strlen(script_opers[i].seq);
+ return foundn;
+}
+
+char*
+script_list_arrayelems(char**elem)
+{
+ char*indxbeg,*indxend;
+ if(!**elem)
+ return 0;
+ while(grub_isspace(**elem))(*elem)++;
+ if(**elem!='[')
+ return 0;
+ (*elem)++;
+ if(**elem!='\'')
+ return 0;
+ indxbeg=*elem+1;
+ *elem+=script_get_strend(*elem);
+ indxend=*elem;
+ (*elem)++;
+ if(**elem!=']')
+ return 0;
+ (*elem)++;
+ if(**elem!='=')
+ return 0;
+ (*elem)++;
+ if(**elem!='\'')
+ return 0;
+ *elem+=script_get_strend(*elem);
+ (*elem)++;
+ char*rtval=grub_malloc(indxend-indxbeg+1);
+ grub_memcpy(rtval,indxbeg,indxend-indxbeg);
+ rtval[indxend-indxbeg]=0;
+ return rtval;
+}
+char*
+script_get_arrayelem(char*elem,char*indx)
+{
+ char*escindx=script_escape_string(indx);
+ grub_free(indx);
+ char*indxbeg,*indxend;
+ char*valbeg=0,*valend=0;
+ while(1)
+ {
+ if(!*elem)
+ return 0;
+ while(grub_isspace(*elem))elem++;
+ if(*elem!='[')
+ return 0;
+ elem++;
+ if(*elem!='\'')
+ return 0;
+ indxbeg=elem+1;
+ elem+=script_get_strend(elem);
+ indxend=elem;
+ elem++;
+ if(*elem!=']')
+ return 0;
+ elem++;
+ if(*elem!='=')
+ return 0;
+ elem++;
+ if(*elem!='\'')
+ return 0;
+ valbeg=elem+1;
+ elem+=script_get_strend(elem);
+ valend=elem;
+ elem++;
+ if((unsigned)(indxend-indxbeg)==grub_strlen(escindx) &&
!grub_memcmp(indxbeg,escindx,indxend-indxbeg))
+ {
+ char*rtval=grub_malloc(valend-valbeg+1);
+ grub_memcpy(rtval,valbeg,valend-valbeg);
+ rtval[valend-valbeg]=0;
+ script_unescape(rtval);
+ return rtval;
+ }
+ }
+}
+#define STR_BUFFER 256
+char*
+script_escape_string(char*str)
+{
+ char*res=grub_malloc(STR_BUFFER),*rptr=res;
+ char*ptr=str;
+ while(*ptr)
+ {
+ if((rptr-res+2)%STR_BUFFER==0)
+ {
+ int delta=rptr-res;
+ res=grub_realloc(res,rptr-res+2+STR_BUFFER);
+ rptr=res+delta;
+ }
+ if(*ptr=='\'' || *ptr=='\\')
+ *(rptr++)='\\';
+ *(rptr++)=*(ptr++);
+ }
+ *(rptr++)=*(ptr++);
+ return res;
+}
+void
+script_del_arrayelem(char**arr,char*indx)
+{
+ char*escindx=script_escape_string(indx);
+ grub_free(indx);
+ char*arptr=*arr;
+ char*prevarptr=*arr;
+ char*curindx;
+ int wfnd=0;
+ while(*arptr)
+ {
+ prevarptr=arptr;
+ curindx=script_list_arrayelems(&arptr);
+ if(!curindx)
+ break;
+ if(!grub_strcmp(escindx,curindx))
+ {
+ grub_free(curindx);
+ wfnd=1;
+ break;
+ }
+ grub_free(curindx);
+ }
+ if(wfnd)
+ while(*arptr)
+ *(prevarptr++)=*(arptr++);
+ else
+ prevarptr=arptr;
+ int delta=prevarptr-*arr;
+ *arr=grub_realloc(*arr,delta+1);
+ (*arr)[delta]=0;
+}
+void
+script_add_arrayelem(char**arr,char*indx,char*val)
+{
+ char*escval=script_escape_string(val);
+ char*escindx=script_escape_string(indx);
+ grub_free(indx);
+ grub_free(val);
+ char*arptr=*arr;
+ char*prevarptr=*arr;
+ char*curindx;
+ int wfnd=0;
+ while(*arptr)
+ {
+ prevarptr=arptr;
+ curindx=script_list_arrayelems(&arptr);
+ if(!curindx)
+ break;
+ if(!grub_strcmp(escindx,curindx))
+ {
+ grub_free(curindx);
+ wfnd=1;
+ break;
+ }
+ grub_free(curindx);
+ }
+ if(wfnd)
+ while(*arptr)
+ *(prevarptr++)=*(arptr++);
+ else
+ prevarptr=arptr;
+ int delta=prevarptr-*arr;
+
*arr=grub_realloc(*arr,delta+grub_strlen(escindx)+grub_strlen(escval)+9);
+ char*ptr=*arr+delta;
+ ptr[0]=' ';
+ ptr[1]='[';
+ ptr[2]='\'';
+ ptr+=3;
+ grub_memcpy(ptr,escindx,grub_strlen(escindx));
+ ptr+=grub_strlen(escindx);
+ ptr[0]='\'';
+ ptr[1]=']';
+ ptr[2]='=';
+ ptr[3]='\'';
+ ptr+=4;
+ grub_memcpy(ptr,escval,grub_strlen(escval));
+ ptr+=grub_strlen(escval);
+ ptr[0]='\'';
+ ptr[1]=0;
+}
+
+void
+script_unescape(char*str)
+{
+ char*to=str,*from=str;
+ while(*from)
+ {
+ if(*to=='\\')
+ {
+ from++;
+ switch(*(from++))
+ {
+ case 'n':
+ *(to++)='\n';
+ break;
+ case 'r':
+ *(to++)='\r';
+ break;
+ case 't':
+ *(to++)='\t';
+ break;
+ case 'x':
+ *(to++)=grub_strtoul(from,&from,16);
+ break;
+ default:
+ if(*(from-1)>='0' && *(from-1)<='7')
+ {
+
*(to++)=grub_strtoul(from-1,&from,16);
+ break;
+ }
+ *(to++)=*(from-1);
+ }
+ }
+ *(to++)=*(from++);
+ }
+ *to=0;
+}
+
+char*
+script_get_singlestring(char**exp)
+{
+ char*rtval=grub_malloc(STR_BUFFER);
+ int j;
+ for(j=0;**exp!='\'' && **exp;(*exp)++)
+ {
+ if((j+1)%STR_BUFFER==0)
+ rtval=grub_realloc(rtval,j+1+STR_BUFFER);
+ if(**exp=='\\')
+ {
+ switch(*((*exp)++)){
+ case '\n':
+ break;
+ case '\'':
+ case '\\':
+ rtval[j++]=**exp;
+ break;
+ default:
+ rtval[j++]='\\';
+ rtval[j++]=**exp;
+ }
+ }
+ else
+ rtval[j++]=**exp;
+ }
+ rtval[j]=0;
+ (*exp)++;
+ return rtval;
+}
+
+char*
+script_get_doublestring(char**exp)
+{
+ char*rtval=grub_malloc(STR_BUFFER);
+ int j;char *end;
+ for(j=0;**exp!='"' && **exp!=0;(*exp)++,j++){
+ if((j+1)%STR_BUFFER==0)
+ rtval=grub_realloc(rtval,j+1+STR_BUFFER);
+ if(**exp=='\\'){
+ switch(*(*exp+1)){
+ case '\n':
+ j--;
+ break;
+ case 'n':
+ rtval[j]='\n';
+ break;
+ case 'r':
+ rtval[j]='\r';
+ break;
+ case 'x':
+ rtval[j]=grub_strtoul(*exp+2,&end,16);
+ *exp=end-2;
+ break;
+ case 't':
+ rtval[j]='\t';
+ break;
+ case '\'':
+ case '\\':
+ case '"':
+ case '$':
+ rtval[j]=*(*exp+1);
+ break;
+ default:
+ if(*(*exp+1)>='0' && *(*exp+1)<='7'){
+
rtval[j]=grub_strtoul(*exp+1,&end,8);
+ *exp=end-2;
+ }else{
+ rtval[j]='\\';
+ (*exp)--;
+ }
+ }
+ (*exp)++;
+ }
+ else
+ rtval[j]=**exp;
+ }
+ rtval[j]=0;
+ (*exp)++;
+ return rtval;
+}
+
+char*
+script_get_array(char*exp)
+{
+ char*rtval=grub_malloc(3);
+ rtval[0]=0;
+ int ptr=0;
+ char*expcur=exp;
+ int maxindx=-1;
+ void arr_putc(char c)
+ {
+ if((ptr+2)%STR_BUFFER==0)
+ rtval=grub_realloc(rtval,(ptr+2)+STR_BUFFER);
+ rtval[ptr++]=c;
+ }
+ while(*expcur && *expcur!=')')
+ {
+ char*indx;
+ if(grub_isspace(*expcur))
+ {
+ expcur++;
+ continue;
+ }
+ if(*expcur=='[')
+ {
+
char*expend=expcur+1+script_find_pas('[',']',expcur+1);
+ char c=*expend;
+ char*end;
+ enum vartype vtp;
+ *expend=0;
+ char*tm=script_eval_arith(expcur+1,&vtp);
+ indx=script_get_str(tm,vtp);
+ char *t=indx;
+ int z=-1;
+ while(*t && grub_isdigit(*t))t++;
+ if(!*t)
+ z=grub_strtoul(indx,&end,0);
+ if(z>maxindx)
+ maxindx=z;
+ *expend=c;
+ expcur=expend+1;
+ while(grub_isspace(*expcur))expcur++;
+ expcur++;
+ }
+ else
+ indx=script_ltostr(++maxindx);
+ while(grub_isspace(*expcur))
+ expcur++;
+ {
+ char *expbeg=expcur;
+ int brack=0;
+ while((!grub_isspace(*expcur)&&*expcur!=')') ||
brack!=0)
+ {
+ if(*expcur=='\\')
+ {
+ expcur+=2;
+ continue;
+ }
+ if(*expcur=='(' || *expcur=='[' ||
*expcur=='{')
+ brack++;
+ if(*expcur==')' || *expcur==']' ||
*expcur=='}')
+ brack--;
+ if(*expcur=='"' || *expcur=='\'')
+ expcur+=script_get_strend(expcur);
+ expcur++;
+ }
+ char*expcpy=grub_malloc(expcur-expbeg+1);
+ grub_memcpy(expcpy,expbeg,expcur-expbeg);
+ expcpy[expcur-expbeg]=0;
+ script_unescape(expcpy);
+ script_add_arrayelem(&rtval,indx,expcpy);
+ }
+ }
+ return rtval;
+}
+
+char*
+script_eval_arith(char*exp,enum vartype*vtp)
+{
+ char*cur=0;
+ char*expcur=exp;
+ *vtp=SCRIPT_STR;
+ while(*expcur){
+ if(!*expcur)
+ return cur;
+ if(grub_isspace(*expcur))
+ {
+ expcur++;
+ continue;
+ }
+ int op=script_find_oper(expcur,!cur);
+ if(op!=-1){
+ int newop=0,unary;char*tern1=expcur;
+ char*expbeg;
+ expcur+=grub_strlen(script_opers[op].seq);
+ expbeg=expcur;
+ switch(script_opers[op].type&SCRIPT_ARGPART){
+ case SCRIPT_BRACK:
+
expcur+=script_find_pas(script_opers[op].seq[0],(script_opers[op].seq[0]=='['?']':'}'),expcur);
+ break;
+ case SCRIPT_RIGHT:
+ break;
+ case SCRIPT_TERN:
+ for(;*expcur;expcur++){
+ if(*expcur==':')
+ break;
+
if(grub_isalpha(*expcur)||grub_isdigit(*expcur)||*expcur=='_')
+ unary=0;
+ if(*expcur=='(')
+
expcur+=script_find_pas('(',')',expcur),unary=0;
+ if(*expcur=='{')
+
expcur+=script_find_pas('{','}',expcur),unary=0;
+ if(*expcur=='[')
+
expcur+=script_find_pas('[',']',expcur),unary=0;
+ if(*expcur=='"' || *expcur=='\''){
+
expcur+=script_get_strend(expcur),unary=0;
+ continue;
+ }
+ }
+ tern1=expcur;
+ expcur++;
+ case SCRIPT_LEFT:
+ case SCRIPT_BIN:
+ case SCRIPT_AND:
+ case SCRIPT_OR:
+ unary=1;
+ for(;*expcur;expcur++){
+
newop=script_find_oper(expcur,unary);
+ if(newop!=-1 &&!unary)
+ unary=1;
+ if(newop!=-1 &&
(script_opers[newop].priority<script_opers[op].priority ||
+
(script_opers[newop].priority==script_opers[op].priority &&
!(script_opers[op].type&SCRIPT_RASSOC)) ) )
+ break;
+
if(grub_isalpha(*expcur)||grub_isdigit(*expcur)||*expcur=='_')
+ unary=0;
+ if(*expcur=='('){
+
expcur+=script_find_pas('(',')',expcur),unary=0;
+ continue;
+ }
+ if(*expcur=='{'){
+
expcur+=script_find_pas('{','}',expcur),unary=0;
+ continue;
+ }
+ if(*expcur=='['){
+
expcur+=script_find_pas('[',']',expcur),unary=0;
+ continue;
+ }
+ if(*expcur=='"' || *expcur=='\''){
+
expcur+=script_get_strend(expcur),unary=0;
+ continue;
+ }
+ }
+ }
+ char c=*expcur;
+ *expcur=0;
+ switch(script_opers[op].type&SCRIPT_ARGPART){
+ case SCRIPT_TERN:
+ {
+ char c2;
+ int
ncur=script_get_bool(script_get_str(cur,*vtp));
+ if(ncur){
+ c2=*tern1;
+ *tern1=0;
+
cur=script_eval_arith(expbeg,vtp);
+ *tern1=c2;
+ }else
+
cur=script_eval_arith(tern1+1,vtp);
+ }
+ break;
+ case SCRIPT_OR:
+ case SCRIPT_AND:
+ {
+ int
ncur=script_get_bool(script_get_str(cur,*vtp));
+
if(ncur==((script_opers[op].type&SCRIPT_ARGPART)==SCRIPT_AND)){
+
cur=script_eval_arith(expbeg,vtp);
+
ncur=script_get_bool(script_get_str(cur,*vtp));
+ }
+ cur=script_ltostr(ncur);
+ *vtp=SCRIPT_STR;
+ }
+ break;
+ case SCRIPT_RIGHT:
+ {
+
if((script_opers[op].type&SCRIPT_NEEDLVALUEA) && *vtp==SCRIPT_STR){
+
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: Lvalue needed for
%s",script_opers[op].seq);
+ return 0;
+ }
+
cur=script_opers[op].func_do((script_opers[op].type&SCRIPT_NEEDLVALUEA)?cur:script_get_str(cur,*vtp),0,op);
+ }
+
*vtp=(script_opers[op].type&SCRIPT_LVALUE)?SCRIPT_VAR_NAME:SCRIPT_STR;
+ break;
+ default:
+ {
+ enum vartype rtype;
+
char*right=script_eval_arith(expbeg,&rtype);
+ if(!right){
+
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected end of expression at
line %d",*expcur);
+ return 0;
+ }
+
if((script_opers[op].type&SCRIPT_ARGPART)==SCRIPT_LEFT){
+
if((script_opers[op].type&SCRIPT_NEEDLVALUEA) && rtype==SCRIPT_STR){
+
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: Lvalue needed for
%s",script_opers[op].seq);
+ return 0;
+ }
+
cur=script_opers[op].func_do((script_opers[op].type&SCRIPT_NEEDLVALUEA)?right:script_get_str(right,rtype),0,op);
+ }
+ else
+ {
+
if((script_opers[op].type&SCRIPT_NEEDLVALUEA) && *vtp==SCRIPT_STR){
+
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: Lvalue needed for
%s",script_opers[op].seq);
+ return 0;
+ }
+
cur=script_opers[op].func_do(
+
(script_opers[op].type&SCRIPT_NEEDLVALUEA)?cur:script_get_str(cur,*vtp),script_get_str(right,rtype),op);
+ }
+ }
+
*vtp=(script_opers[op].type&SCRIPT_LVALUE)?SCRIPT_VAR_NAME:SCRIPT_STR;
+ break;
+ }
+ *expcur=c;
+
if((script_opers[op].type&SCRIPT_ARGPART)==SCRIPT_BRACK)
+ expcur++;
+ continue;
+ }
+ if(grub_isalpha(*expcur))
+ {
+ char*nmbeg=expcur;
+ char t;
+ while(grub_isalpha(*expcur) ||
grub_isdigit(*expcur) || *expcur=='_')
+ expcur++;
+ t=*expcur;
+ *expcur=0;
+ *vtp=SCRIPT_VAR_NAME;
+ cur=grub_malloc(expcur-nmbeg+1);
+ grub_memcpy(cur,nmbeg,expcur-nmbeg+1);
+ *expcur=t;
+ continue;
+ }
+ if(*expcur=='(')
+ {
+ expcur++;
+ char*expbeg=expcur;
+ char c;
+ expcur+=script_find_pas('(',')',expbeg);
+ c=*expcur;
+ *expcur=0;
+ cur=script_eval_arith(expbeg,vtp);
+ *expcur=c;
+ if(*expcur)
+ expcur++;
+ continue;
+ }
+ if(*expcur=='[')
+ {
+ expcur++;
+ char*expbeg=expcur;
+ char c;
+ char *indx;
+ enum vartype rttype;
+ expcur+=script_find_pas('[',']',expbeg);
+ c=*expcur;
+ *expcur=0;
+ char*tm=script_eval_arith(expbeg,&rttype);
+
indx=script_escape_string(script_get_str(tm,rttype));
+ *expcur=c;
+ if(*expcur)
+ expcur++;
+ if(*vtp==SCRIPT_VAR_NAME)
+ {
+ int
curlen=grub_strlen(cur),indxlen=grub_strlen(indx);
+ cur=grub_realloc(cur,curlen+indxlen+5);
+ cur[curlen]='[';
+ cur[curlen+1]='\'';
+ grub_memcpy(cur+curlen+2,indx,indxlen);
+ cur[curlen+2+indxlen]='\'';
+ cur[curlen+3+indxlen]=']';
+ cur[curlen+4+indxlen]=0;
+ }
+ continue;
+ }
+ if(grub_isdigit(*expcur))
+ {
+ cur=script_getnum(&expcur);
+ continue;
+ }
+ if(*expcur=='"')
+ {
+ expcur++;
+ cur=script_get_doublestring(&expcur);
+ *vtp=SCRIPT_STR;
+ continue;
+ }
+ if(*expcur=='\'')
+ {
+ expcur++;
+ cur=script_get_singlestring(&expcur);
+ *vtp=SCRIPT_STR;
+ continue;
+ }
+ }
+ return cur;
+}
+
+
+char*
+script_expand (char*cmdline,grub_err_t (* getline) (char
**),char**end,int flags)
+{
+ char *rd = (char *) cmdline;
+ char unputbuf;
+ int unput = 0;
+ char*rtval=grub_malloc(EXPAND_BUF_SIZE);
+ char *wto=rtval;
+ int wor=0,wand=0;
+ enum stat {STAT_NORM,STAT_QUOTE,STAT_DQUOTE,STAT_BQUOTE};
+ enum stat status=STAT_NORM;
+
+ grub_err_t dummygetline(char**s)
+ {
+ **s=0;
+ return 0;
+ }
+
+ /* Get one character from the commandline. If the caller reads
+ beyond the end of the string a new line will be read. This
+ function will not chech for errors, the caller has to check for
+ grub_errno. */
+ char getchar (void)
+ {
+ int c;
+ if (unput)
+ {
+ unput = 0;
+ return unputbuf;
+ }
+
+ if (! rd)
+ {
+ if(getline)
+ getline (&rd);
+ else
+ return 0;
+ /* Error is ignored here, the caller will check for this
+ when it reads beyond the EOL. */
+ c = *(rd)++;
+ return c;
+ }
+
+ c = *(rd)++;
+ if (! c)
+ {
+ rd = 0;
+ return '\n';
+ }
+
+ return c;
+ }
+
+ void unputc (char c)
+ {
+ unputbuf = c;
+ unput = 1;
+ }
+ void putchar(char c)
+ {
+ if((wto-rtval+1)%EXPAND_BUF_SIZE==0)
+ {
+ int delta=wto-rtval;
+ grub_realloc(rtval,wto-rtval+1+EXPAND_BUF_SIZE);
+ wto=rtval+delta;
+ }
+ *(wto++)=c;
+ }
+ void puts(char*str){
+ for(;*str;str++)
+ putchar(*str);
+ }
+ while(1)
+ {
+ char c;
+ c=getchar();
+ if((c==';' || c=='\n' || c=='#'
||(c=='|'&&wor)||(c=='&'&&wand)) && status==STAT_NORM)
+ break;
+ if(wor)
+ {
+ putchar('|');
+ wor=0;
+ }
+ if(wand)
+ {
+ putchar('&');
+ wand=0;
+ }
+ if(c=='|')
+ {
+ wor=1;
+ continue;
+ }
+ if(c=='&')
+ {
+ wand=1;
+ continue;
+ }
+ if(c=='"'&&(status=STAT_NORM ||status==STAT_DQUOTE))
+ {
+ putchar(c);
+ status=STAT_DQUOTE-status;
+ continue;
+ }
+ if(c=='\''&&(status=STAT_NORM ||status==STAT_QUOTE))
+ {
+ putchar(c);
+ status=STAT_QUOTE-status;
+ continue;
+ }
+ if(c=='\\')
+ {
+ putchar(c);
+ putchar(getchar());
+ continue;
+ }
+ if(c=='$' && status!=STAT_QUOTE && (flags&EXPAND_DOLLAR))
+ {
+ char exp[1024];
+ char *p=exp;
+ c = getchar ();
+ if(c=='(')
+ {
+ enum vartype vtp;
+ //TODO: command expansion
+ if((c=getchar())=='(')
+ {
+ int brack=2;
+ for(;brack;)
+ {
+ char c=0;
+ int esc=0;
+ *(p++)=getchar();
+ if(*(p-1)=='(')
+ brack++;
+ if(*(p-1)==')')
+ brack--;
+ if(*(p-1)=='"')
+
for(c=*(p++)=getchar();esc || c!='"';esc=(c=='\\'
&&!esc),c=*(p++)=getchar());
+ if(*(p-1)=='\'')
+
for(c=*(p++)=getchar();esc || c!='\'';esc=(c=='\\'
&&!esc),c=*(p++)=getchar());
+ }
+ }
+ *(p-2)=0;
+
char*tm=script_eval_arith(script_expand(exp,0,0,EXPAND_DOLLAR),&vtp);
+ puts(script_get_str(tm,vtp));
+ *(p-2)=')';
+ }
+ else
+ {
+ if (c == '{')
+ while ((c = getchar ()) != '}')
+ *(p++) = c;
+ else
+ {
+ /* XXX: An env. variable can
have characters and digits in
+ its name, are more characters
allowed here? */
+ while (c && (grub_isalpha (c)
|| grub_isdigit (c)))
+ {
+ *(p++) = c;
+ c = getchar ();
+ }
+ unputc (c);
+ }
+ *p = '\0';
+ puts(script_env_get (exp));
+ }
+ continue;
+ }
+ putchar(c);
+ }
+ putchar(0);
+ if(end)
+ *end=rd?rd-1:0;
+ return rtval;
+}
+void
+script_parse_list(grub_menu_entry_t
fnptr,char**cmd,grub_err_t(*getline)(char**),int no1stskip)
+{
+ grub_command_list_t listptr=0;char*lastcmd=*cmd,*bfrcmd=*cmd;
+ /* Get one character from the commandline. If the caller reads
+ beyond the end of the string a new line will be read. This
+ function will not chech for errors, the caller has to check for
+ grub_errno. */
+ char getchar (void)
+ {
+ int c;
+
+ if (! *cmd)
+ {
+ if(getline)
+ {
+ if(listptr)
+ listptr->next=grub_malloc(sizeof(*listptr));
+ getline (cmd);
+ lastcmd=*cmd;
+ if(listptr)
+ {
+ listptr=listptr->next;
+ listptr->next=0;
+ listptr->command=grub_malloc(grub_strlen(*cmd)+2);
+
grub_memcpy(listptr->command,*cmd,grub_strlen(*cmd)+1);
+ }
+ }
+ else
+ return 0;
+ fnptr->num++;
+
+ /* Error is ignored here, the caller will check for this
+ when it reads beyond the EOL. */
+ c = *(*cmd)++;
+ return c;
+ }
+
+ c = *(*cmd)++;
+ if (! c)
+ {
+ bfrcmd=*cmd;
+ *cmd = 0;
+ return '\n';
+ }
+
+ return c;
+ }
+ void skip_oper()
+ {
+ int esc=0;char c;
+ while(1)
+ {
+ c=getchar();
+ if((c=='\n'||c==';') && !esc)
+ break;
+ if(c=='"' && !esc)
+ {
+ while((c=getchar())&& (c!='"' ||esc))
+ esc=(c=='\\')&&!esc;
+ continue;
+ }
+ if(c=='\'' && !esc)
+ {
+ while((c=getchar())&& (c!='\'' ||esc))
+ esc=(c=='\\')&&!esc;
+ continue;
+ }
+ }
+ }
+ char c;int brack=1;int lmin=0;
+ if(!no1stskip)
+ {
+ while(grub_isspace((c=getchar())));
+ switch(c)
+ {
+ case '{':
+ break;
+ case 'd':
+ if(getchar()!='o')
+ break;
+ if(!script_islexend(getchar()))
+ break;
+ break;
+ default:
+ grub_error(GRUB_ERR_BAD_ARGUMENT,"unexpected %c
'{' expected",c);
+ return;
+ }
+ }
+ listptr=grub_malloc(sizeof(*listptr));
+ listptr->command=grub_malloc(grub_strlen(*cmd)+2);
+ listptr->next=0;
+ fnptr->command_list=listptr;
+ grub_memcpy(listptr->command,*cmd,grub_strlen(*cmd)+1);
+ while(brack)
+ {
+ lmin=0;
+ while(grub_isspace(c=getchar()));
+ if(c=='}')
+ {
+ brack--;
+ continue;
+ }
+ if(c=='{')
+ {
+ brack++;
+ continue;
+ }
+ if(c=='i')
+ {
+ if((c=getchar())=='f' &&
script_islexend(c=getchar()))
+ {
+ brack++;
+ continue;
+ }
+ else
+ {
+ if(c!=';' && c!='\n')
+ skip_oper();
+ continue;
+ }
+ }
+ if(c=='f')
+ {
+ if((c=getchar())=='i' &&
script_islexend(c=getchar()))
+ {
+ brack--;
+ lmin=3;
+ continue;
+ }
+ else
+ {
+ if(c!=';' && c!='\n')
+ skip_oper();
+ continue;
+ }
+ }
+ if(c=='d')
+ {
+ if((c=getchar())=='o')
+ {
+ c=getchar();
+ if(script_islexend(c))
+ {
+ brack++;
+ continue;
+ }
+ if(c=='n' && (c=getchar())=='e' &&
script_islexend(c=getchar()))
+ {
+ brack--;
+ continue;
+ }
+ if(c!=';' && c!='\n')
+ skip_oper();
+ continue;
+ }
+ else
+ {
+ if(c!=';' && c!='\n')
+ skip_oper();
+ continue;
+ }
+ }
+ if(c=='e'&& brack==1)
+ {
+ while(1)
+ {
+ if((c=getchar())!='l')
+ break;;
+ c=getchar();
+ if(c=='s')
+ {
+ if((c=getchar())!='e' ||
!script_islexend(c=getchar()))
+ break;
+ brack=0;
+ lmin=5;
+ break;
+ }
+ if(c=='i')
+ {
+ if((c=getchar())!='f' ||
!script_islexend(c=getchar()))
+ break;
+ brack=0;
+ lmin=5;
+ break;
+ }
+ }
+ if(c!='\n' && c!=';'&& brack)
+ skip_oper();
+ continue;
+ }
+ if(script_isfuncbeg(*cmd))
+ {
+ script_skipfuncbeg(cmd);
+ continue;
+ }
+ skip_oper();
+ }
+ if(*cmd)
+ {
+ (*cmd)-=lmin;
+ listptr->command[(*cmd)-lastcmd]=0;
+ }
+ if(!*cmd&& lmin)
+ *cmd=bfrcmd-lmin;
+}
+int
+script_list_execute( grub_menu_entry_t fn)
+{
+ grub_command_list_t cmdlist=fn->command_list;
+ grub_err_t getln(char**s)
+ {
+ if(cmdlist&& cmdlist->next)
+ {
+ cmdlist=cmdlist->next;
+ *s=cmdlist->command;
+ }
+ else
+ *s=0;
+ return 0;
+ }
+ int rtval=0;
+ while(cmdlist)
+ {
+ rtval=script_execute(cmdlist->command,getln,0);
+ if(cmdlist)
+ cmdlist=cmdlist->next;
+ }
+ return rtval;
+}
+void
+script_free_list(grub_menu_entry_t arg)
+{
+ grub_command_list_t lst=arg->command_list,last;
+ while(lst)
+ {
+ grub_free(lst->command);
+ last=lst;
+ lst=lst->next;
+ grub_free(last);
+ }
+ grub_free(arg);
+}
+int
+script_exec_file (char*fname,int argc, char**argv)
+{
+ grub_file_t file;char*lastalloc=0;
+ grub_err_t getln(char**s)
+ {
+ *s=grub_malloc(GRUB_MAX_CMDLINE);
+ if(lastalloc)
+ grub_free(lastalloc);
+ lastalloc=*s;
+ char c;
+ int pos = 0;
+ int literal = 0;
+ int comment = 0;
+ while (1)
+ {
+ if (grub_file_read (file, &c, 1) != 1)
+ break;
+
+ /* Skip all carriage returns. */
+ if (c == '\r')
+ continue;
+
+ /* Replace tabs with spaces. */
+ if (c == '\t')
+ c = ' ';
+
+ /* The previous is a backslash, then... */
+ if (literal)
+ {
+ /* If it is a newline, replace it with
a space and continue. */
+ if (c == '\n')
+ {
+ c = ' ';
+
+ /* Go back to overwrite the
backslash. */
+ if (pos > 0)
+ pos--;
+ }
+
+ literal = 0;
+ }
+
+ if (c == '\\')
+ literal = 1;
+
+ if (comment)
+ {
+ if (c == '\n')
+ comment = 0;
+ }
+ else if (pos == 0)
+ {
+ if (c == '#')
+ comment = 1;
+ else if (! grub_isspace (c))
+ (*s)[pos++] = c;
+ }
+ else
+ {
+ if (c == '\n')
+ break;
+
+ if (pos < GRUB_MAX_CMDLINE)
+ (*s)[pos++] = c;
+ }
+ }
+ if(pos==0)
+ {
+ grub_free(*s);
+ *s=0;
+ }
+ else
+ (*s)[pos] = '\0';
+ return 0;
+ }
+ char*ln;int ret=0;
+ file=grub_file_open(fname);
+ if(!file)
+ return grub_errno;
+ while(1)
+ {
+ getln(&ln);
+ if(!ln)
+ break;
+ ret=script_execute(ln,getln,0);
+ }
+ return ret;
+}
+int
+script_execute(char*cmdline,grub_err_t(*getline)(char**),char**rest)
+{
+ int rtval=0,semdel=0;
+ int invrtval=0;
+ char*end=cmdline;
+ int skip_spaces()
+ {
+ if(!end)
+ return 0;
+ do
+ {
+ if(!*end)
+ getline(&end);
+ if(!end)
+ return 0;
+ while(*end && grub_isspace(*end))
+ end++;
+ }while(!*end);
+ return 1;
+ }
+ if(rest)*rest=0;
+ while(1)
+ {
+ if(invrtval)
+ rtval=!rtval;
+ invrtval=0;
+ if(!end || !*end || *end=='#' || *end=='\n')
+ break;
+ if(*end=='|' && rtval)
+ break;
+ if(*end=='&' && !rtval)
+ break;
+ semdel=(*end==';');
+ if(*end==';' || *end=='|' ||*end=='&')
+ end++;
+ if(!*end &&semdel)
+ break;
+ if(!skip_spaces())return rtval;
+ if(*end=='!')
+ invrtval=1,end++;
+ if(!skip_spaces())return rtval;
+ if(*end=='{')
+ end++;
+ if(!skip_spaces())return rtval;
+ if(*end=='}')
+ end++;
+ while(*end && grub_isspace(*end))
+ end++;
+ if(!*end)
+ break;
+ if((!grub_memcmp(end,"then",4) && script_islexend(end[4]))
+ ||(!grub_memcmp(end,"else",4) &&
script_islexend(end[4]))
+ ||(!grub_memcmp(end,"elif",4) &&
script_islexend(end[4]))
+ ||(!grub_memcmp(end,"done",4) &&
script_islexend(end[4]))
+ ||(!grub_memcmp(end,"fi",2) &&
script_islexend(end[2])))
+ {
+ if(rest)
+ *rest=end;
+ break;
+ }
+ if(end[0]=='i' && end[1]=='f'&& script_islexend(end[2]))
+ {
+ int ret=0,crtval=0;
+ end+=2;
+ while(!end || !*end ||
grub_memcmp(end,"then",4)|| !script_islexend(end[4]))
+ {
+ if(!end || !*end)
+ getline(&end);
+ ret=!script_execute(end,getline,&end);
+ }
+ grub_menu_entry_t lst=grub_malloc(sizeof(*lst));
+ lst->num=0;
+ lst->title=0;
+ lst->next=0;
+ end+=4;
+ script_parse_list(lst,&end,getline,1);
+ if(ret)
+ rtval=script_list_execute(lst);
+ script_free_list(lst);
+
while((!grub_memcmp(end,"else",4)&&script_islexend(end[4]))
+
||(!grub_memcmp(end,"elif",4)&&script_islexend(end[4])))
+ {
+ lst=grub_malloc(sizeof(*lst));
+ lst->num=0;
+ lst->title=0;
+ lst->next=0;
+ lst->command_list=0;
+ end+=4;
+ if(!ret&& !grub_memcmp(end-4,"elif",4))
+ {
+ while(!end || !*end ||
grub_memcmp(end,"then",4)|| !script_islexend(end[4]))
+ {
+ if(!end || !*end)
+ getline(&end);
+
crtval=!script_execute(end,getline,&end);
+ }
+ end+=4;
+ }
+ else
+ crtval=!ret;
+ script_parse_list(lst,&end,getline,1);
+ if(crtval)
+ {
+ rtval=script_list_execute(lst);
+ ret=1;
+ }
+ script_free_list(lst);
+ }
+ end+=2;
+ continue;
+ }
+ if(end[0]=='(' && end[1]=='(')
+ {
+
char*exp=script_expand(end,getline,&end,EXPAND_DOLLAR);
+ while(grub_isspace(*exp))exp++;
+ if(*exp=='(' && *(exp+1)=='(')
+ {
+ exp+=2;
+ char*expend,c;
+ char*ret;enum vartype vtp;
+ expend=exp+script_find_pas('(',')',exp);
+ c=*expend;
+ *expend=0;
+ ret=script_eval_arith(exp,&vtp);
+ *expend=c;
+
rtval=!script_strtol(script_get_str(ret,vtp));
+ continue;
+ }
+ }
+ if (script_isfuncbeg(end))
+ {
+ grub_menu_t baseptr=&funcs;
+ grub_menu_entry_t bbptr,bptr2;
+ char*name=0;
+ while(grub_isspace(*end))end++;
+ if(!grub_memcmp(end,"entry",sizeof("entry")-1)
&& script_islexend(end[sizeof("entry")-1]))
+ end+=sizeof("entry")-1,baseptr=menu;
+ while(grub_isspace(*end))end++;
+
if(!grub_memcmp(end,"function",sizeof("function")-1) &&
script_islexend(end[sizeof("function")-1]))
+ end+=sizeof("function")-1;
+ while(grub_isspace(*end))end++;
+ switch(*end)
+ {
+ case '"':
+ end++;
+ name=script_get_doublestring(&end);
+ break;
+ case '\'':
+ end++;
+ name=script_get_singlestring(&end);
+ break;
+ default:
+ name=grub_malloc(64);//Must be enough
+ char*ptr=name;
+ while(!script_islexend(*end))
+ *(ptr++)=*(end++);
+ *ptr=0;
+ }
+ while(grub_isspace(*end))end++;
+ if(*end=='(')end++;//skip (
+ while(grub_isspace(*end))end++;
+ if(*end==')')end++;//skip )
+ while(grub_isspace(*end))end++;
+ baseptr->size++;
+ bbptr=bptr2=baseptr->entry_list;
+ while(bptr2)bbptr=bptr2,bptr2=bptr2->next;
+ bptr2=grub_malloc(sizeof(struct grub_menu_entry));
+ if(bbptr)
+ bbptr->next=bptr2;
+ else
+ baseptr->entry_list=bptr2;
+ bptr2->title=name;
+ bptr2->num=0;
+ bptr2->next=0;
+ script_parse_list(bptr2,&end,getline,0);
+ continue;
+ }
+ char*exp=script_expand(end,getline,&end,EXPAND_ALL);
+ while(grub_isspace(*exp))exp++;
+ char*expcur=exp;
+ {
+ grub_menu_entry_t cur=funcs.entry_list;
+ if(funcs.entry_list)
+ {
+ while(cur)
+ {
+
if(!grub_memcmp(cur->title,expcur,grub_strlen(cur->title))&&script_islexend(expcur[grub_strlen(cur->title)]))
+ break;
+ cur=cur->next;
+ }
+ if(cur)
+ {
+ expcur+=grub_strlen(cur->title);
+ rtval=script_list_execute(cur);
+ continue;
+ }
+ }
+ }
+ /* In case of an assignment set the environment
accordingly instead
+ of calling a function. */
+ while(*expcur && !grub_isspace(*expcur) &&
*expcur!='=')expcur++;
+ if (*expcur=='=')
+ {
+ expcur[0] = 0;
+ char*ptr2=expcur+1;
+ char*endptr=exp+grub_strlen(exp)-1;
+ int array=0;
+ while(*ptr2 &&grub_isspace(*ptr2))ptr2++;
+ while(grub_isspace(*endptr))
+ endptr--;
+ *(endptr+1)=0;
+ if(ptr2[0]=='(')
+ ptr2++,array=1;
+ script_env_set (exp,
array?script_get_array(ptr2):ptr2);
+ expcur[0] = '=';
+ rtval=0;
+ continue;
+ }
+ rtval=grub_exec_norm(exp);
+ }
+ return rtval;
+}
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bash pre-alpha
2005-01-29 13:18 ` Bash pre-alpha Serbinenko Vladimir
@ 2005-01-29 14:08 ` Serbinenko Vladimir
2005-01-29 16:04 ` Marco Gerards
0 siblings, 1 reply; 10+ messages in thread
From: Serbinenko Vladimir @ 2005-01-29 14:08 UTC (permalink / raw)
To: The development of GRUB 2
I'm sorry but I had some diff issues I confused run_menu and
run_menu_entry. Here is a patch to correct this error and update i386.mk
----------------------------------------------------------
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x output.0 -x kernel_syms.lst
-x symlist.c -x requests -x traces.0 --expand-tabs
./grub2pr/conf/i386-pc.mk ./grub2/conf/i386-pc.mk
--- ./grub2pr/conf/i386-pc.mk 2005-01-29 14:55:54.000000000 +0100
+++ ./grub2/conf/i386-pc.mk 2005-01-29 14:56:31.000000000 +0100
@@ -504,12 +504,12 @@
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
-CLEANFILES += grub-emu grub_emu-kern_main.o grub_emu-kern_device.o
grub_emu-fs_fshelp.o grub_emu-kern_disk.o grub_emu-kern_dl.o
grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-kern_err.o
grub_emu-kern_misc.o grub_emu-kern_loader.o grub_emu-kern_rescue.o
grub_emu-kern_term.o grub_emu-kern_partition.o grub_emu-kern_env.o
grub_emu-commands_ls.o grub_emu-partmap_amiga.o grub_emu-partmap_pc.o
grub_emu-partmap_apple.o grub_emu-commands_terminal.o
grub_emu-commands_boot.o grub_emu-commands_cmp.o grub_emu-commands_cat.o
grub_emu-util_i386_pc_biosdisk.o grub_emu-fs_fat.o grub_emu-fs_ext2.o
grub_emu-fs_ufs.o grub_emu-fs_minix.o grub_emu-fs_hfs.o
grub_emu-fs_jfs.o grub_emu-fs_iso9660.o grub_emu-normal_cmdline.o
grub_emu-normal_command.o grub_emu-normal_main.o grub_emu-normal_menu.o
grub_emu-normal_arg.o grub_emu-util_console.o grub_emu-util_grub_emu.o
grub_emu-util_misc.o grub_emu-util_i386_pc_getroot.o
grub_emu-disk_loopback.o
-MOSTLYCLEANFILES += grub_emu-kern_main.d grub_emu-kern_device.d
grub_emu-fs_fshelp.d grub_emu-kern_disk.d grub_emu-kern_dl.d
grub_emu-kern_file.d grub_emu-kern_fs.d grub_emu-kern_err.d
grub_emu-kern_misc.d grub_emu-kern_loader.d grub_emu-kern_rescue.d
grub_emu-kern_term.d grub_emu-kern_partition.d grub_emu-kern_env.d
grub_emu-commands_ls.d grub_emu-partmap_amiga.d grub_emu-partmap_pc.d
grub_emu-partmap_apple.d grub_emu-commands_terminal.d
grub_emu-commands_boot.d grub_emu-commands_cmp.d grub_emu-commands_cat.d
grub_emu-util_i386_pc_biosdisk.d grub_emu-fs_fat.d grub_emu-fs_ext2.d
grub_emu-fs_ufs.d grub_emu-fs_minix.d grub_emu-fs_hfs.d
grub_emu-fs_jfs.d grub_emu-fs_iso9660.d grub_emu-normal_cmdline.d
grub_emu-normal_command.d grub_emu-normal_main.d grub_emu-normal_menu.d
grub_emu-normal_arg.d grub_emu-util_console.d grub_emu-util_grub_emu.d
grub_emu-util_misc.d grub_emu-util_i386_pc_getroot.d
grub_emu-disk_loopback.d
+CLEANFILES += grub-emu grub_emu-kern_main.o grub_emu-kern_device.o
grub_emu-fs_fshelp.o grub_emu-kern_disk.o grub_emu-kern_dl.o
grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-kern_err.o
grub_emu-kern_misc.o grub_emu-kern_loader.o grub_emu-kern_rescue.o
grub_emu-kern_term.o grub_emu-kern_partition.o grub_emu-kern_env.o
grub_emu-commands_ls.o grub_emu-partmap_amiga.o grub_emu-partmap_pc.o
grub_emu-partmap_apple.o grub_emu-commands_terminal.o
grub_emu-commands_boot.o grub_emu-commands_cmp.o grub_emu-commands_cat.o
grub_emu-util_i386_pc_biosdisk.o grub_emu-fs_fat.o grub_emu-fs_ext2.o
grub_emu-fs_ufs.o grub_emu-fs_minix.o grub_emu-fs_hfs.o
grub_emu-fs_jfs.o grub_emu-fs_iso9660.o grub_emu-normal_cmdline.o
grub_emu-normal_command.o grub_emu-normal_script.o
grub_emu-normal_main.o grub_emu-normal_menu.o grub_emu-normal_arg.o
grub_emu-util_console.o grub_emu-util_grub_emu.o grub_emu-util_misc.o
grub_emu-util_i386_pc_getroot.o grub_emu-disk_loopback.o
+MOSTLYCLEANFILES += grub_emu-kern_main.d grub_emu-kern_device.d
grub_emu-fs_fshelp.d grub_emu-kern_disk.d grub_emu-kern_dl.d
grub_emu-kern_file.d grub_emu-kern_fs.d grub_emu-kern_err.d
grub_emu-kern_misc.d grub_emu-kern_loader.d grub_emu-kern_rescue.d
grub_emu-kern_term.d grub_emu-kern_partition.d grub_emu-kern_env.d
grub_emu-commands_ls.d grub_emu-partmap_amiga.d grub_emu-partmap_pc.d
grub_emu-partmap_apple.d grub_emu-commands_terminal.d
grub_emu-commands_boot.d grub_emu-commands_cmp.d grub_emu-commands_cat.d
grub_emu-util_i386_pc_biosdisk.d grub_emu-fs_fat.d grub_emu-fs_ext2.d
grub_emu-fs_ufs.d grub_emu-fs_minix.d grub_emu-fs_hfs.d
grub_emu-fs_jfs.d grub_emu-fs_iso9660.d grub_emu-normal_cmdline.d
grub_emu-normal_command.d grub_emu-normal_script.d
grub_emu-normal_main.d grub_emu-normal_menu.d grub_emu-normal_arg.d
grub_emu-util_console.d grub_emu-util_grub_emu.d grub_emu-util_misc.d
grub_emu-util_i386_pc_getroot.d grub_emu-disk_loopback.d
-grub-emu: grub_emu-kern_main.o grub_emu-kern_device.o
grub_emu-fs_fshelp.o grub_emu-kern_disk.o grub_emu-kern_dl.o
grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-kern_err.o
grub_emu-kern_misc.o grub_emu-kern_loader.o grub_emu-kern_rescue.o
grub_emu-kern_term.o grub_emu-kern_partition.o grub_emu-kern_env.o
grub_emu-commands_ls.o grub_emu-partmap_amiga.o grub_emu-partmap_pc.o
grub_emu-partmap_apple.o grub_emu-commands_terminal.o
grub_emu-commands_boot.o grub_emu-commands_cmp.o grub_emu-commands_cat.o
grub_emu-util_i386_pc_biosdisk.o grub_emu-fs_fat.o grub_emu-fs_ext2.o
grub_emu-fs_ufs.o grub_emu-fs_minix.o grub_emu-fs_hfs.o
grub_emu-fs_jfs.o grub_emu-fs_iso9660.o grub_emu-normal_cmdline.o
grub_emu-normal_command.o grub_emu-normal_main.o grub_emu-normal_menu.o
grub_emu-normal_arg.o grub_emu-util_console.o grub_emu-util_grub_emu.o
grub_emu-util_misc.o grub_emu-util_i386_pc_getroot.o
grub_emu-disk_loopback.o
+grub-emu: grub_emu-kern_main.o grub_emu-kern_device.o
grub_emu-fs_fshelp.o grub_emu-kern_disk.o grub_emu-kern_dl.o
grub_emu-kern_file.o grub_emu-kern_fs.o grub_emu-kern_err.o
grub_emu-kern_misc.o grub_emu-kern_loader.o grub_emu-kern_rescue.o
grub_emu-kern_term.o grub_emu-kern_partition.o grub_emu-kern_env.o
grub_emu-commands_ls.o grub_emu-partmap_amiga.o grub_emu-partmap_pc.o
grub_emu-partmap_apple.o grub_emu-commands_terminal.o
grub_emu-commands_boot.o grub_emu-commands_cmp.o grub_emu-commands_cat.o
grub_emu-util_i386_pc_biosdisk.o grub_emu-fs_fat.o grub_emu-fs_ext2.o
grub_emu-fs_ufs.o grub_emu-fs_minix.o grub_emu-fs_hfs.o
grub_emu-fs_jfs.o grub_emu-fs_iso9660.o grub_emu-normal_cmdline.o
grub_emu-normal_command.o grub_emu-normal_script.o
grub_emu-normal_main.o grub_emu-normal_menu.o grub_emu-normal_arg.o
grub_emu-util_console.o grub_emu-util_grub_emu.o grub_emu-util_misc.o
grub_emu-util_i386_pc_getroot.o grub_emu-disk_loopback.o
$(BUILD_CC) -o $@ $^ $(BUILD_LDFLAGS) $(grub_emu_LDFLAGS)
grub_emu-kern_main.o: kern/main.c
@@ -768,6 +768,14 @@
-include grub_emu-normal_command.d
+grub_emu-normal_script.o: normal/script.c
+ $(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS)
$(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $<
+
+grub_emu-normal_script.d: normal/script.c
+ set -e; $(BUILD_CC) -Inormal -I$(srcdir)/normal
$(BUILD_CPPFLAGS) $(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -M
$< | sed 's,script\.o[ :]*,grub_emu-normal_script.o $@ : ,g' >
$@; [ -s $@ ] || rm -f $@
+
+-include grub_emu-normal_script.d
+
grub_emu-normal_main.o: normal/main.c
$(BUILD_CC) -Inormal -I$(srcdir)/normal $(BUILD_CPPFLAGS)
$(BUILD_CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -c -o $@ $<
@@ -1291,10 +1299,10 @@
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
-CLEANFILES += normal.mod mod-normal.o mod-normal.c pre-normal.o
normal_mod-normal_cmdline.o normal_mod-normal_command.o
normal_mod-normal_main.o normal_mod-normal_menu.o
normal_mod-normal_arg.o normal_mod-normal_i386_setjmp.o def-normal.lst
und-normal.lst
-MOSTLYCLEANFILES += normal_mod-normal_cmdline.d
normal_mod-normal_command.d normal_mod-normal_main.d
normal_mod-normal_menu.d normal_mod-normal_arg.d
normal_mod-normal_i386_setjmp.d
+CLEANFILES += normal.mod mod-normal.o mod-normal.c pre-normal.o
normal_mod-normal_cmdline.o normal_mod-normal_command.o
normal_mod-normal_script.o normal_mod-normal_main.o
normal_mod-normal_menu.o normal_mod-normal_arg.o
normal_mod-normal_i386_setjmp.o def-normal.lst und-normal.lst
+MOSTLYCLEANFILES += normal_mod-normal_cmdline.d
normal_mod-normal_command.d normal_mod-normal_script.d
normal_mod-normal_main.d normal_mod-normal_menu.d
normal_mod-normal_arg.d normal_mod-normal_i386_setjmp.d
DEFSYMFILES += def-normal.lst
UNDSYMFILES += und-normal.lst
@@ -1303,7 +1311,7 @@
$(LD) -r -d -o $@ $^
$(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R
.note -R .comment $@
-pre-normal.o: normal_mod-normal_cmdline.o normal_mod-normal_command.o
normal_mod-normal_main.o normal_mod-normal_menu.o
normal_mod-normal_arg.o normal_mod-normal_i386_setjmp.o
+pre-normal.o: normal_mod-normal_cmdline.o normal_mod-normal_command.o
normal_mod-normal_script.o normal_mod-normal_main.o
normal_mod-normal_menu.o normal_mod-normal_arg.o
normal_mod-normal_i386_setjmp.o
-rm -f $@
$(LD) -r -d -o $@ $^
@@ -1336,6 +1344,14 @@
-include normal_mod-normal_command.d
+normal_mod-normal_script.o: normal/script.c
+ $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS)
$(normal_mod_CFLAGS) -c -o $@ $<
+
+normal_mod-normal_script.d: normal/script.c
+ set -e; $(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS)
$(CFLAGS) $(normal_mod_CFLAGS) -M $< | sed 's,script\.o[
:]*,normal_mod-normal_script.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@
+
+-include normal_mod-normal_script.d
+
normal_mod-normal_main.o: normal/main.c
$(CC) -Inormal -I$(srcdir)/normal $(CPPFLAGS) $(CFLAGS)
$(normal_mod_CFLAGS) -c -o $@ $<
diff -b -B -r -u -E -N -x '*~' -x '*.d' -x output.0 -x kernel_syms.lst
-x symlist.c -x requests -x traces.0 --expand-tabs
./grub2pr/normal/menu.c ./grub2/normal/menu.c
--- ./grub2pr/normal/menu.c 2005-01-29 14:55:55.000000000 +0100
+++ ./grub2/normal/menu.c 2005-01-29 15:00:11.000000000 +0100
@@ -239,42 +239,148 @@
static int
run_menu (grub_menu_t menu, int nested)
{
- return script_list_execute(entry);
-}
+ int first, offset;
+ unsigned long saved_time;
-/* Run a menu entry. */
-static void
-run_menu_entry (grub_menu_entry_t entry)
-{
- grub_command_list_t cl;
+ first = 0;
+ offset = menu->default_entry;
+ if (offset > TERM_NUM_ENTRIES - 1)
+ {
+ first = offset - (TERM_NUM_ENTRIES - 1);
+ offset = TERM_NUM_ENTRIES - 1;
+ }
+
+ /* Initialize the time. */
+ saved_time = grub_get_rtc ();
+
+ refresh:
+ grub_setcursor (0);
+ init_page (nested, 0);
+ print_entries (menu, first, offset);
+ grub_refresh ();
+
+ while (1)
+ {
+ int c;
+
+ if (menu->timeout > 0)
+ {
+ unsigned long current_time;
- for (cl = entry->command_list; cl != 0; cl = cl->next)
+ current_time = grub_get_rtc ();
+ if (current_time - saved_time >= GRUB_TICKS_PER_SECOND)
{
- grub_command_t c;
+ menu->timeout--;
+ saved_time = current_time;
+ }
+
+ grub_gotoxy (0, TERM_HEIGHT - 3);
+ /* NOTE: Do not remove the trailing space characters.
+ They are required to clear the line. */
+ grub_printf ("\
+ The highlighted entry will be booted automatically in %d seconds. ",
+ menu->timeout);
+ grub_gotoxy (TERM_CURSOR_X, TERM_FIRST_ENTRY_Y + offset);
+ grub_refresh ();
+ }
- if (cl->command[0] == '\0')
- /* Ignore an empty command line. */
- continue;
+ if (menu->timeout == 0)
+ return menu->default_entry;
- c = grub_command_find (cl->command);
- if (! c)
+ if (grub_checkkey () >= 0 || menu->timeout < 0)
+ {
+ c = GRUB_TERM_ASCII_CHAR (grub_getkey ());
+
+ if (menu->timeout >= 0)
+ {
+ grub_gotoxy (0, TERM_HEIGHT - 3);
+ grub_printf ("\
+ ");
+ menu->timeout = -1;
+ menu->fallback_entry = -1;
+ grub_gotoxy (TERM_CURSOR_X, TERM_FIRST_ENTRY_Y + offset);
+ }
+
+ switch (c)
+ {
+ case 16:
+ case '^':
+ if (offset > 0)
+ {
+ print_entry (TERM_FIRST_ENTRY_Y + offset, 0,
+ get_entry (menu, first + offset));
+ offset--;
+ print_entry (TERM_FIRST_ENTRY_Y + offset, 1,
+ get_entry (menu, first + offset));
+ }
+ else if (first > 0)
+ {
+ first--;
+ print_entries (menu, first, offset);
+ }
break;
- if (! (c->flags & GRUB_COMMAND_FLAG_CMDLINE))
+ case 14:
+ case 'v':
+ if (menu->size > first + offset + 1)
{
- grub_error (GRUB_ERR_INVALID_COMMAND,
- "invalid command `%s'",
- cl->command);
+ if (offset < TERM_NUM_ENTRIES - 1)
+ {
+ print_entry (TERM_FIRST_ENTRY_Y + offset, 0,
+ get_entry (menu, first + offset));
+ offset++;
+ print_entry (TERM_FIRST_ENTRY_Y + offset, 1,
+ get_entry (menu, first + offset));
+ }
+ else
+ {
+ first++;
+ print_entries (menu, first, offset);
+ }
+ }
break;
+
+ case '\n':
+ case '\r':
+ case 6:
+ grub_setcursor (1);
+ return first + offset;
+
+ case '\e':
+ if (nested)
+ {
+ grub_setcursor (1);
+ return -1;
}
+ break;
- if (! (c->flags & GRUB_COMMAND_FLAG_NO_ECHO))
- grub_printf ("%s\n", cl->command);
+ case 'c':
+ grub_setcursor (1);
+ grub_cmdline_run (1);
+ goto refresh;
+
+ case 'e':
+ edit_menu_entry (get_entry (menu, first + offset));
+ goto refresh;
- if (grub_command_execute (cl->command) != 0)
+ default:
break;
}
+ grub_refresh ();
+ }
+ }
+
+ /* Never reach here. */
+ return -1;
+}
+
+/* Run a menu entry. */
+static void
+run_menu_entry (grub_menu_entry_t entry)
+{
+
+ script_list_execute(entry);
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
/* Implicit execution of boot, only if something is loaded. */
grub_command_execute ("boot");
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bash pre-alpha
2005-01-29 14:08 ` Serbinenko Vladimir
@ 2005-01-29 16:04 ` Marco Gerards
2005-01-29 18:03 ` Serbinenko Vladimir
0 siblings, 1 reply; 10+ messages in thread
From: Marco Gerards @ 2005-01-29 16:04 UTC (permalink / raw)
To: The development of GRUB 2
Serbinenko Vladimir <serbinenko.vova@list.ru> writes:
> I'm sorry but I had some diff issues I confused run_menu and
> run_menu_entry. Here is a patch to correct this error and update
> i386.mk
Urgh... It seems that I do not get all my emails. The one you sent
now appears to be a follow up on an email I never received. The same
seems to be true for other emails on this list. So if I don't reply
to an email, I most likely did not receive it...
It's our custom not to send in patches for generated files. Perhaps
it is possible to use .cvsignore to make sure they are not added, it's
annoying that I always have to remove the files before making a patch.
So please just send in a patch for *.rmk next time. :)
> ./grub2pr/normal/menu.c ./grub2/normal/menu.c
> --- ./grub2pr/normal/menu.c 2005-01-29 14:55:55.000000000 +0100
> +++ ./grub2/normal/menu.c 2005-01-29 15:00:11.000000000 +0100
What does this patch do? Because I missed your last email I missed
the description. I don't see that email in the archives yet. :/
Anyway, this patch looks interesting at least. :)
Thanks,
Marco
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bash pre-alpha
2005-01-29 16:04 ` Marco Gerards
@ 2005-01-29 18:03 ` Serbinenko Vladimir
2005-01-31 5:59 ` Serbinenko Vladimir
0 siblings, 1 reply; 10+ messages in thread
From: Serbinenko Vladimir @ 2005-01-29 18:03 UTC (permalink / raw)
To: The development of GRUB 2
Marco Gerards wrote:
>Serbinenko Vladimir <serbinenko.vova@list.ru> writes:
>
>
>
>>I'm sorry but I had some diff issues I confused run_menu and
>>run_menu_entry. Here is a patch to correct this error and update
>>i386.mk
>>
>>
>
>Urgh... It seems that I do not get all my emails. The one you sent
>now appears to be a follow up on an email I never received. The same
>seems to be true for other emails on this list. So if I don't reply
>to an email, I most likely did not receive it...
>
>
>
Perhaps you have a mail filter that filters out big messages? Spam filter?
>It's our custom not to send in patches for generated files. Perhaps
>it is possible to use .cvsignore to make sure they are not added, it's
>annoying that I always have to remove the files before making a patch.
>
>So please just send in a patch for *.rmk next time. :)
>
>
>
>>./grub2pr/normal/menu.c ./grub2/normal/menu.c
>>--- ./grub2pr/normal/menu.c 2005-01-29 14:55:55.000000000 +0100
>>+++ ./grub2/normal/menu.c 2005-01-29 15:00:11.000000000 +0100
>>
>>
>
>What does this patch do? Because I missed your last email I missed
>the description. I don't see that email in the archives yet. :/
>
>Anyway, this patch looks interesting at least. :)
>
>Thanks,
>Marco
>
>
>
>
>
I resend a text part of my message. I don't want to resend a patch
because it's quite big and I suppose that not all subscribers have a
broad channel. If you want I can resend it to you personally.
With this mail I also send an incremental patch.
It contains some bugfixing(some newline handling) and new commands '.',
'while,'until', 'break', 'continue' and 'return'
About help it can be optimised as in new syntax title is not used
anymore but some script commands are integrated in parse engine because
they control executition and/or parsing. I could prepare a small help
which will be simply printed as a text-string
Best wishes
Vladimir
---------------------------------------------------------------------
Here I prepared first preview version of bash scripting engine. I repeat
*first preview version*
That means I haven't really tested it nor cleaned up or commented. This
version is only for discussions.
For now supported features are:
arrays both syntaxes i=([0]=7 ...) and i[0]
arithmetic expansion and ((...))
commands echo, ':',source
Function support:
[function ] name() { list; }
Menu entries support like
entry "<description>" { list; }
Now configuration file is parsed the same way as any script file or
console entering
menu is automatically shown after configfile is parsed or you can use
showmenu command
In arithmetical expansion some additional commands are present:
i{9} means 10-th character of i
"i",'i' means string i
Associative arrays are supported: use
z['hello']=JJJ
This version is made in the goal to show my ideas and receive the
critics. Please send your suggestions,critics and bug-reports.
Known bugs:
possible segmentation faults at incorrect constructions
Not complete GCS compilance
Some plans:
See TODO in script.c
commands clear menu and unregister_entry
Bug fixing
-----------------------------------------------------------------------
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2pr/ChangeLog
./grub2/ChangeLog
--- ./grub2pr/ChangeLog 2005-01-29 15:39:33.000000000 +0100
+++ ./grub2/ChangeLog 2005-01-29 18:51:35.000000000 +0100
@@ -1,4 +1,9 @@
2005-01-29 Serbinenko Vladimir <serbinenko.vov@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.vov@list.ru>
Scripting support
* normal/script.c: New file
* include/grub/normal.h: New prototype
diff -b -B -r -u -E -N -x '*~' --expand-tabs
./grub2pr/include/grub/script.h ./grub2/include/grub/script.h
--- ./grub2pr/include/grub/script.h 2005-01-29 15:39:33.000000000 +0100
+++ ./grub2/include/grub/script.h 2005-01-29 17:04:57.000000000 +0100
@@ -40,6 +40,7 @@
char* (*func_do)(char*a,char*b,int opn);
};
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);
@@ -72,11 +73,11 @@
int
script_get_strend(char*str);
int
-script_execute(char*cmdline,grub_err_t(*getline)(char**),char**rest);
+script_execute(char*cmdline,grub_err_t(*getline)(char**),char**rest,enum
returnreason*retres,int*depth);
int
-script_exec_file (char*fname,int argc, char**argv);
+script_list_execute( grub_menu_entry_t fn,enum
returnreason*retres,int*depth);
int
-script_list_execute(grub_menu_entry_t fn);
+script_exec_file (char*fname,int argc, char**argv);
grub_menu_t menu;
#define EXPAND_DOLLAR 1
#define EXPAND_ALL 1
diff -b -B -r -u -E -N -x '*~' --expand-tabs ./grub2pr/normal/command.c
./grub2/normal/command.c
--- ./grub2pr/normal/command.c 2005-01-29 15:39:34.000000000 +0100
+++ ./grub2/normal/command.c 2005-01-29 17:01:19.000000000 +0100
@@ -121,7 +121,7 @@
return grub_cmdline_get (">", *s, GRUB_MAX_CMDLINE, 0, 1);
}
- return script_execute(cmdline,cmdline_get,0);
+ return script_execute(cmdline,cmdline_get,0,0,0);
}
int
grub_exec_norm(char*exp)
@@ -350,6 +350,21 @@
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)
@@ -382,6 +397,13 @@
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 '*~' --expand-tabs ./grub2pr/normal/menu.c
./grub2/normal/menu.c
--- ./grub2pr/normal/menu.c 2005-01-29 15:39:34.000000000 +0100
+++ ./grub2/normal/menu.c 2005-01-29 17:07:57.000000000 +0100
@@ -379,8 +379,7 @@
static void
run_menu_entry (grub_menu_entry_t entry)
{
-
- script_list_execute(entry);
+ 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 '*~' --expand-tabs ./grub2pr/normal/script.c
./grub2/normal/script.c
--- ./grub2pr/normal/script.c 2005-01-29 15:39:34.000000000 +0100
+++ ./grub2/normal/script.c 2005-01-29 18:43:28.000000000 +0100
@@ -1427,9 +1427,9 @@
return rtval;
}
void
-script_parse_list(grub_menu_entry_t
fnptr,char**cmd,grub_err_t(*getline)(char**),int no1stskip)
+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=*cmd;
+ 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
@@ -1497,19 +1497,13 @@
}
}
char c;int brack=1;int lmin=0;
- if(!no1stskip)
+ if(!(flgs&1))
{
while(grub_isspace((c=getchar())));
switch(c)
{
case '{':
break;
- case 'd':
- if(getchar()!='o')
- break;
- if(!script_islexend(getchar()))
- break;
- break;
default:
grub_error(GRUB_ERR_BAD_ARGUMENT,"unexpected %c
'{' expected",c);
return;
@@ -1523,7 +1517,11 @@
while(brack)
{
lmin=0;
- while(grub_isspace(c=getchar()));
+ c=getchar();
+ if(grub_isspace(c))
+ continue;
+ if(c=='\n' || c==';')
+ continue;
if(c=='}')
{
brack--;
@@ -1570,6 +1568,11 @@
c=getchar();
if(script_islexend(c))
{
+ if((flgs&2) && brack==1)
+ {
+ lmin=3;
+ break;
+ }
brack++;
continue;
}
@@ -1594,7 +1597,7 @@
while(1)
{
if((c=getchar())!='l')
- break;;
+ break;
c=getchar();
if(c=='s')
{
@@ -1630,10 +1633,13 @@
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)
+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)
@@ -1650,7 +1656,12 @@
int rtval=0;
while(cmdlist)
{
- rtval=script_execute(cmdlist->command,getln,0);
+ enum returnreason rt;
+
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;
}
@@ -1754,12 +1765,12 @@
getln(&ln);
if(!ln)
break;
- ret=script_execute(ln,getln,0);
+ ret=script_execute(ln,getln,0,0,0);
}
return ret;
}
int
-script_execute(char*cmdline,grub_err_t(*getline)(char**),char**rest)
+script_execute(char*cmdline,grub_err_t(*getline)(char**),char**rest,enum
returnreason*retres,int*depth)
{
int rtval=0,semdel=0;
int invrtval=0;
@@ -1780,6 +1791,8 @@
return 1;
}
if(rest)*rest=0;
+ if(retres)
+ *retres=SCRIPT_NONE;
while(1)
{
if(invrtval)
@@ -1825,9 +1838,17 @@
end+=2;
while(!end || !*end ||
grub_memcmp(end,"then",4)|| !script_islexend(end[4]))
{
+ enum returnreason rt;
if(!end || !*end)
getline(&end);
- ret=!script_execute(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;
@@ -1836,7 +1857,15 @@
end+=4;
script_parse_list(lst,&end,getline,1);
if(ret)
- rtval=script_list_execute(lst);
+ {
+ 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])))
@@ -1851,9 +1880,17 @@
{
while(!end || !*end ||
grub_memcmp(end,"then",4)|| !script_islexend(end[4]))
{
+ enum returnreason rt;
if(!end || !*end)
getline(&end);
-
crtval=!script_execute(end,getline,&end);
+ if(*end)
+ {
+
ret=!script_execute(end,getline,&end,&rt,depth);
+ if(retres)
+ *retres=rt;
+ if(rt)
+ return
rtval;
+ }
}
end+=4;
}
@@ -1862,14 +1899,63 @@
script_parse_list(lst,&end,getline,1);
if(crtval)
{
- rtval=script_list_execute(lst);
+ 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,"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(end[0]=='(' && end[1]=='(')
{
char*exp=script_expand(end,getline,&end,EXPAND_DOLLAR);
@@ -1939,6 +2025,40 @@
char*exp=script_expand(end,getline,&end,EXPAND_ALL);
while(grub_isspace(*exp))exp++;
char*expcur=exp;
+
if(!grub_memcmp("return",expcur,sizeof("return")-1)&&script_islexend(expcur[sizeof("return")-1]))
+ {
+ expcur+=sizeof("return")-1;
+ while(grub_isspace(*expcur))expcur++;
+ if(*expcur=='-' ||grub_isdigit(*expcur))
+ rtval=grub_strtol(expcur,&expcur,0);
+ if(retres)
+ *retres=SCRIPT_RETURN;
+ return rtval;
+ }
+
if(!grub_memcmp("continue",expcur,sizeof("continue")-1)&&script_islexend(expcur[sizeof("continue")-1]))
+ {
+ expcur+=sizeof("continue")-1;
+ while(grub_isspace(*expcur))expcur++;
+ if(depth)
+ *depth=1;
+ if(depth && (*expcur=='-'
||grub_isdigit(*expcur) ))
+ *depth=grub_strtol(expcur,&expcur,0);;
+ if(retres)
+ *retres=SCRIPT_CONTINUE;
+ return rtval;
+ }
+
if(!grub_memcmp("break",expcur,sizeof("break")-1)&&script_islexend(expcur[sizeof("break")-1]))
+ {
+ expcur+=sizeof("break")-1;
+ while(grub_isspace(*expcur))expcur++;
+ if(depth)
+ *depth=1;
+ if(depth && (*expcur=='-'
||grub_isdigit(*expcur) ))
+ *depth=grub_strtol(expcur,&expcur,0);
+ if(retres)
+ *retres=SCRIPT_BREAK;
+ return rtval;
+ }
{
grub_menu_entry_t cur=funcs.entry_list;
if(funcs.entry_list)
@@ -1952,7 +2072,7 @@
if(cur)
{
expcur+=grub_strlen(cur->title);
- rtval=script_list_execute(cur);
+ rtval=script_list_execute(cur,0,0);
continue;
}
}
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: Bash pre-alpha
2005-01-29 18:03 ` Serbinenko Vladimir
@ 2005-01-31 5:59 ` Serbinenko Vladimir
0 siblings, 0 replies; 10+ messages in thread
From: Serbinenko Vladimir @ 2005-01-31 5:59 UTC (permalink / raw)
To: The development of GRUB 2
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;
+}
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2005-01-31 6:16 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 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.