]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
menuentry option parsing is done using lib/arg.c
authorBVK Chaitanya <bvk.groups@gmail.com>
Thu, 22 Jul 2010 13:31:40 +0000 (19:01 +0530)
committerBVK Chaitanya <bvk.groups@gmail.com>
Thu, 22 Jul 2010 13:31:40 +0000 (19:01 +0530)
commands/extcmd.c
commands/menuentry.c
include/grub/lib/arg.h
include/grub/normal.h
lib/arg.c
normal/main.c
script/script.c

index 8fe2ead3578c97ba8eb7798eb5a29df9c14bebaf..4b3d9d36b63ed9b01b130b14a75ca60960ce506a 100644 (file)
@@ -29,10 +29,8 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args,
 {
   int new_argc;
   char **new_args;
-  struct grub_arg_option *parser;
   struct grub_arg_list *state;
   struct grub_extcmd_context context;
-  int maxargs = 0;
   grub_err_t ret;
   grub_extcmd_t ext = cmd->data;
 
@@ -46,24 +44,20 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args,
       return ret;
     }
 
-  parser = (struct grub_arg_option *) ext->options;
-  while (parser && (parser++)->doc)
-    maxargs++;
-
-  /* Set up the option state.  */
-  state = grub_zalloc (sizeof (struct grub_arg_list) * maxargs);
-
+  state = grub_arg_list_alloc (ext, argc, args);
   if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc))
     {
       context.state = state;
       ret = (ext->func) (&context, new_argc, new_args);
       grub_free (new_args);
+      grub_free (state);
+      return ret;
     }
-  else
-    ret = grub_errno;
 
-  grub_free (state);
-  return ret;
+  if (state)
+    grub_free (state);
+
+  return grub_errno;
 }
 
 static grub_err_t
index 2d389e9425d293c9733761023a4145e3a44c338f..6b7214d629fd069e172285e2ee7cb3bbe1bda5bd 100644 (file)
 #include <grub/i18n.h>
 #include <grub/normal.h>
 
+static const struct grub_arg_option options[] =
+  {
+    {"class", 1, GRUB_ARG_OPTION_REPEATABLE,
+     N_("Menu entry type."), "STRING", ARG_TYPE_STRING},
+    {"users", 2, 0,
+     N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING},
+    {"hotkey", 3, 0,
+     N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING},
+    {0, 0, 0, 0, 0, 0}
+  };
+
+static struct
+{
+  char *name;
+  int key;
+} hotkey_aliases[] =
+  {
+    {"backspace", '\b'},
+    {"tab", '\t'},
+    {"delete", GRUB_TERM_DC}
+  };
+
+/* Add a menu entry to the current menu context (as given by the environment
+   variable data slot `menu').  As the configuration file is read, the script
+   parser calls this when a menu entry is to be created.  */
+static grub_err_t
+add_menu_entry (int argc, const char **args, char **classes,
+               const char *users, const char *hotkey,
+               const char *sourcecode)
+{
+  unsigned i;
+  int menu_hotkey = 0;
+  char *menu_users = NULL;
+  char *menu_title = NULL;
+  char *menu_sourcecode = NULL;
+  struct grub_menu_entry_class *menu_classes = NULL;
+
+  grub_menu_t menu;
+  grub_menu_entry_t *last;
+
+  menu = grub_env_get_menu ();
+  if (! menu)
+    return grub_error (GRUB_ERR_MENU, "no menu context");
+
+  last = &menu->entry_list;
+
+  menu_sourcecode = grub_strdup (sourcecode);
+  if (! menu_sourcecode)
+    return grub_errno;
+
+  if (classes)
+    {
+      for (i = 0; classes[i]; i++); /* count # of menuentry classes */
+      menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class) * i);
+      if (! menu_classes)
+       goto fail;
+
+      for (i = 0; classes[i]; i++)
+       {
+         menu_classes[i].name = grub_strdup (classes[i]);
+         if (! menu_classes[i].name)
+           goto fail;
+         menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL;
+       }
+    }
+
+  if (users)
+    {
+      menu_users = grub_strdup (users);
+      if (! menu_users)
+       goto fail;
+    }
+
+  if (hotkey)
+    {
+      for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++)
+       if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0)
+         {
+           menu_hotkey = hotkey_aliases[i].key;
+           break;
+         }
+      if (i > ARRAY_SIZE (hotkey_aliases))
+       goto fail;
+    }
+
+  if (! argc)
+    {
+      grub_error (GRUB_ERR_MENU, "menuentry is missing title");
+      goto fail;
+    }
+
+  menu_title = grub_strdup (args[0]);
+  if (! menu_title)
+    goto fail;
+
+  /* XXX: pass args[1..end] as parameters to block arg. */
+
+  /* Add the menu entry at the end of the list.  */
+  while (*last)
+    last = &(*last)->next;
+
+  *last = grub_zalloc (sizeof (**last));
+  if (! *last)
+    goto fail;
+
+  (*last)->title = menu_title;
+  (*last)->hotkey = menu_hotkey;
+  (*last)->classes = menu_classes;
+  if (menu_users)
+    (*last)->restricted = 1;
+  (*last)->users = menu_users;
+  (*last)->sourcecode = menu_sourcecode;
+
+  menu->size++;
+  return GRUB_ERR_NONE;
+
+ fail:
+
+  grub_free (menu_sourcecode);
+  for (i = 0; menu_classes && menu_classes[i].name; i++)
+    grub_free (menu_classes[i].name);
+  grub_free (menu_classes);
+  grub_free (menu_users);
+  grub_free (menu_title);
+  return grub_errno;
+}
+
 static grub_err_t
 grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
 {
+  char ch;
   char *src;
   unsigned len;
   grub_err_t r;
 
-  /* XXX Rewrite to make use of already parsed menu definition.  */
   if (! argc || ! ctxt->script)
     return GRUB_ERR_BAD_ARGUMENT;
 
   src = args[argc - 1];
-  args[argc - 1] = '\0';
+  args[argc - 1] = NULL;
+
   len = grub_strlen(src);
+  ch = src[len - 1];
   src[len - 1] = '\0';
 
-  r = grub_normal_add_menu_entry (argc - 1, (const char **) args, src + 1);
+  r = add_menu_entry (argc - 1, (const char **) args,
+                     ctxt->state[0].args, ctxt->state[1].arg,
+                     ctxt->state[2].arg, src + 1);
 
-  src[len - 1] = '}';
+  src[len - 1] = ch;
   args[argc - 1] = src;
   return r;
 }
