From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1CvUrL-0007O2-JA for mharc-grub-devel@gnu.org; Mon, 31 Jan 2005 01:16:27 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1CvUrJ-0007Na-Pt for grub-devel@gnu.org; Mon, 31 Jan 2005 01:16:26 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1CvUrE-0007Lg-Hd for grub-devel@gnu.org; Mon, 31 Jan 2005 01:16:25 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1CvUrD-0007LA-I5 for grub-devel@gnu.org; Mon, 31 Jan 2005 01:16:19 -0500 Received: from [194.67.23.121] (helo=mx1.mail.ru) by monty-python.gnu.org with esmtp (Exim 4.34) id 1CvUb5-0008WA-N8 for grub-devel@gnu.org; Mon, 31 Jan 2005 00:59:43 -0500 Received: from [81.62.4.25] (port=1294 helo=[192.168.1.100]) by mx1.mail.ru with esmtp id 1CvUaq-000Pan-00 for grub-devel@gnu.org; Mon, 31 Jan 2005 08:59:24 +0300 Message-ID: <41FDC95A.1090703@list.ru> Date: Mon, 31 Jan 2005 06:59:54 +0100 From: Serbinenko Vladimir User-Agent: Mozilla Thunderbird 1.0 (X11/20041206) X-Accept-Language: en-us, en MIME-Version: 1.0 To: The development of GRUB 2 References: <200501221618.27972.okuji@enbug.org> <200501221835.25876.okuji@enbug.org> <41FB8D22.8030203@list.ru> <41FB98D9.1090309@list.ru> <871xc4rzlq.fsf@marco.marco-g.com> <41FBCFFC.8060507@list.ru> In-Reply-To: <41FBCFFC.8060507@list.ru> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Spam: Not detected Subject: Re: Bash pre-alpha X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 31 Jan 2005 06:16:26 -0000 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 + + * 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 + + * 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 + + 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 * 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 #include #include +#include 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;isize) + 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 #include #include +#include /* 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/*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)<>*/ +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;ilenfound && + ((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-contmaxindx) + 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') + && !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(optrword=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-expsnum=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-expstitle,exps[0])) + break; + cur=cur->next; + } + if(cur) + { + rtval=script_list_execute(cur,0,0); + continue; + } + } + } + rtval=grub_exec_norm(exps,argc); + } + return rtval; +}