2008-10-13 Colin D Bennett Support classes for menu entries via the '--class CLASSNAME' argument to the menuentry command. Argument list parsing functionality by Vesa Jääskeläinen . * include/grub/menu.h (grub_menu_entry_class): New struct type. (grub_menu_entry): Added 'classes' field. * include/grub/normal.h (grub_normal_menu_addentry): Changed signature to take a list of arguments instead of just a title. * include/grub/script.h (grub_script_cmd_menuentry): Replaced title with arglist. (grub_script_create_cmdmenu): Changed signature to take an arglist instead of just a single arg (title). * normal/execute.c (grub_script_execute_menuentry): Parse arguments to the 'menuentry' script command. * normal/main.c (free_menu_entry_classes): New function. (grub_normal_menu_addentry): Take and process a list of arguments; handle '--class CLASSNAME' arguments and store the list of class names in the menu entry. * normal/parser.y (menuentry): Take a list of arguments. * normal/script.c (grub_script_create_cmdmenu): Take an argument list, store it in the command. === modified file 'include/grub/menu.h' --- include/grub/menu.h 2008-08-30 19:20:13 +0000 +++ include/grub/menu.h 2008-10-13 16:15:06 +0000 @@ -20,12 +20,24 @@ #ifndef GRUB_MENU_HEADER #define GRUB_MENU_HEADER 1 +struct grub_menu_entry_class +{ + char *name; + struct grub_menu_entry_class *next; +}; + /* The menu entry. */ struct grub_menu_entry { /* The title name. */ const char *title; + /* The classes associated with the menu entry: + used to choose an icon or other style attributes. + This is a dummy head node for the linked list, so for an entry E, + E.classes->next is the first class if it is not NULL. */ + struct grub_menu_entry_class *classes; + /* The commands associated with this menu entry. */ struct grub_script *commands; === modified file 'include/grub/normal.h' --- include/grub/normal.h 2008-10-03 14:26:41 +0000 +++ include/grub/normal.h 2008-10-13 16:15:06 +0000 @@ -141,7 +141,7 @@ char *grub_normal_do_completion (char *buf, int *restore, void (*hook) (const char *item, grub_completion_type_t type, int count)); grub_err_t grub_normal_print_device_info (const char *name); -grub_err_t grub_normal_menu_addentry (const char *title, +grub_err_t grub_normal_menu_addentry (int argc, const char **args, struct grub_script *script, const char *sourcecode); char *grub_env_write_color_normal (struct grub_env_var *var, const char *val); === modified file 'include/grub/script.h' --- include/grub/script.h 2008-05-30 02:26:56 +0000 +++ include/grub/script.h 2008-10-13 16:15:06 +0000 @@ -113,8 +113,8 @@ { struct grub_script_cmd cmd; - /* The title of the menu entry. */ - struct grub_script_arg *title; + /* The arguments for this menu entry. */ + struct grub_script_arglist *arglist; /* The sourcecode the entry will be generated from. */ const char *sourcecode; @@ -204,7 +204,7 @@ struct grub_script_cmd * grub_script_create_cmdmenu (struct grub_parser_param *state, - struct grub_script_arg *title, + struct grub_script_arglist *arglist, char *sourcecode, int options); === modified file 'normal/execute.c' --- normal/execute.c 2008-01-15 15:32:17 +0000 +++ normal/execute.c 2008-10-13 16:15:06 +0000 @@ -216,29 +216,50 @@ grub_script_execute_menuentry (struct grub_script_cmd *cmd) { struct grub_script_cmd_menuentry *cmd_menuentry; - char *title; + struct grub_script_arglist *arglist; struct grub_script *script; + char **args = 0; + int argcount = 0; + int i = 0; cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd; - /* The title can contain variables, parse them and generate a string - from it. */ - title = grub_script_execute_argument_to_string (cmd_menuentry->title); - if (! title) - return grub_errno; + 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; + } + } /* Parse the menu entry *again*. */ script = grub_script_parse ((char *) cmd_menuentry->sourcecode, 0); - if (! script) + /* Add new menu entry. */ + if (script) { - grub_free (title); - return grub_errno; + grub_normal_menu_addentry (argcount, args, + script, cmd_menuentry->sourcecode); } - /* XXX: When this fails, the memory should be freed? */ - return grub_normal_menu_addentry (title, script, - cmd_menuentry->sourcecode); + /* Free arguments. */ + for (i = 0; i < argcount; i++) + grub_free (args[i]); + grub_free (args); + + return grub_errno; } === modified file 'normal/main.c' --- normal/main.c 2008-08-30 19:20:13 +0000 +++ normal/main.c 2008-10-13 16:15:06 +0000 @@ -148,14 +148,41 @@ grub_env_unset_data_slot ("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; + } +} + grub_err_t -grub_normal_menu_addentry (const char *title, struct grub_script *script, +grub_normal_menu_addentry (int argc, const char **args, struct grub_script *script, const char *sourcecode) { - const char *menutitle; + 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; + + /* Allocate dummy head node for class list. */ + classes_head = grub_malloc (sizeof (struct grub_menu_entry_class)); + if (! classes_head) + return grub_errno; + classes_head->name = 0; + classes_head->next = 0; + classes_tail = classes_head; menu = grub_env_get_data_slot("menu"); if (! menu) @@ -167,10 +194,81 @@ if (! menusourcecode) return grub_errno; - menutitle = grub_strdup (title); - if (! menutitle) - { + /* Parse menu arguments. */ + for (i = 0; i < argc; i++) + { + /* Capture arguments. */ + if (grub_strncmp ("--", args[i], 2) == 0) + { + 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_malloc (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; + new_class->next = 0; + /* Link the tail to it, and make it the new tail. */ + classes_tail->next = new_class; + classes_tail = new_class; + continue; + } + 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; } @@ -181,6 +279,7 @@ *last = grub_malloc (sizeof (**last)); if (! *last) { + free_menu_entry_classes (classes_head); grub_free ((void *) menutitle); grub_free ((void *) menusourcecode); return grub_errno; @@ -188,6 +287,7 @@ (*last)->commands = script; (*last)->title = menutitle; + (*last)->classes = classes_head; (*last)->next = 0; (*last)->sourcecode = menusourcecode; === modified file 'normal/parser.y' --- normal/parser.y 2008-07-02 00:00:37 +0000 +++ normal/parser.y 2008-10-13 16:15:06 +0000 @@ -204,7 +204,7 @@ ; /* A menu entry. Carefully save the memory that is allocated. */ -menuentry: "menuentry" argument +menuentry: "menuentry" arguments { grub_script_lexer_ref (state->lexerstate); } newlines '{' === modified file 'normal/script.c' --- normal/script.c 2007-12-30 08:52:06 +0000 +++ normal/script.c 2008-10-13 16:15:06 +0000 @@ -206,7 +206,7 @@ The options for this entry are passed in OPTIONS. */ struct grub_script_cmd * grub_script_create_cmdmenu (struct grub_parser_param *state, - struct grub_script_arg *title, + struct grub_script_arglist *arglist, char *sourcecode, int options) { @@ -232,9 +232,9 @@ cmd->cmd.next = 0; /* XXX: Check if this memory is properly freed. */ cmd->sourcecode = sourcecode; - cmd->title = title; + cmd->arglist = arglist; cmd->options = options; - + return (struct grub_script_cmd *) cmd; }