@@ -54,7 +185,7 @@ GRUB_MOD_INIT(menuentry)
 {
   cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry,
                              GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS,
-                             N_("BLOCK"), N_("Define a menuentry."), 0);
+                             N_("BLOCK"), N_("Define a menuentry."), options);
 }
 
 GRUB_MOD_FINI(menuentry)
index e6af60cf97ae67ee7dcd148f36f1114ecac8565e..3bab277816560fbf6096385525c5888d68f5f209 100644 (file)
@@ -38,6 +38,8 @@ typedef enum grub_arg_type grub_arg_type_t;
 
 /* Flags for the option field op grub_arg_option.  */
 #define GRUB_ARG_OPTION_OPTIONAL       (1 << 1)
+/* Flags for an option that can appear multiple times.  */
+#define GRUB_ARG_OPTION_REPEATABLE      (1 << 2)
 
 enum grub_key_type
   {
@@ -59,7 +61,10 @@ struct grub_arg_option
 struct grub_arg_list
 {
   int set;
-  char *arg;
+  union {
+    char *arg;
+    char **args;
+  };
 };
 
 struct grub_extcmd;
@@ -68,5 +73,7 @@ int grub_arg_parse (struct grub_extcmd *cmd, int argc, char **argv,
                    struct grub_arg_list *usr, char ***args, int *argnum);
 
 void grub_arg_show_help (struct grub_extcmd *cmd);
+struct grub_arg_list* grub_arg_list_alloc (struct grub_extcmd *cmd,
+                                          int argc, char *argv[]);
 
 #endif /* ! GRUB_ARG_HEADER */
index a33e42e6176e0eedb753cb7927333e4de0a7c369..04d08a55711ea82a0d9235412e249904f02fac6b 100644 (file)
@@ -54,8 +54,6 @@ void grub_normal_execute (const char *config, int nested, int batch);
 void grub_menu_init_page (int nested, int edit,
                          struct grub_term_output *term);
 void grub_normal_init_page (struct grub_term_output *term);
-grub_err_t grub_normal_add_menu_entry (int argc, const char **args,
-                                      const char *sourcecode);
 char *grub_file_getline (grub_file_t file);
 void grub_cmdline_run (int nested);
 
index 04e0ea8baae68c9d6d425230b9d5df152f31cd0f..a11496d5bfe0ce85b6cbb8f06611fb55cff64d85 100644 (file)
--- a/lib/arg.c
+++ b/lib/arg.c
@@ -207,8 +207,16 @@ parse_option (grub_extcmd_t cmd, int key, char *arg, struct grub_arg_list *usr)
        if (found == -1)
          return -1;
 
-       usr[found].set = 1;
-       usr[found].arg = arg;
+       if (opt->flags & GRUB_ARG_OPTION_REPEATABLE)
+         {
+           usr[found].args[usr[found].set++] = arg;
+           usr[found].args[usr[found].set] = NULL;
+         }
+       else
+         {
+           usr[found].set = 1;
+           usr[found].arg = arg;
+         }
       }
     }
 
