From 87e51b1848c449827e1a5a6438a19d2047021816 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 19 Feb 2008 15:33:36 -0800 Subject: [PATCH] simple menu: first cut at working submenus With this edit, the submenu system seems to have minimal functionality. --- com32/menu/menu.h | 1 + com32/menu/menumain.c | 39 +++++++- com32/menu/readconfig.c | 249 ++++++++++++++++++++++++++++++++---------------- 3 files changed, 206 insertions(+), 83 deletions(-) diff --git a/com32/menu/menu.h b/com32/menu/menu.h index 7f452a1..62b2f46 100644 --- a/com32/menu/menu.h +++ b/com32/menu/menu.h @@ -35,6 +35,7 @@ struct menu; enum menu_action { + MA_NONE, /* Undefined value */ MA_CMD, /* Execute a command */ MA_DISABLED, /* Disabled menu entry */ MA_SUBMENU, /* This is a submenu entry */ diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c index f512e63..84fe2b0 100644 --- a/com32/menu/menumain.c +++ b/com32/menu/menumain.c @@ -95,6 +95,13 @@ display_entry(const struct menu_entry *entry, const char *attrib, const char *hotattrib, int width) { const char *p = entry->displayname; + bool is_submenu = (entry->action == MA_SUBMENU || entry->action == MA_GOTO); + + if (!p) + p = ""; + + if (is_submenu) + width -= 2; while ( width ) { if ( *p ) { @@ -115,6 +122,9 @@ display_entry(const struct menu_entry *entry, const char *attrib, width--; } } + + if (is_submenu) + fputs(" >", stdout); } static void @@ -743,6 +753,8 @@ run_menu(void) /* Clear and redraw whole screen */ /* Enable ASCII on G0 and DEC VT on G1; do it in this order to avoid confusing the Linux console */ + if (clear >= 2) + prepare_screen_for_menu(); clear_screen(); clear = 0; prev_entry = prev_top = -1; @@ -809,7 +821,30 @@ run_menu(void) } else { done = 1; } - cmdline = cm->menu_entries[entry].cmdline; + cmdline = NULL; + if (done) { + switch (cm->menu_entries[entry].action) { + case MA_CMD: + cmdline = cm->menu_entries[entry].cmdline; + break; + case MA_SUBMENU: + case MA_GOTO: + done = 0; + clear = 2; + cm = cm->menu_entries[entry].submenu; + entry = top = 0; + break; + case MA_QUIT: + /* Quit menu system */ + done = 1; + clear = 1; + draw_row(entry-top+4+VSHIFT, -1, top, 0, 0); + break; + default: + done = 0; + break; + } + } break; case KEY_UP: @@ -1024,7 +1059,6 @@ int menu_main(int argc, char *argv[]) } parse_configs(argv+1); - cm = start_menu; /* Some postprocessing for all menus */ for (m = menu_list; m; m = m->next) { @@ -1043,6 +1077,7 @@ int menu_main(int argc, char *argv[]) return 1; /* Error! */ } + cm = start_menu; for(;;) { cmdline = run_menu(); diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c index 88b450f..4c2ecbd 100644 --- a/com32/menu/readconfig.c +++ b/com32/menu/readconfig.c @@ -113,7 +113,9 @@ looking_at(char *line, const char *kwd) return my_isspace(*p) ? p : NULL; /* Must be EOL or whitespace */ } -static struct menu *new_menu(struct menu *parent, const char *label) +static struct menu * new_menu(struct menu *parent, + struct menu_entry *parent_entry, + const char *label) { struct menu *m = calloc(1, sizeof(struct menu)); int i; @@ -123,11 +125,16 @@ static struct menu *new_menu(struct menu *parent, const char *label) if (parent) { /* Submenu */ m->parent = parent; - m->parent_entry = &parent->menu_entries[parent->nentries-1]; + m->parent_entry = parent_entry; + parent_entry->action = MA_SUBMENU; + parent_entry->submenu = m; for (i = 0; i < MSG_COUNT; i++) m->messages[i] = refstr_get(parent->messages[i]); + refstr_put(m->messages[MSG_TITLE]); + m->messages[MSG_TITLE] = refstr_get(empty_string); + memcpy(m->mparm, parent->mparm, sizeof m->mparm); m->allowedit = parent->allowedit; @@ -175,21 +182,27 @@ struct labeldata { unsigned int menuseparator; unsigned int menudisabled; unsigned int menuindent; + enum menu_action action; }; +/* Menu currently being parsed */ +static struct menu *current_menu; + static void -record(struct menu *m, struct labeldata *ld, const char *append) +clear_label_data(struct labeldata *ld) { - int i; - struct menu_entry *me; - const struct syslinux_ipappend_strings *ipappend; + refstr_put(ld->label); + refstr_put(ld->kernel); + refstr_put(ld->append); + refstr_put(ld->menulabel); + refstr_put(ld->passwd); - if (!ld->label) - return; /* Nothing defined */ + memset(ld, 0, sizeof *ld); +} - /* Hidden entries are recorded on a special "hidden menu" */ - if (ld->menuhide) - m = hide_menu; +static struct menu_entry *new_entry(struct menu *m) +{ + struct menu_entry *me; if (m->nentries >= m->nentries_space) { if (!m->nentries_space) @@ -200,19 +213,60 @@ record(struct menu *m, struct labeldata *ld, const char *append) m->menu_entries = realloc(m->menu_entries, m->nentries_space* sizeof(struct menu_entry)); } - me = &m->menu_entries[m->nentries]; + + me = &m->menu_entries[m->nentries++]; + memset(me, 0, sizeof *me); + + *all_entries_end = me; + all_entries_end = &me->next; + + return me; +} + +static void consider_for_hotkey(struct menu *m, struct menu_entry *me) +{ + unsigned char *p = + (unsigned char *)strchr(me->displayname, '^'); + + if (me->action != MA_DISABLED) { + if ( p && p[1] ) { + int hotkey = p[1] & ~0x20; + if ( !m->menu_hotkeys[hotkey] ) { + me->hotkey = hotkey; + m->menu_hotkeys[hotkey] = me; + } + } + } +} + +static void +record(struct menu *m, struct labeldata *ld, const char *append) +{ + int i; + struct menu_entry *me; + const struct syslinux_ipappend_strings *ipappend; + + if (!ld->label) + return; /* Nothing defined */ + + /* Hidden entries are recorded on a special "hidden menu" */ + if (ld->menuhide) + m = hide_menu; if ( ld->label ) { char ipoptions[4096], *ipp; const char *a; char *s; - me->displayname = ld->menulabel ? ld->menulabel : refstr_get(ld->label); - me->label = ld->label; - me->passwd = ld->passwd; + me = new_entry(m); + + me->displayname = ld->menulabel + ? refstr_get(ld->menulabel) : refstr_get(ld->label); + me->label = refstr_get(ld->label); + me->passwd = refstr_get(ld->passwd); me->helptext = ld->helptext; - me->hotkey = 0; - me->action = MA_CMD; + me->hotkey = 0; + me->action = ld->action ? ld->action : MA_CMD; if ( ld->menuindent ) { const char *dn; @@ -222,74 +276,83 @@ record(struct menu *m, struct labeldata *ld, const char *append) me->displayname = dn; } - if ( ld->menulabel ) { - unsigned char *p = (unsigned char *)strchr(ld->menulabel, '^'); - if ( p && p[1] ) { - int hotkey = p[1] & ~0x20; - if ( !m->menu_hotkeys[hotkey] ) { - me->hotkey = hotkey; - } - } - } - - ipp = ipoptions; - *ipp = '\0'; - ipappend = syslinux_ipappend_strings(); - for (i = 0; i < ipappend->count; i++) { - if ( (ld->ipappend & (1U << i)) && ipappend->ptr[i] ) - ipp += sprintf(ipp, " %s", ipappend->ptr[i]); - } - - a = ld->append; - if ( !a ) - a = append; - if ( !a || (a[0] == '-' && !a[1]) ) - a = ""; - s = a[0] ? " " : ""; - if (ld->type == KT_KERNEL) { - rsprintf(&me->cmdline, "%s%s%s%s", - ld->kernel, s, a, ipoptions); - } else { - rsprintf(&me->cmdline, ".%s %s%s%s%s", - kernel_types[ld->type], ld->kernel, s, a, ipoptions); - } - refstr_put(ld->kernel); - ld->kernel = NULL; - refstr_put(ld->append); - ld->append = NULL; - if ( ld->menuseparator ) { refstr_put(me->displayname); me->displayname = refstr_get(empty_string); } if ( ld->menuseparator || ld->menudisabled ) { + me->action = MA_DISABLED; + refstr_put(me->label); me->label = NULL; + refstr_put(me->passwd); me->passwd = NULL; - me->action = MA_DISABLED; - - refstr_put(me->cmdline); - me->cmdline = NULL; } - ld->label = NULL; - ld->passwd = NULL; + if (ld->menulabel) + consider_for_hotkey(m, me); + + switch (me->action) { + case MA_CMD: + ipp = ipoptions; + *ipp = '\0'; + + if (ld->ipappend) { + ipappend = syslinux_ipappend_strings(); + for (i = 0; i < ipappend->count; i++) { + if ( (ld->ipappend & (1U << i)) && ipappend->ptr[i] ) + ipp += sprintf(ipp, " %s", ipappend->ptr[i]); + } + } + + a = ld->append; + if ( !a ) + a = append; + if ( !a || (a[0] == '-' && !a[1]) ) + a = ""; + s = a[0] ? " " : ""; + if (ld->type == KT_KERNEL) { + rsprintf(&me->cmdline, "%s%s%s%s", + ld->kernel, s, a, ipoptions); + } else { + rsprintf(&me->cmdline, ".%s %s%s%s%s", + kernel_types[ld->type], ld->kernel, s, a, ipoptions); + } + break; - if ( me->hotkey ) - m->menu_hotkeys[me->hotkey] = me; - - if ( ld->menudefault && !ld->menudisabled && !ld->menuseparator ) - m->defentry = m->nentries; + case MA_GOTO_UNRES: + me->cmdline = refstr_get(ld->kernel); + break; - *all_entries_end = me; - all_entries_end = &me->next; + default: + break; + } - m->nentries++; + if ( ld->menudefault && me->action == MA_CMD ) + m->defentry = m->nentries-1; } + + clear_label_data(ld); } -static const char * -unlabel(const char *str) +static struct menu *begin_submenu(const char *tag) +{ + struct menu_entry *me; + + if (!tag[0]) + tag = NULL; + + me = new_entry(current_menu); + me->displayname = refstrdup(tag); + return new_menu(current_menu, me, tag); +} + +static struct menu *end_submenu(void) +{ + return current_menu->parent ? current_menu->parent : current_menu; +} + +static const char *unlabel(const char *str) { /* Convert a CLI-style command line to an executable command line */ const char *p; @@ -477,8 +540,6 @@ static char *is_fkey(char *cmdstr, int *fkeyno) return q; } -static struct menu *current_menu; - static void parse_config_file(FILE *f) { char line[MAX_LINE], *p, *ep, ch; @@ -507,14 +568,25 @@ static void parse_config_file(FILE *f) } else if ( m->parent_entry ) { refstr_put(m->parent_entry->displayname); m->parent_entry->displayname = refstrdup(skipspace(p+5)); + consider_for_hotkey(m, m->parent_entry); + if (!m->messages[MSG_TITLE][0]) { + /* MENU LABEL -> MENU TITLE on submenu */ + refstr_put(m->messages[MSG_TITLE]); + m->messages[MSG_TITLE] = refstr_get(m->parent_entry->displayname); + } } } else if ( looking_at(p, "default") ) { ld.menudefault = 1; } else if ( looking_at(p, "hide") ) { ld.menuhide = 1; } else if ( looking_at(p, "passwd") ) { - refstr_put(ld.passwd); - ld.passwd = refstrdup(skipspace(p+6)); + if ( ld.label ) { + refstr_put(ld.passwd); + ld.passwd = refstrdup(skipspace(p+6)); + } else if ( m->parent_entry ) { + refstr_put(m->parent_entry->passwd); + m->parent_entry->passwd = refstrdup(skipspace(p+6)); + } } else if ( looking_at(p, "shiftkey") ) { shiftkey = 1; } else if ( looking_at(p, "onerror") ) { @@ -625,17 +697,32 @@ static void parse_config_file(FILE *f) } set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow); } else if ( looking_at(p, "separator") ) { - record(root_menu, &ld, append); - memset(&ld, 0, sizeof(struct labeldata)); - ld.label = ""; + record(m, &ld, append); + ld.label = refstr_get(empty_string); ld.menuseparator = 1; - record(root_menu, &ld, append); - memset(&ld, 0, sizeof(struct labeldata)); + record(m, &ld, append); } else if ( looking_at(p, "disable") || looking_at(p, "disabled")) { ld.menudisabled = 1; } else if ( looking_at(p, "indent") ) { ld.menuindent = atoi(skipspace(p+6)); + } else if ( looking_at(p, "begin") ) { + record(m, &ld, append); + m = current_menu = begin_submenu(skipspace(p+5)); + } else if ( looking_at(p, "end") ) { + record(m, &ld, append); + m = current_menu = end_submenu(); + } else if ( looking_at(p, "quit") ) { + if (ld.label) + ld.action = MA_QUIT; + } else if ( looking_at(p, "goto") ) { + if (ld.label) { + ld.action = MA_GOTO_UNRES; + refstr_put(ld.kernel); + ld.kernel = refstrdup(skipspace(p+4)); + } + } else if ( looking_at(p, "start") ) { + start_menu = m; } else { /* Unknown, check for layout parameters */ enum parameter_number mp; @@ -707,7 +794,7 @@ static void parse_config_file(FILE *f) } } else if ( looking_at(p, "label") ) { p = skipspace(p+5); - record(root_menu, &ld, append); + record(m, &ld, append); ld.label = refstrdup(p); ld.kernel = refstrdup(p); ld.type = KT_KERNEL; @@ -786,8 +873,8 @@ void parse_configs(char **argv) empty_string = refstrdup(""); /* Initialize defaults for the root and hidden menus */ - hide_menu = new_menu(NULL, ".hidden"); - root_menu = new_menu(NULL, ".top"); + hide_menu = new_menu(NULL, NULL, ".hidden"); + root_menu = new_menu(NULL, NULL, ".top"); start_menu = root_menu; /* Other initialization */ -- 2.7.4