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  <bvk.gro...@gmail.com>
 
+       * 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  <bvk.gro...@gmail.com>
+
        * 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
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to