@@ -229,13 +237,14 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
   grub_err_t add_arg (char *s)
     {
       char **p = argl;
-      argl = grub_realloc (argl, (++num) * sizeof (char *));
+      argl = grub_realloc (argl, (++num + 1) * sizeof (char *));
       if (! argl)
        {
          grub_free (p);
          return grub_errno;
        }
       argl[num - 1] = s;
+      argl[num] = NULL;
       return 0;
     }
 
@@ -312,8 +321,11 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
          if (option) {
            arglen = option - arg - 2;
            option++;
-         } else
+         } else {
            arglen = grub_strlen (arg) - 2;
+           if (argv[curarg + 1])
+             option = argv[curarg + 1][0] == '-' ? 0 : argv[++curarg];
+         }
 
          opt = find_long (cmd->options, arg + 2, arglen);
          if (! opt)
@@ -392,3 +404,43 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
  fail:
   return complete;
 }
+
+struct grub_arg_list*
+grub_arg_list_alloc(grub_extcmd_t extcmd, int argc,
+                   char **argv __attribute__((unused)))
+{
+  int i;
+  char **args;
+  unsigned argcnt;
+  struct grub_arg_list *list;
+  const struct grub_arg_option *options;
+
+  options = extcmd->options;
+  if (! options)
+    return 0;
+
+  argcnt = 0;
+  for (i = 0; options[i].doc; i++)
+    {
+      if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
+       argcnt += (argc + 1) / 2 + 1; /* max possible for any option */
+    }
+
+  list = grub_zalloc (sizeof (*list) * i + sizeof (char*) * argcnt);
+  if (! list)
+    return 0;
+
+  args = (char**) (list + i);
+  for (i = 0; options[i].doc; i++)
+    {
+      list[i].set = 0;
+      list[i].arg = 0;
+
+      if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
+       {
+         list[i].args = args;
+         args += argc / 2 + 1;
+       }
+    }
+  return list;
+}
index 710b68d144702bf7e4bd116532d1d73e2be03eeb..6997b5d6a84fc1e84829751fb170e4fbde8830bb 100644 (file)
@@ -141,209 +141,6 @@ free_menu (grub_menu_t menu)
   grub_env_unset_menu ();
 }
 
