Hi,
This patch fixes a GRUB script bug in expanding (and splitting into
parameters) words like, aaa${foo}bbb, aaa"bbb ${foo} ccc"ddd, etc.
forms.
thanks,
--
bvk.chaitanya
=== modified file 'ChangeLog.scripting'
--- ChangeLog.scripting 2009-12-25 18:16:20 +0000
+++ ChangeLog.scripting 2009-12-25 12:13:34 +0000
@@ -1,5 +1,25 @@
2009-12-25 BVK Chaitanya <[email protected]>
+ * include/grub/script_sh.h (grub_script_arg_type_t): New types
+ added.
+ (grub_script_execute_arglist_to_arg): Function proptotype added.
+ (grub_script_execute_argument_to_string): Prototype is removed.
+ * script/execute.c (grub_script_execute_arglist_to_arg): New
+ function to convert arglist to argv.
+ (grub_script_execute_cmdfor): Updated to make use of arglist to
+ argv conversion function.
+ (grub_script_execute_cmdline): Likewise.
+ (grub_script_execute_menuentry): Likewise.
+ (grub_script_execute_argument_to_string): Removed.
+ * script/function.c (grub_script_function_create): Removed
+ unnecessary reference to removed function
+ grub_script_execute_argument_to_string.
+ * script/lexer.c (grub_script_yylex): Fixed grub_script_arg
+ argument construction.
+ * script/yylex.l: Likewise.
+
+2009-12-25 BVK Chaitanya <[email protected]>
+
* conf/tests.rmk: Makerules for new unit tests.
* include/grub/script_sh.h: Function prototypes for for statement
functions.
=== modified file 'include/grub/script_sh.h'
--- include/grub/script_sh.h 2009-12-25 18:16:20 +0000
+++ include/grub/script_sh.h 2009-12-25 12:13:34 +0000
@@ -45,8 +45,11 @@
typedef enum
{
- GRUB_SCRIPT_ARG_TYPE_STR,
- GRUB_SCRIPT_ARG_TYPE_VAR
+ GRUB_SCRIPT_ARG_TYPE_VAR,
+ GRUB_SCRIPT_ARG_TYPE_TEXT,
+ GRUB_SCRIPT_ARG_TYPE_DQVAR,
+ GRUB_SCRIPT_ARG_TYPE_DQSTR,
+ GRUB_SCRIPT_ARG_TYPE_SQSTR
} grub_script_arg_type_t;
/* A part of an argument. */
@@ -172,6 +175,9 @@
/* Text of current token. */
char *text;
+ /* Type of text. */
+ grub_script_arg_type_t type;
+
/* Flex scanner. */
void *yyscanner;
@@ -316,7 +322,7 @@
int grub_script_function_call (grub_script_function_t func,
int argc, char **args);
-char *
-grub_script_execute_argument_to_string (struct grub_script_arg *arg);
+char **
+grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist);
#endif /* ! GRUB_NORMAL_PARSER_HEADER */
=== modified file 'script/execute.c'
--- script/execute.c 2009-12-25 18:16:20 +0000
+++ script/execute.c 2009-12-25 12:13:34 +0000
@@ -35,49 +35,132 @@
return cmd->exec (cmd);
}
-/* Parse ARG and return the textual representation. Add strings are
- concatenated and all values of the variables are filled in. */
-char *
-grub_script_execute_argument_to_string (struct grub_script_arg *arg)
+#define ROUND_UPTO(sz,up) (((sz) + (up) - 1) / (up) * (up))
+
+/* Expand arguments in ARGLIST into multiple arguments. */
+char **
+grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist)
{
- int size = 0;
- char *val;
- char *chararg;
- struct grub_script_arg *argi;
-
- /* First determine the size of the argument. */
- for (argi = arg; argi; argi = argi->next)
- {
- if (argi->type == 1)
- {
- val = grub_env_get (argi->str);
- if (val)
- size += grub_strlen (val);
- }
- else
- size += grub_strlen (argi->str);
- }
-
- /* Create the argument. */
- chararg = grub_malloc (size + 1);
- if (! chararg)
- return 0;
-
- *chararg = '\0';
- /* First determine the size of the argument. */
- for (argi = arg; argi; argi = argi->next)
- {
- if (argi->type == 1)
- {
- val = grub_env_get (argi->str);
- if (val)
- grub_strcat (chararg, val);
- }
- else
- grub_strcat (chararg, argi->str);
- }
-
- return chararg;
+ int i;
+ int oom;
+ int argc;
+ char *ptr;
+ char **argv;
+ char *value;
+ struct grub_script_arg *arg;
+
+ auto void push (char *str);
+ void push (char *str)
+ {
+ char **ptr;
+
+ if (oom)
+ return;
+
+ ptr = grub_realloc (argv, ROUND_UPTO (sizeof(char*) * (argc + 1), 32));
+ if (!ptr)
+ oom = 1;
+ else
+ {
+ ptr[argc++] = str;
+ argv = ptr;
+ }
+ }
+
+ auto char* append (const char *str, grub_size_t nchar);
+ char* append (const char *str, grub_size_t nchar)
+ {
+ int len;
+ int old;
+ char *ptr;
+
+ if (oom || !str)
+ return 0;
+
+ len = nchar ?: grub_strlen (str);
+ old = argv[argc - 1] ? grub_strlen (argv[argc - 1]) : 0;
+ ptr = grub_realloc (argv[argc - 1], ROUND_UPTO(old + len + 1, 32));
+
+ if (ptr)
+ {
+ grub_strncpy (ptr + old, str, len);
+ ptr[old + len] = '\0';
+ }
+ else
+ {
+ oom = 1;
+ grub_free (argv[argc - 1]);
+ }
+ argv[argc - 1] = ptr;
+ return argv[argc - 1];
+ }
+
+ /* Move *STR to the begining of next word, but return current word. */
+ char* move_to_next (char **str)
+ {
+ char *end;
+ char *start;
+
+ if (oom || !str || !*str)
+ return 0;
+
+ start = *str;
+ while (*start && grub_isspace (*start)) start++;
+ if (*start == '\0')
+ return 0;
+
+ end = start + 1;
+ while (*end && !grub_isspace (*end)) end++;
+
+ *str = end;
+ return start;
+ }
+
+ oom = 0;
+ argv = 0;
+ argc = 0;
+ for (; arglist; arglist = arglist->next)
+ {
+ push (0);
+ arg = arglist->arg;
+
+ while (arg)
+ {
+ switch (arg->type)
+ {
+ case GRUB_SCRIPT_ARG_TYPE_VAR:
+ value = grub_env_get (arg->str);
+ while (*value && (ptr = move_to_next(&value)))
+ {
+ append (ptr, value - ptr);
+ if (*value) push(0);
+ }
+ break;
+
+ case GRUB_SCRIPT_ARG_TYPE_TEXT:
+ case GRUB_SCRIPT_ARG_TYPE_DQSTR:
+ case GRUB_SCRIPT_ARG_TYPE_SQSTR:
+ append (arg->str, 0);
+ break;
+
+ case GRUB_SCRIPT_ARG_TYPE_DQVAR:
+ append (grub_env_get (arg->str), 0);
+ break;
+ }
+ arg = arg->next;
+ }
+ }
+ push (0); /* Ensure argv[argc] == 0. */
+
+ if (oom)
+ {
+ for (i = 0; i < argc; i++)
+ grub_free (argv[i]);
+ grub_free (argv);
+ argv = 0;
+ }
+
+ return argv;
}
/* Execute a single command line. */
@@ -85,7 +168,6 @@
grub_script_execute_cmdline (struct grub_script_cmd *cmd)
{
struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd;
- struct grub_script_arglist *arglist;
char **args = 0;
int i = 0;
grub_command_t grubcmd;
@@ -96,7 +178,11 @@
char *cmdname;
/* Lookup the command. */
- cmdname = grub_script_execute_argument_to_string (cmdline->arglist->arg);
+ args = grub_script_execute_arglist_to_argv (cmdline->arglist);
+ if (!args)
+ return grub_errno;
+
+ cmdname = args[0];
grubcmd = grub_command_find (cmdname);
if (! grubcmd)
{
@@ -129,27 +215,15 @@
return 0;
}
}
- grub_free (cmdname);
-
- if (cmdline->arglist->next)
- {
- argcount = cmdline->arglist->argcount - 1;
-
- /* Create argv from the arguments. */
- args = grub_malloc (sizeof (char *) * argcount);
- for (arglist = cmdline->arglist->next; arglist; arglist = arglist->next)
- {
- char *str;
- str = grub_script_execute_argument_to_string (arglist->arg);
- args[i++] = str;
- }
- }
+
+ /* Count argv size. */
+ for (argcount = 0; args[argcount]; argcount++);
/* Execute the GRUB command or function. */
if (grubcmd)
- ret = (grubcmd->func) (grubcmd, argcount, args);
+ ret = (grubcmd->func) (grubcmd, argcount - 1, args + 1);
else
- ret = grub_script_function_call (func, argcount, args);
+ ret = grub_script_function_call (func, argcount - 1, args + 1);
/* Free arguments. */
for (i = 0; i < argcount; i++)
@@ -201,50 +275,24 @@
grub_err_t
grub_script_execute_cmdfor (struct grub_script_cmd *cmd)
{
- char *str;
- char *end;
- char *start;
- int last;
+ int i;
int result;
- struct grub_script_arglist *word;
+ char **args;
struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd;
+ args = grub_script_execute_arglist_to_argv (cmdfor->words);
+ if (!args)
+ return grub_errno;
+
result = 0;
- word = cmdfor->words;
- while (word)
+ for (i = 0; args[i]; i++)
{
- str = grub_script_execute_argument_to_string (word->arg);
- if (!str)
- return 1;
-
- last = 0;
- start = str;
- while (!last && *start)
- {
- /* Skip whitespaces. */
- while (*start && grub_isspace (*start))
- start++;
-
- if (*start == '\0')
- break;
-
- end = start + 1;
- while (*end && !grub_isspace (*end))
- end++;
- if (*end == '\0')
- last = 1;
- else
- *end = '\0';
-
- grub_env_set (cmdfor->name->str, start);
- result = grub_script_execute_cmd (cmdfor->list);
- start = end + 1;
- }
-
- grub_free (str);
- word = word->next;
+ grub_env_set (cmdfor->name->str, args[i]);
+ result = grub_script_execute_cmd (cmdfor->list);
+ grub_free (args[i]);
}
+ grub_free (args);
return result;
}
@@ -253,7 +301,6 @@
grub_script_execute_menuentry (struct grub_script_cmd *cmd)
{
struct grub_script_cmd_menuentry *cmd_menuentry;
- struct grub_script_arglist *arglist;
char **args = 0;
int argcount = 0;
int i = 0;
@@ -262,22 +309,11 @@
if (cmd_menuentry->arglist)
{
- argcount = cmd_menuentry->arglist->argcount;
-
- /* Create argv from the arguments. */
- args = grub_malloc (sizeof (char *) * argcount);
-
- if (! args)
- {
- return grub_errno;
- }
-
- for (arglist = cmd_menuentry->arglist; arglist; arglist = arglist->next)
- {
- char *str;
- str = grub_script_execute_argument_to_string (arglist->arg);
- args[i++] = str;
- }
+ args = grub_script_execute_arglist_to_argv (cmd_menuentry->arglist);
+ if (!args)
+ return grub_errno;
+
+ for (argcount = 0; args[argcount]; argcount++);
}
grub_normal_add_menu_entry (argcount, (const char **) args,
=== modified file 'script/function.c'
--- script/function.c 2009-11-23 15:37:33 +0000
+++ script/function.c 2009-12-25 12:13:34 +0000
@@ -34,7 +34,7 @@
if (! func)
return 0;
- func->name = grub_script_execute_argument_to_string (functionname_arg);
+ func->name = grub_strdup (functionname_arg->str);
if (! func->name)
{
grub_free (func);
=== modified file 'script/lexer.c'
--- script/lexer.c 2009-12-20 07:30:02 +0000
+++ script/lexer.c 2009-12-25 12:13:34 +0000
@@ -302,13 +302,12 @@
{
lexerstate->text[lexerstate->size] = '\0';
str = lexerstate->text;
- type = (token == GRUB_PARSER_TOKEN_NAME ?
- GRUB_SCRIPT_ARG_TYPE_VAR : GRUB_SCRIPT_ARG_TYPE_STR);
+ type = lexerstate->type;
}
else
{
str = yyget_text (lexerstate->yyscanner);
- type = GRUB_SCRIPT_ARG_TYPE_STR;
+ type = GRUB_SCRIPT_ARG_TYPE_TEXT;
}
/* grub_printf ("tok %u, txt [%s] size %u\n", token, str,
lexerstate->size); */
=== modified file 'script/yylex.l'
--- script/yylex.l 2009-12-20 07:00:31 +0000
+++ script/yylex.l 2009-12-25 12:13:34 +0000
@@ -11,8 +11,8 @@
#define yyrealloc grub_lexer_yyrealloc
/*
- * XXX As we don't have access to yyscanner, we cannot do much except
- * to print the fatal error.
+ * As we don't have access to yyscanner, we cannot do much except to
+ * print the fatal error.
*/
#define YY_FATAL_ERROR(msg) \
do { \
@@ -42,6 +42,12 @@
grub_script_lexer_record (yyextra, yytext); \
} while (0)
+#define ARG(t) \
+ do { \
+ yyextra->lexerstate->type = t; \
+ return GRUB_PARSER_TOKEN_WORD; \
+ } while (0)
+
/* We don't need YY_INPUT, as we rely on yy_scan_strings */
#define YY_INPUT(buf,res,max) do { res = 0; } while (0)
@@ -197,15 +203,22 @@
<SPLIT>{
\\. { PUSH (yytext[1]); }
- \" { yy_push_state (DQUOTE, yyscanner); }
- \' { yy_push_state (SQUOTE, yyscanner); }
+ \" {
+ yy_push_state (DQUOTE, yyscanner);
+ ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
+ }
+ \' {
+ yy_push_state (SQUOTE, yyscanner);
+ ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
+ }
\$ {
yy_push_state (VAR, yyscanner);
- return GRUB_PARSER_TOKEN_WORD;
+ ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
}
{CHAR} { PUSH (yytext[0]); }
.|\n {
- grub_script_yyerror (yyextra, "unrecognized token");
+ /* This cannot happen. */
+ grub_script_yyerror (yyextra, "internal error: unexpected
characters in a word");
return GRUB_PARSER_TOKEN_BAD;
}
@@ -213,7 +226,7 @@
yy_pop_state (yyscanner);
yypop_buffer_state (yyscanner);
yyextra->lexerstate->merge_end = 1;
- return GRUB_PARSER_TOKEN_WORD;
+ ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
}
}
@@ -221,27 +234,39 @@
{NAME} {
COPY (yytext);
yy_pop_state (yyscanner);
- return GRUB_PARSER_TOKEN_NAME;
+ if (YY_START == SPLIT)
+ ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
+ else
+ ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
}
\{{NAME}\} {
yytext[yyleng - 1] = '\0';
COPY (yytext + 1);
yy_pop_state (yyscanner);
- return GRUB_PARSER_TOKEN_NAME;
+ if (YY_START == SPLIT)
+ ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
+ else
+ ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
}
.|\n { return GRUB_PARSER_TOKEN_BAD; }
}
<SQUOTE>{
- \' { yy_pop_state (yyscanner); }
+ \' {
+ yy_pop_state (yyscanner);
+ ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
+ }
(.|\n) { PUSH (yytext[0]); }
}
<DQUOTE>{
- \" { yy_pop_state (yyscanner); }
+ \" {
+ yy_pop_state (yyscanner);
+ ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
+ }
\$ {
yy_push_state (VAR, yyscanner);
- return GRUB_PARSER_TOKEN_WORD;
+ ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
}
\\\\ { PUSH ('\\'); }
\\\" { PUSH ('\"'); }
_______________________________________________
Grub-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/grub-devel