-static void
-free_menu_entry_classes (struct grub_menu_entry_class *head)
-{
-  /* Free all the classes.  */
-  while (head)
-    {
-      struct grub_menu_entry_class *next;
-
-      grub_free (head->name);
-      next = head->next;
-      grub_free (head);
-      head = next;
-    }
-}
-
-static struct
-{
-  char *name;
-  int key;
-} hotkey_aliases[] =
-  {
-    {"backspace", '\b'},
-    {"tab", '\t'},
-    {"delete", GRUB_TERM_DC}
-  };
-
-/* Add a menu entry to the current menu context (as given by the environment
-   variable data slot `menu').  As the configuration file is read, the script
-   parser calls this when a menu entry is to be created.  */
-grub_err_t
-grub_normal_add_menu_entry (int argc, const char **args,
-                           const char *sourcecode)
-{
-  const char *menutitle = 0;
-  const char *menusourcecode;
-  grub_menu_t menu;
-  grub_menu_entry_t *last;
-  int failed = 0;
-  int i;
-  struct grub_menu_entry_class *classes_head;  /* Dummy head node for list.  */
-  struct grub_menu_entry_class *classes_tail;
-  char *users = NULL;
-  int hotkey = 0;
-
-  /* Allocate dummy head node for class list.  */
-  classes_head = grub_zalloc (sizeof (struct grub_menu_entry_class));
-  if (! classes_head)
-    return grub_errno;
-  classes_tail = classes_head;
-
-  menu = grub_env_get_menu ();
-  if (! menu)
-    return grub_error (GRUB_ERR_MENU, "no menu context");
-
-  last = &menu->entry_list;
-
-  menusourcecode = grub_strdup (sourcecode);
-  if (! menusourcecode)
-    return grub_errno;
-
-  /* Parse menu arguments.  */
-  for (i = 0; i < argc; i++)
-    {
-      /* Capture arguments.  */
-      if (grub_strncmp ("--", args[i], 2) == 0 && i + 1 < argc)
-       {
-         const char *arg = &args[i][2];
-
-         /* Handle menu class.  */
-         if (grub_strcmp(arg, "class") == 0)
-           {
-             char *class_name;
-             struct grub_menu_entry_class *new_class;
-
-             i++;
-             class_name = grub_strdup (args[i]);
-             if (! class_name)
-               {
-                 failed = 1;
-                 break;
-               }
-
-             /* Create a new class and add it at the tail of the list.  */
-             new_class = grub_zalloc (sizeof (struct grub_menu_entry_class));
-             if (! new_class)
-               {
-                 grub_free (class_name);
-                 failed = 1;
-                 break;
-               }
-             /* Fill in the new class node.  */
-             new_class->name = class_name;
-             /* Link the tail to it, and make it the new tail.  */
-             classes_tail->next = new_class;
-             classes_tail = new_class;
-             continue;
-           }
-         else if (grub_strcmp(arg, "users") == 0)
-           {
-             i++;
-             users = grub_strdup (args[i]);
-             if (! users)
-               {
-                 failed = 1;
-                 break;
-               }
-
-             continue;
-           }
-         else if (grub_strcmp(arg, "hotkey") == 0)
-           {
-             unsigned j;
-
-             i++;
-             if (args[i][1] == 0)
-               {
-                 hotkey = args[i][0];
-                 continue;
-               }
-
-             for (j = 0; j < ARRAY_SIZE (hotkey_aliases); j++)
-               if (grub_strcmp (args[i], hotkey_aliases[j].name) == 0)
-                 {
-                   hotkey = hotkey_aliases[j].key;
-                   break;
-                 }
-
-             if (j < ARRAY_SIZE (hotkey_aliases))
-               continue;
-
-             failed = 1;
-             grub_error (GRUB_ERR_MENU,
-                         "Invalid hotkey: '%s'.", args[i]);
-             break;
-           }
-         else
-           {
-             /* Handle invalid argument.  */
-             failed = 1;
-             grub_error (GRUB_ERR_MENU,
-                         "invalid argument for menuentry: %s", args[i]);
-             break;
-           }
-       }
-
-      /* Capture title.  */
-      if (! menutitle)
-       {
-         menutitle = grub_strdup (args[i]);
-       }
-      else
-       {
-         failed = 1;
-         grub_error (GRUB_ERR_MENU,
-                     "too many titles for menuentry: %s", args[i]);
-         break;
-       }
-    }
-
-  /* Validate arguments.  */
-  if ((! failed) && (! menutitle))
-    {
-      grub_error (GRUB_ERR_MENU, "menuentry is missing title");
-      failed = 1;
-    }
-
-  /* If argument parsing failed, free any allocated resources.  */
-  if (failed)
-    {
-      free_menu_entry_classes (classes_head);
-      grub_free ((void *) menutitle);
-      grub_free ((void *) menusourcecode);
-
-      /* Here we assume that grub_error has been used to specify failure details.  */
-      return grub_errno;
-    }
-
-  /* Add the menu entry at the end of the list.  */
-  while (*last)
-    last = &(*last)->next;
-
-  *last = grub_zalloc (sizeof (**last));
-  if (! *last)
-    {
-      free_menu_entry_classes (classes_head);
-      grub_free ((void *) menutitle);
-      grub_free ((void *) menusourcecode);
-      return grub_errno;
-    }
-
-  (*last)->title = menutitle;
-  (*last)->hotkey = hotkey;
-  (*last)->classes = classes_head;
-  if (users)
-    (*last)->restricted = 1;
-  (*last)->users = users;
-  (*last)->sourcecode = menusourcecode;
-
-  menu->size++;
-
-  return GRUB_ERR_NONE;
-}
-
 static grub_menu_t
 read_config_file (const char *config)
 {
index bcefd81d89584c80c869324ac12183c0f6fae4bb..c1b5cf8cdfe811f0b15f1c865b6cf4adc226329c 100644 (file)
@@ -104,8 +104,8 @@ grub_script_free (struct grub_script *script)
 
   s = script->children;
   while (s) {
-    grub_script_put (s);
     s = s->siblings;
+    grub_script_put (s);
   }
   grub_free (script);
 }