MODULES = menu.c32 vesamenu.c32
TESTFILES =
-COMMONOBJS = menumain.o readconfig.o passwd.o printmsg.o
+COMMONOBJS = menumain.o readconfig.o passwd.o printmsg.o colors.o \
+ background.o refstr.o
all: $(MODULES) $(TESTFILES)
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <consoles.h>
+#include <string.h>
+#include "menu.h"
+
+const char *current_background = NULL;
+
+void set_background(const char *new_background)
+{
+ if (!current_background ||
+ strcmp(current_background, new_background)) {
+ draw_background(new_background);
+ current_background = new_background;
+ }
+}
+
*
* ----------------------------------------------------------------------- */
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
#include <colortbl.h>
#include "menu.h"
* 17 - disabled Disabled menu item
*/
-static const struct color_table default_color_table[] = {
+static const struct color_table default_colors[] = {
{ "screen", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL },
{ "border", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL },
{ "title", "1;36;44", 0xc00090f0, 0x00000000, SHADOW_NORMAL },
{ "disabled", "1;30;44", 0x60cccccc, 0x00000000, SHADOW_NORMAL },
};
-#define NCOLORS (sizeof default_color_table/sizeof(struct color_table))
+#define NCOLORS (sizeof default_colors/sizeof default_colors[0])
const int message_base_color = NCOLORS;
-
+/* Algorithmically generate the msgXX colors */
void set_msg_colors_global(struct color_table *tbl,
unsigned int fg, unsigned int bg,
enum color_table_shadow shadow)
}
}
-struct color_table *default_color_table(const struct color_table *base)
+struct color_table *default_color_table(void)
{
- unsigned int i, ncolors;
+ unsigned int i;
const struct color_table *dp;
struct color_table *cp;
struct color_table *color_table;
static const int pc2ansi[8] = {0, 4, 2, 6, 1, 5, 3, 7};
-
- if (!base)
- base = default_color_table;
+ static char msg_names[6*256];
+ char *mp;
color_table = calloc(NCOLORS+256, sizeof(struct color_table));
- dp = base;
+ dp = default_colors;
cp = color_table;
- if (base == default_color_table)
- ncolors = NCOLORS;
- else
- ncolors = NCOLORS+256;
-
- for (i = 0; i < ncolors; i++) {
- if (cp->ansi)
- free((void *)cp->ansi);
-
+ for (i = 0; i < NCOLORS; i++) {
*cp = *dp;
- cp->ansi = strdup(dp->ansi);
-
+ cp->ansi = refstrdup(dp->ansi);
cp++;
dp++;
}
- if (base == default_color_table) {
- for (i = 0; i < 256; i++) {
- if (!cp->name)
- asprintf((char **)&cp->name, "msg%02x", i);
-
- if (cp->ansi)
- free((void *)cp->ansi);
-
- asprintf((char **)&cp->ansi, "%s3%d;4%d", (i & 8) ? "1;" : "",
- pc2ansi[i & 7], pc2ansi[(i >> 4) & 7]);
-
- cp++;
- }
+ mp = msg_names;
+ for (i = 0; i < 256; i++) {
+ cp->name = mp;
+ mp += sprintf(mp, "msg%02x", i)+1;
- /*** XXX: This needs to move to run_menu() ***/
- console_color_table = color_table;
- console_color_table_size = NCOLORS+256;
+ rsprintf(&cp->ansi, "%s3%d;4%d", (i & 8) ? "1;" : "",
+ pc2ansi[i & 7], pc2ansi[(i >> 4) & 7]);
+ cp++;
+ }
- set_msg_colors_global(color_table, MSG_COLORS_DEF_FG, MSG_COLORS_DEF_BG,
- MSG_COLORS_DEF_SHADOW);
+ /*** XXX: This needs to move to run_menu() ***/
+ console_color_table = color_table;
+ console_color_table_size = NCOLORS+256;
+
+ set_msg_colors_global(color_table, MSG_COLORS_DEF_FG,
+ MSG_COLORS_DEF_BG, MSG_COLORS_DEF_SHADOW);
+
+ return color_table;
+}
+
+struct color_table *copy_color_table(const struct color_table *master)
+{
+ const struct color_table *dp;
+ struct color_table *color_table, *cp;
+ unsigned int i;
+
+ color_table = calloc(NCOLORS+256, sizeof(struct color_table));
+
+ dp = master;
+ cp = color_table;
+
+ for (i = 0; i < NCOLORS+256; i++) {
+ *cp = *dp;
+ cp->ansi = refstr_get(dp->ansi);
+ cp++;
+ dp++;
}
return color_table;
}
+
+
#include <inttypes.h>
#include <unistd.h>
#include <colortbl.h>
+#include <stdbool.h>
+#include "refstr.h"
#ifndef CLK_TCK
# define CLK_TCK sysconf(_SC_CLK_TCK)
struct menu;
+enum menu_action {
+ MA_CMD, /* Execute a command */
+ MA_DISABLED, /* Disabled menu entry */
+ MA_SUBMENU, /* This is a submenu entry */
+ MA_GOTO, /* Go to another menu */
+ MA_GOTO_UNRES, /* Unresolved go to */
+ MA_QUIT, /* Quit to CLI */
+};
+
struct menu_entry {
char *displayname;
char *label;
char *helptext;
char *cmdline;
struct menu *submenu;
+ struct menu_entry *next; /* Linked list of all labels across menus */
+ enum menu_action action;
unsigned char hotkey;
- unsigned char disabled;
};
+static inline bool is_disabled(struct menu_entry *me)
+{
+ return me->action == MA_DISABLED;
+}
+
enum kernel_type {
/* Meta-types for internal use */
KT_NONE,
extern const char * const kernel_types[];
+/* Configurable integer parameters */
+enum parameter_number {
+ P_WIDTH,
+ P_MARGIN,
+ P_PASSWD_MARGIN,
+ P_MENU_ROWS,
+ P_TABMSG_ROW,
+ P_CMDLINE_ROW,
+ P_END_ROW,
+ P_PASSWD_ROW,
+ P_TIMEOUT_ROW,
+ P_HELPMSG_ROW,
+ P_HELPMSGEND_ROW,
+ P_HSHIFT,
+ P_VSHIFT,
+ P_HIDDEN_ROW,
+
+ NPARAMS
+};
+
/* Configurable messages */
enum message_number {
MSG_TITLE,
};
struct menu {
+ struct menu *next; /* Linked list of all menus */
+ const char *label; /* Goto label for this menu */
struct menu *parent;
+ int parent_entry;
struct menu_entry *menu_entries;
struct menu_entry *menu_hotkeys[256];
struct fkey_help fkeyhelp[12];
};
-extern struct menu *root_menu;
+extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
/* 2048 is the current definition inside syslinux */
#define MAX_CMDLINE_LEN 2048
+/* These are global parameters regardless of which menu we're displaying */
+extern int shiftkey;
+extern int hiddenmenu;
+extern long long totaltimeout;
+
void parse_configs(char **argv);
int draw_background(const char *filename);
int mygetkey(clock_t timeout);
int show_message_file(const char *filename, const char *background);
+/* passwd.c */
+int passwd_compare(const char *passwd, const char *entry);
+
+/* colors.c */
#define MSG_COLORS_DEF_FG 0x90ffffff
#define MSG_COLORS_DEF_BG 0x80ffffff
#define MSG_COLORS_DEF_SHADOW SHADOW_NORMAL
-void set_msg_colors_global(unsigned int fg, unsigned int bg,
+void set_msg_colors_global(struct color_table *tbl,
+ unsigned int fg, unsigned int bg,
enum color_table_shadow shadow);
+struct color_table *default_color_table(void);
+struct color_table *copy_color_table(const struct color_table *master);
+extern const int message_base_color;
-/* passwd.c */
-int passwd_compare(const char *passwd, const char *entry);
+/* background.c */
+extern const char *current_background;
+void set_background(const char *new_background);
#endif /* MENU_H */
#include "menu.h"
+/* The symbol "cm" always refers to the current menu across this file... */
+static const struct menu *cm;
+
const struct menu_parameter mparm[NPARAMS] = {
- { "width", 80 },
- { "margin", 10 },
- { "passwordmargin", 3 },
- { "rows", 12 },
- { "tabmsgrow", 18 },
- { "cmdlinerow", 18 },
- { "endrow", -1 },
- { "passwordrow", 11 },
- { "timeoutrow", 20 },
- { "helpmsgrow", 22 },
- { "helpmsgendrow", -1 },
- { "hshift", 0 },
- { "vshift", 0 },
- { "hiddenrow", -2 },
+ [P_WIDTH] = { "width", 0 },
+ [P_MARGIN] = { "margin", 10 },
+ [P_PASSWD_MARGIN] = { "passwordmargin", 3 },
+ [P_MENU_ROWS] = { "rows", 12 },
+ [P_TABMSG_ROW] = { "tabmsgrow", 18 },
+ [P_CMDLINE_ROW] = { "cmdlinerow", 18 },
+ [P_END_ROW] = { "endrow", -1 },
+ [P_PASSWD_ROW] = { "passwordrow", 11 },
+ [P_TIMEOUT_ROW] = { "timeoutrow", 20 },
+ [P_HELPMSG_ROW] = { "helpmsgrow", 22 },
+ [P_HELPMSGEND_ROW] = { "helpmsgendrow", -1 },
+ [P_HSHIFT] = { "hshift", 0 },
+ [P_VSHIFT] = { "vshift", 0 },
+ [P_HIDDEN_ROW] = { "hiddenrow", -2 },
};
-#define WIDTH mparm[0].value
-#define MARGIN mparm[1].value
-#define PASSWD_MARGIN mparm[2].value
-#define MENU_ROWS mparm[3].value
-#define TABMSG_ROW (mparm[4].value+VSHIFT)
-#define CMDLINE_ROW (mparm[5].value+VSHIFT)
-#define END_ROW mparm[6].value
-#define PASSWD_ROW (mparm[7].value+VSHIFT)
-#define TIMEOUT_ROW (mparm[8].value+VSHIFT)
-#define HELPMSG_ROW (mparm[9].value+VSHIFT)
-#define HELPMSGEND_ROW mparm[10].value
-#define HSHIFT mparm[11].value
-#define VSHIFT mparm[12].value
-#define HIDDEN_ROW mparm[13].value
+/* These macros assume "cm" is a pointer to the current menu */
+#define WIDTH (cm->mparm[P_WIDTH])
+#define MARGIN (cm->mparm[P_MARGIN])
+#define PASSWD_MARGIN (cm->mparm[P_PASSWD_MARGIN])
+#define MENU_ROWS (cm->mparm[P_MENU_ROWS])
+#define TABMSG_ROW (cm->mparm[P_TABMSG_ROW]+VSHIFT)
+#define CMDLINE_ROW (cm->mparm[P_CMDLINE_ROW]+VSHIFT)
+#define END_ROW (cm->mparm[P_END_ROW])
+#define PASSWD_ROW (cm->mparm[P_PASSWD_ROW]+VSHIFT)
+#define TIMEOUT_ROW (cm->mparm[P_TIMEOUT_ROW]+VSHIFT)
+#define HELPMSG_ROW (cm->mparm[P_HELPMSG_ROW]+VSHIFT)
+#define HELPMSGEND_ROW (cm->mparm[P_HELPMSGEND_ROW])
+#define HSHIFT (cm->mparm[P_HSHIFT])
+#define VSHIFT (cm->mparm[P_VSHIFT])
+#define HIDDEN_ROW (cm->mparm[P_HIDDEN_ROW])
static char *
pad_line(const char *text, int align, int width)
draw_row(int y, int sel, int top, int sbtop, int sbbot)
{
int i = (y-4-VSHIFT)+top;
- int dis = (i < nentries) && menu_entries[i].disabled;
+ int dis = (i < cm->nentries) && is_disabled(&cm->menu_entries[i]);
printf("\033[%d;%dH\1#1\016x\017%s ",
y, MARGIN+1+HSHIFT,
(i == sel) ? "\1#5" : dis ? "\2#17" : "\1#3");
- if ( i >= nentries ) {
+ if ( i >= cm->nentries ) {
fputs(pad_line("", 0, WIDTH-2*MARGIN-4), stdout);
} else {
- display_entry(&menu_entries[i],
+ display_entry(&cm->menu_entries[i],
(i == sel) ? "\1#5" : dis ? "\2#17" : "\1#3",
(i == sel) ? "\1#6" : dis ? "\2#17" : "\1#4",
WIDTH-2*MARGIN-4);
}
- if ( nentries <= MENU_ROWS ) {
+ if ( cm->nentries <= MENU_ROWS ) {
printf(" \1#1\016x\017");
} else if ( sbtop > 0 ) {
if ( y >= sbtop && y <= sbbot )
putchar('q');
printf("j\017\033[%d;%dH\2#12 %s \033[%d;%dH\2#13",
- PASSWD_ROW, (WIDTH-(strlen(messages[MSG_PASSPROMPT].msg)+2))/2,
- messages[MSG_PASSPROMPT].msg, PASSWD_ROW+1, PASSWD_MARGIN+3);
+ PASSWD_ROW, (WIDTH-(strlen(cm->messages[MSG_PASSPROMPT])+2))/2,
+ cm->messages[MSG_PASSPROMPT], PASSWD_ROW+1, PASSWD_MARGIN+3);
/* Actually allow user to type a password, then compare to the SHA1 */
done = 0;
*p = '\0';
- return (menu_master_passwd && passwd_compare(menu_master_passwd, user_passwd))
+ return (cm->menu_master_passwd &&
+ passwd_compare(cm->menu_master_passwd, user_passwd))
|| (menu_entry && passwd_compare(menu_entry, user_passwd));
}
const char *tabmsg;
int tabmsg_len;
- if ( nentries > MENU_ROWS ) {
- int sblen = MENU_ROWS*MENU_ROWS/nentries;
- sbtop = (MENU_ROWS-sblen+1)*top/(nentries-MENU_ROWS+1);
+ if ( cm->nentries > MENU_ROWS ) {
+ int sblen = MENU_ROWS*MENU_ROWS/cm->nentries;
+ sbtop = (MENU_ROWS-sblen+1)*top/(cm->nentries-MENU_ROWS+1);
sbbot = max(sbtop, sbtop+sblen-1);
sbtop += 4; sbbot += 4; /* Starting row of scrollbar */
printf("k\033[%d;%dH\1#1x\017\1#2 %s \1#1\016x",
VSHIFT+2,
HSHIFT+MARGIN+1,
- pad_line(messages[MSG_TITLE].msg, 1, WIDTH-2*MARGIN-4));
+ pad_line(cm->messages[MSG_TITLE], 1, WIDTH-2*MARGIN-4));
printf("\033[%d;%dH\1#1t", VSHIFT+3, HSHIFT+MARGIN+1);
for ( x = 2+HSHIFT ; x <= (WIDTH-2*MARGIN-1)+HSHIFT ; x++ )
putchar('q');
fputs("j\017", stdout);
- if ( edit_line && allowedit && !menu_master_passwd )
- tabmsg = messages[MSG_TAB].msg;
+ if ( edit_line && cm->allowedit && !cm->menu_master_passwd )
+ tabmsg = cm->messages[MSG_TAB];
else
- tabmsg = messages[MSG_NOTAB].msg;
+ tabmsg = cm->messages[MSG_NOTAB];
tabmsg_len = strlen(tabmsg);
if (fkey == -1)
break;
- if (fkeyhelp[fkey].textname)
- key = show_message_file(fkeyhelp[fkey].textname,
- fkeyhelp[fkey].background);
+ if (cm->fkeyhelp[fkey].textname)
+ key = show_message_file(cm->fkeyhelp[fkey].textname,
+ cm->fkeyhelp[fkey].background);
else
break;
}
printf("\033[%d;%dH\2#14 %s ", row, HSHIFT+1+((WIDTH-nc-8)>>1), buf);
}
+/* Set the background screen, etc. */
+static void
+prepare_screen_for_menu(void)
+{
+ console_color_table = cm->color_table;
+ console_color_table_size = message_base_color+256;
+ set_background(cm->menu_background);
+}
+
static const char *
do_hidden_menu(void)
{
clear_screen();
if ( !setjmp(timeout_jump) ) {
- timeout_left = timeout;
+ timeout_left = cm->timeout;
- while (!timeout || timeout_left) {
+ while (!cm->timeout || timeout_left) {
int tol = timeout_left/CLK_TCK;
- print_timeout_message(tol, HIDDEN_ROW, messages[MSG_AUTOBOOT].msg);
+ print_timeout_message(tol, HIDDEN_ROW, cm->messages[MSG_AUTOBOOT]);
this_timeout = min(timeout_left, CLK_TCK);
key = mygetkey(this_timeout);
}
}
- return menu_entries[defentry].cmdline; /* Default entry */
+ return cm->menu_entries[cm->defentry].cmdline; /* Default entry */
}
static const char *
{
int key;
int done = 0;
- volatile int entry = defentry, prev_entry = -1;
+ volatile int entry = cm->defentry, prev_entry = -1;
int top = 0, prev_top = -1;
int clear = 1, to_clear;
const char *cmdline = NULL;
volatile clock_t key_timeout, timeout_left, this_timeout;
/* Note: for both key_timeout and timeout == 0 means no limit */
- timeout_left = key_timeout = timeout;
+ timeout_left = key_timeout = cm->timeout;
- /* If we're in shiftkey mode, exit immediately unless a shift key is pressed */
+ /* If we're in shiftkey mode, exit immediately unless a shift key
+ is pressed */
if ( shiftkey && !shift_is_held() ) {
- return menu_entries[defentry].cmdline;
+ return cm->menu_entries[cm->defentry].cmdline;
+ } else {
+ shiftkey = 0;
}
+ /* Do this before hiddenmenu handling, so we show the background */
+ prepare_screen_for_menu();
+
/* Handle hiddenmenu */
if ( hiddenmenu ) {
cmdline = do_hidden_menu();
/* Handle both local and global timeout */
if ( setjmp(timeout_jump) ) {
- entry = defentry;
+ entry = cm->defentry;
if ( top < 0 || top < entry-MENU_ROWS+1 )
top = max(0, entry-MENU_ROWS+1);
- else if ( top > entry || top > max(0,nentries-MENU_ROWS) )
- top = min(entry, max(0,nentries-MENU_ROWS));
+ else if ( top > entry || top > max(0, cm->nentries-MENU_ROWS) )
+ top = min(entry, max(0, cm->nentries-MENU_ROWS));
- draw_menu(ontimeout ? -1 : entry, top, 1);
- cmdline = ontimeout ? ontimeout : menu_entries[entry].cmdline;
+ draw_menu(cm->ontimeout ? -1 : entry, top, 1);
+ cmdline = cm->ontimeout ? cm->ontimeout : cm->menu_entries[entry].cmdline;
done = 1;
}
while ( !done ) {
if ( entry <= 0 ) {
entry = 0;
- while ( entry < nentries && menu_entries[entry].disabled ) entry++;
+ while (entry < cm->nentries && is_disabled(&cm->menu_entries[entry]))
+ entry++;
}
- if ( entry >= nentries ) {
- entry = nentries-1;
- while ( entry > 0 && menu_entries[entry].disabled ) entry--;
+ if ( entry >= cm->nentries ) {
+ entry = cm->nentries-1;
+ while (entry > 0 && is_disabled(&cm->menu_entries[entry]))
+ entry--;
}
if ( top < 0 || top < entry-MENU_ROWS+1 )
top = max(0, entry-MENU_ROWS+1);
- else if ( top > entry || top > max(0,nentries-MENU_ROWS) )
- top = min(entry, max(0,nentries-MENU_ROWS));
+ else if ( top > entry || top > max(0, cm->nentries-MENU_ROWS) )
+ top = min(entry, max(0, cm->nentries-MENU_ROWS));
/* Start with a clear screen */
if ( clear ) {
if ( top != prev_top ) {
draw_menu(entry, top, 1);
- display_help(menu_entries[entry].helptext);
+ display_help(cm->menu_entries[entry].helptext);
} else if ( entry != prev_entry ) {
draw_row(prev_entry-top+4+VSHIFT, entry, top, 0, 0);
draw_row(entry-top+4+VSHIFT, entry, top, 0, 0);
- display_help(menu_entries[entry].helptext);
+ display_help(cm->menu_entries[entry].helptext);
}
prev_entry = entry; prev_top = top;
/* Cursor movement cancels timeout */
- if ( entry != defentry )
+ if ( entry != cm->defentry )
key_timeout = 0;
if ( key_timeout ) {
int tol = timeout_left/CLK_TCK;
- print_timeout_message(tol, TIMEOUT_ROW, messages[MSG_AUTOBOOT].msg);
+ print_timeout_message(tol, TIMEOUT_ROW, cm->messages[MSG_AUTOBOOT]);
to_clear = 1;
} else {
to_clear = 0;
case KEY_ENTER:
case KEY_CTRL('J'):
key_timeout = 0; /* Cancels timeout */
- if ( menu_entries[entry].passwd ) {
+ if ( cm->menu_entries[entry].passwd ) {
clear = 1;
- done = ask_passwd(menu_entries[entry].passwd);
+ done = ask_passwd(cm->menu_entries[entry].passwd);
} else {
done = 1;
}
- cmdline = menu_entries[entry].cmdline;
+ cmdline = cm->menu_entries[entry].cmdline;
break;
case KEY_UP:
case KEY_CTRL('P'):
- while ( entry > 0 && entry-- && menu_entries[entry].disabled ) {
+ while (entry > 0 && entry-- && is_disabled(&cm->menu_entries[entry])) {
if ( entry < top )
top -= MENU_ROWS;
}
if ( entry == 0 ) {
- while ( menu_entries[entry].disabled )
+ while (is_disabled(&cm->menu_entries[entry]))
entry++;
}
break;
case KEY_DOWN:
case KEY_CTRL('N'):
- while ( entry < nentries-1 && entry++ && menu_entries[entry].disabled ) {
+ while (entry < cm->nentries-1 && entry++ &&
+ is_disabled(&cm->menu_entries[entry])) {
if ( entry >= top+MENU_ROWS )
top += MENU_ROWS;
}
- if ( entry == nentries-1 ) {
- while ( menu_entries[entry].disabled )
+ if ( entry >= cm->nentries-1 ) {
+ while (is_disabled(&cm->menu_entries[entry]))
entry--;
}
break;
case KEY_CTRL('E'):
case KEY_END:
- entry = nentries - 1;
- top = max(0, nentries-MENU_ROWS);
+ entry = cm->nentries - 1;
+ top = max(0, cm->nentries-MENU_ROWS);
break;
case KEY_F1:
break;
case KEY_TAB:
- if ( allowedit ) {
+ if ( cm->allowedit ) {
int ok = 1;
key_timeout = 0; /* Cancels timeout */
draw_row(entry-top+4+VSHIFT, -1, top, 0, 0);
- if ( menu_master_passwd ) {
+ if ( cm->menu_master_passwd ) {
ok = ask_passwd(NULL);
clear_screen();
draw_menu(-1, top, 0);
}
if ( ok ) {
- cmdline = edit_cmdline(menu_entries[entry].cmdline, top);
+ cmdline = edit_cmdline(cm->menu_entries[entry].cmdline, top);
done = !!cmdline;
clear = 1; /* In case we hit [Esc] and done is null */
} else {
break;
case KEY_CTRL('C'): /* Ctrl-C */
case KEY_ESC: /* Esc */
- if ( allowedit ) {
+ if ( cm->allowedit ) {
done = 1;
clear = 1;
key_timeout = 0;
draw_row(entry-top+4+VSHIFT, -1, top, 0, 0);
- if ( menu_master_passwd )
+ if ( cm->menu_master_passwd )
done = ask_passwd(NULL);
}
break;
default:
if ( key > 0 && key < 0xFF ) {
key &= ~0x20; /* Upper case */
- if ( menu_hotkeys[key] ) {
+ if ( cm->menu_hotkeys[key] ) {
key_timeout = 0;
- entry = menu_hotkeys[key] - menu_entries;
+ entry = cm->menu_hotkeys[key] - cm->menu_entries;
/* Should we commit at this point? */
}
}
execute(const char *cmdline, enum kernel_type type)
{
com32sys_t ireg;
- const char *p, **pp;
+ const char *p, * const *pp;
char *q = __com32.cs_bounce;
const char *kernel, *args;
int menu_main(int argc, char *argv[])
{
const char *cmdline;
+ struct menu *m;
int rows, cols;
int i;
console_prepare();
- install_default_color_table();
if (getscreensize(1, &rows, &cols)) {
/* Unknown screen size? */
rows = 24;
cols = 80;
}
- WIDTH = cols;
parse_configs(argv+1);
+ cm = start_menu;
+
+ /* Some postprocessing for all menus */
+ for (m = menu_list; m; m = m->next) {
+ if (!m->mparm[P_WIDTH])
+ m->mparm[P_WIDTH] = cols;
+
+ /* If anyone has specified negative parameters, consider them
+ relative to the bottom row of the screen. */
+ for (i = 0; i < NPARAMS; i++)
+ if (m->mparm[i] < 0)
+ m->mparm[i] = max(m->mparm[i]+rows, 0);
+ }
- /* If anyone has specified negative parameters, consider them
- relative to the bottom row of the screen. */
- for (i = 0; mparm[i].name; i++)
- if (mparm[i].value < 0)
- mparm[i].value = max(mparm[i].value+rows, 0);
-
- draw_background(menu_background);
-
- if ( !nentries ) {
- fputs("No LABEL entries found in configuration file!\n", stdout);
+ if ( !cm->nentries ) {
+ fputs("Initial menu has no LABEL entries!\n", stdout);
return 1; /* Error! */
}
if ( cmdline ) {
execute(cmdline, KT_NONE);
- if ( onerror )
- execute(onerror, KT_NONE);
+ if ( cm->onerror )
+ execute(cm->onerror, KT_NONE);
} else {
return 0; /* Exit */
}
int show_message_file(const char *filename, const char *background)
{
int rv = KEY_NONE;
+ const char *old_background = NULL;
- if (background && (!menu_background || strcmp(background, menu_background)))
- draw_background(background);
- else
- background = NULL;
+ if (background) {
+ old_background = current_background;
+ set_background(background);
+ }
if ( !(rv = draw_message_file(filename)) )
rv = mygetkey(0); /* Wait for keypress */
- if (background)
- draw_background(menu_background);
+ if (old_background)
+ set_background(old_background);
return rv;
}
#include <alloca.h>
#include <inttypes.h>
#include <colortbl.h>
-#ifdef __COM32__
-# include <com32.h>
-#endif
+#include <com32.h>
+#include <syslinux/config.h>
#include "menu.h"
-int nentries = 0;
-int nhidden = 0;
-int defentry = 0;
-int allowedit = 1; /* Allow edits of the command line */
-int timeout = 0;
+/* Root menu, starting menu, hidden menu, and list of all menus */
+struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
+
+/* These are global parameters regardless of which menu we're displaying */
int shiftkey = 0; /* Only display menu if shift key pressed */
int hiddenmenu = 0;
long long totaltimeout = 0;
-char *ontimeout = NULL;
-char *onerror = NULL;
-
-char *menu_master_passwd = NULL;
-char *menu_background = NULL;
-
-struct fkey_help fkeyhelp[12];
-
-struct menu_entry *menu_entries = NULL;
-struct menu_entry *hide_entries = NULL;
-static int menu_entries_space = 0, hide_entries_space = 0;
-struct menu_entry *menu_hotkeys[256];
+/* Linked list of all entires, hidden or not; used by unlabel() */
+static struct menu_entry *all_entries;
+static struct menu_entry **all_entries_end = &all_entries;
-struct messages messages[MSG_COUNT] = {
+const struct messages messages[MSG_COUNT] = {
[MSG_TITLE] = { "title", "" },
[MSG_AUTOBOOT] = { "autoboot", "Automatic boot in # second{,s}..." },
- [MSG_TAB] = { "tabmsg", "Press [Tab] to edit options", NULL },
+ [MSG_TAB] = { "tabmsg", "Press [Tab] to edit options" },
[MSG_NOTAB] = { "notabmsg", "" },
- [MSG_PASSPROMPT] = { "passprompt", "Password required", NULL },
+ [MSG_PASSPROMPT] = { "passprompt", "Password required" },
};
#define astrdup(x) ({ char *__x = (x); \
__p; })
/* Must match enum kernel_type */
-const char *kernel_types[] = {
+const char * const kernel_types[] = {
"none",
"localboot",
"kernel",
NULL
};
-const char *ipappends[32];
-
-static void
-get_ipappend(void)
+/*
+ * Search the list of all menus for a specific label
+ */
+static struct menu *
+find_menu(const char *label)
{
-#ifdef __COM32__
- static com32sys_t r;
- uint16_t *ipp;
- int i;
- int nipappends;
-
- r.eax.w[0] = 0x000F;
- __intcall(0x22, &r, &r);
-
- nipappends = min(r.ecx.w[0], 32);
- ipp = MK_PTR(r.es, r.ebx.w[0]);
- for ( i = 0 ; i < nipappends ; i++ ) {
- ipappends[i] = MK_PTR(r.es, *ipp++);
+ struct menu *m;
+
+ for (m = menu_list; m; m = m->next) {
+ if (!strcmp(label, m->label))
+ return m;
}
-#else
- ipappends[0] = "ip=foo:bar:baz:quux";
- ipappends[1] = "BOOTIF=01-aa-bb-cc-dd-ee-ff";
-#endif
-}
-
-static const char *
-get_config(void)
-{
-#ifdef __COM32__
- static com32sys_t r;
-
- r.eax.w[0] = 0x000E;
- __intcall(0x22, &r, &r);
- return MK_PTR(r.es, r.ebx.w[0]);
-#else
- return "syslinux.cfg"; /* Dummy default name */
-#endif
+ return NULL;
}
#define MAX_LINE 4096
return my_isspace(*p) ? p : NULL; /* Must be EOL or whitespace */
}
-struct menu *start_menu(struct menu *parent)
+static struct menu *new_menu(struct menu *parent, const char *label)
{
struct menu *m = malloc(sizeof(struct menu));
int i;
memset(m->menu_hotkeys, 0, sizeof m->menu_hotkeys);
m->parent = parent;
+ m->parent_entry = parent->nentries-1; /* Last current entry */
m->nentries = 0;
m->nentries_space = 0;
m->defentry = 0;
- m->color_table = default_color_table(parent->color_table);
+ m->color_table = copy_color_table(parent->color_table);
} else {
/* Root menu */
-
memset(m, 0, sizeof *m);
for (i = 0; i < MSG_COUNT; i++)
- m->messages[i] = messages.defmsg[i];
+ m->messages[i] = strdup(messages[i].defmsg);
for (i = 0; i < NPARAMS; i++)
m->mparm[i] = mparm[i].value;
- m->color_table = default_color_table(NULL);
+ m->allowedit = 1; /* Allow edits of the command line */
+ m->color_table = default_color_table();
}
+ m->label = strdup(label);
+ m->next = menu_list;
+ menu_list = m;
+
return m;
}
};
static void
-record(struct labeldata *ld, char *append)
+record(struct menu *m, struct labeldata *ld, char *append)
{
char ipoptions[256], *ipp;
int i;
struct menu_entry *me;
+ const struct syslinux_ipappend_strings *ipappend;
+
+ if (!ld->label)
+ return; /* Nothing defined */
- if (nentries >= menu_entries_space) {
- if (!menu_entries_space)
- menu_entries_space = 1;
+ /* Hidden entries are recorded on a special "hidden menu" */
+ if (ld->menuhide)
+ m = hide_menu;
+
+ if (m->nentries >= m->nentries_space) {
+ if (!m->nentries_space)
+ m->nentries_space = 1;
else
- menu_entries_space <<= 1;
+ m->nentries_space <<= 1;
- menu_entries = realloc(menu_entries,
- menu_entries_space*sizeof *menu_entries);
+ m->menu_entries = realloc(m->menu_entries, m->nentries_space*
+ sizeof(struct menu_entry));
}
- me = &menu_entries[nentries];
+ me = &m->menu_entries[m->nentries];
if ( ld->label ) {
char *a, *s;
me->passwd = ld->passwd;
me->helptext = ld->helptext;
me->hotkey = 0;
- me->disabled = 0;
+ me->action = MA_CMD;
if ( ld->menuindent ) {
char *n = malloc(ld->menuindent + strlen(me->displayname) + 1);
- memset(n, 32, ld->menuindent);
+ memset(n, ' ', ld->menuindent);
strcpy(n + ld->menuindent, me->displayname);
me->displayname = n;
}
unsigned char *p = (unsigned char *)strchr(ld->menulabel, '^');
if ( p && p[1] ) {
int hotkey = p[1] & ~0x20;
- if ( !menu_hotkeys[hotkey] ) {
+ if ( !m->menu_hotkeys[hotkey] ) {
me->hotkey = hotkey;
}
}
ipp = ipoptions;
*ipp = '\0';
- for ( i = 0 ; i < 32 ; i++ ) {
- if ( (ld->ipappend & (1U << i)) && ipappends[i] )
- ipp += sprintf(ipp, " %s", ipappends[i]);
+ 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 ( ld->menuseparator || ld->menudisabled ) {
me->label = NULL;
me->passwd = NULL;
- me->disabled = 1;
+ me->action = MA_DISABLED;
if ( me->cmdline )
free(me->cmdline);
ld->append = NULL;
}
- if ( !ld->menuhide ) {
- if ( me->hotkey )
- menu_hotkeys[me->hotkey] = me;
-
- if ( ld->menudefault && !ld->menudisabled && !ld->menuseparator )
- defentry = nentries;
-
- nentries++;
- }
- else {
- struct menu_entry *he;
+ if ( me->hotkey )
+ m->menu_hotkeys[me->hotkey] = me;
+
+ if ( ld->menudefault && !ld->menudisabled && !ld->menuseparator )
+ m->defentry = m->nentries;
- if (nhidden >= hide_entries_space) {
- if (!hide_entries_space)
- hide_entries_space = 1;
- else
- hide_entries_space <<= 1;
+ *all_entries_end = me;
+ all_entries_end = &me->next;
- hide_entries = realloc(hide_entries,
- hide_entries_space*sizeof *hide_entries);
- }
- he = &hide_entries[nhidden];
-
- he->displayname = me->displayname;
- he->label = me->label;
- he->cmdline = me->cmdline;
- he->passwd = me->passwd;
-
- me->displayname = NULL;
- me->label = NULL;
- me->cmdline = NULL;
- me->passwd = NULL;
-
- nhidden++;
- }
+ m->nentries++;
}
}
const char *p;
char *q;
struct menu_entry *me;
- int i, pos;
+ int pos;
p = str;
while ( *p && !my_isspace(*p) )
/* p now points to the first byte beyond the kernel name */
pos = p-str;
- for ( i = 0 ; i < nentries ; i++ ) {
- me = &menu_entries[i];
-
- if ( !strncmp(str, me->label, pos) && !me->label[pos] ) {
- /* Found matching label */
- q = malloc(strlen(me->cmdline) + strlen(p) + 1);
- strcpy(q, me->cmdline);
- strcat(q, p);
-
- free(str);
-
- return q;
- }
- }
-
- for ( i = 0 ; i < nhidden ; i++ ) {
- me = &hide_entries[i];
-
+ for ( me = all_entries ; me ; me = me->next ) {
if ( !strncmp(str, me->label, pos) && !me->label[pos] ) {
/* Found matching label */
q = malloc(strlen(me->cmdline) + strlen(p) + 1);
static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
{
- const char **p;
+ const char * const *p;
char *q;
enum kernel_type t = KT_NONE;
return NULL;
}
-static char *is_message_name(char *cmdstr, struct messages **msgptr)
+static char *is_message_name(char *cmdstr, enum message_number *msgnr)
{
char *q;
- int i;
+ enum message_number i;
for (i = 0; i < MSG_COUNT; i++) {
if ((q = looking_at(cmdstr, messages[i].name))) {
- *msgptr = &messages[i];
+ *msgnr = i;
return q;
}
}
return q;
}
+static struct menu *current_menu;
+
static void parse_config_file(FILE *f)
{
char line[MAX_LINE], *p, *ep, ch;
enum kernel_type type;
- struct messages *msgptr;
+ enum message_number msgnr;
int fkeyno;
+ struct menu *m = current_menu;
while ( fgets(line, sizeof line, f) ) {
p = strchr(line, '\r');
} else if ( looking_at(p, "shiftkey") ) {
shiftkey = 1;
} else if ( looking_at(p, "onerror") ) {
- onerror = strdup(skipspace(p+7));
+ m->onerror = strdup(skipspace(p+7));
} else if ( looking_at(p, "master") ) {
p = skipspace(p+6);
if ( looking_at(p, "passwd") ) {
- menu_master_passwd = strdup(skipspace(p+6));
+ /* XXX: need refcount */
+ m->menu_master_passwd = strdup(skipspace(p+6));
}
} else if ( (ep = looking_at(p, "include")) ) {
p = skipspace(ep);
parse_one_config(p);
} else if ( (ep = looking_at(p, "background")) ) {
p = skipspace(ep);
- if (menu_background)
- free(menu_background);
- menu_background = dup_word(&p);
+ /* XXX: need refcount */
+ if (m->menu_background)
+ free(m->menu_background);
+ m->menu_background = dup_word(&p);
} else if ( (ep = looking_at(p, "hidden")) ) {
hiddenmenu = 1;
- } else if ( (ep = is_message_name(p, &msgptr)) ) {
- free(msgptr->msg);
- msgptr->msg = strdup(skipspace(ep));
+ } else if ( (ep = is_message_name(p, &msgnr)) ) {
+ /* XXX: need refcount */
+ if (m->messages[msgnr])
+ free((void *)m->messages[msgnr]);
+ m->messages[msgnr] = strdup(skipspace(ep));
} else if ((ep = looking_at(p, "color")) ||
(ep = looking_at(p, "colour"))) {
int i;
}
}
}
- set_msg_colors_global(fg_mask, bg_mask, shadow);
+ set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow);
} else if ( looking_at(p, "separator") ) {
- record(&ld, append);
+ record(root_menu, &ld, append);
memset(&ld, 0, sizeof(struct labeldata));
ld.label = "";
ld.menuseparator = 1;
- record(&ld, append);
+ record(root_menu, &ld, append);
memset(&ld, 0, sizeof(struct labeldata));
} else if ( looking_at(p, "disable") ||
looking_at(p, "disabled")) {
ld.menuindent = atoi(skipspace(p+6));
} else {
/* Unknown, check for layout parameters */
- struct menu_parameter *pp;
- for ( pp = mparm ; pp->name ; pp++ ) {
- if ( (ep = looking_at(p, pp->name)) ) {
- pp->value = atoi(skipspace(ep));
+ enum parameter_number mp;
+ for (mp = 0; mp < NPARAMS; mp++) {
+ if ( (ep = looking_at(p, mparm[mp].name)) ) {
+ m->mparm[mp] = atoi(skipspace(ep));
break;
}
}
}
} else if ( (ep = is_fkey(p, &fkeyno)) ) {
p = skipspace(ep);
- if (fkeyhelp[fkeyno].textname) {
- free((void *)fkeyhelp[fkeyno].textname);
- fkeyhelp[fkeyno].textname = NULL;
+ if (m->fkeyhelp[fkeyno].textname) {
+ /* XXX: refcount */
+ free((void *)m->fkeyhelp[fkeyno].textname);
+ m->fkeyhelp[fkeyno].textname = NULL;
}
- if (fkeyhelp[fkeyno].background) {
- free((void *)fkeyhelp[fkeyno].background);
- fkeyhelp[fkeyno].background = NULL;
+ if (m->fkeyhelp[fkeyno].background) {
+ /* XXX: refcount */
+ free((void *)m->fkeyhelp[fkeyno].background);
+ m->fkeyhelp[fkeyno].background = NULL;
}
- fkeyhelp[fkeyno].textname = dup_word(&p);
+ /* XXX: refcount */
+ m->fkeyhelp[fkeyno].textname = dup_word(&p);
if (*p) {
p = skipspace(p);
- fkeyhelp[fkeyno].background = dup_word(&p);
+ /* XXX: refcount */
+ m->fkeyhelp[fkeyno].background = dup_word(&p);
}
} else if ( (ep = looking_at(p, "include")) ) {
p = skipspace(ep);
append = a;
} else if ( looking_at(p, "label") ) {
p = skipspace(p+5);
- record(&ld, append);
+ record(root_menu, &ld, append);
ld.label = strdup(p);
ld.kernel = strdup(p);
ld.type = KT_KERNEL;
ld.type = type;
}
} else if ( looking_at(p, "timeout") ) {
- timeout = (atoi(skipspace(p+7))*CLK_TCK+9)/10;
+ m->timeout = (atoi(skipspace(p+7))*CLK_TCK+9)/10;
} else if ( looking_at(p, "totaltimeout") ) {
totaltimeout = (atoll(skipspace(p+13))*CLK_TCK+9)/10;
} else if ( looking_at(p, "ontimeout") ) {
- ontimeout = strdup(skipspace(p+9));
+ m->ontimeout = strdup(skipspace(p+9));
} else if ( looking_at(p, "allowoptions") ) {
- allowedit = atoi(skipspace(p+12));
+ m->allowedit = atoi(skipspace(p+12));
} else if ( looking_at(p, "ipappend") ) {
if (ld.label)
ld.ipappend = atoi(skipspace(p+8));
FILE *f;
if (!strcmp(filename, "~"))
- filename = get_config();
+ filename = syslinux_config_file();
f = fopen(filename, "r");
if ( !f )
return 0;
}
+static void resolve_gotos(void)
+{
+ struct menu_entry *me;
+ struct menu *m;
+
+ for (me = all_entries; me; me = me->next) {
+ if (me->action == MA_GOTO_UNRES) {
+ m = find_menu(me->cmdline);
+ if (m) {
+ me->submenu = m;
+ me->action = MA_GOTO;
+ } else {
+ me->action = MA_DISABLED;
+ }
+ }
+ }
+}
+
void parse_configs(char **argv)
{
const char *filename;
- int i;
+ struct menu *m;
- /* Initialize defaults */
-
- for (i = 0; i < MSG_COUNT; i++) {
- if (messages[i].msg)
- free(messages[i].msg);
- messages[i].msg = strdup(messages[i].defmsg);
- }
+ /* Initialize defaults for the root and hidden menus */
+ hide_menu = new_menu(NULL, ".hidden");
+ root_menu = new_menu(NULL, ".top");
+ start_menu = root_menu;
/* Other initialization */
-
- get_ipappend();
memset(&ld, 0, sizeof(struct labeldata));
/* Actually process the files */
-
+ current_menu = root_menu;
if ( !*argv ) {
parse_one_config("~");
} else {
}
/* On final EOF process the last label statement */
-
- record(&ld, append);
+ record(current_menu, &ld, append);
/* Common postprocessing */
+ resolve_gotos();
- if ( ontimeout )
- ontimeout = unlabel(ontimeout);
- if ( onerror )
- onerror = unlabel(onerror);
+ for (m = menu_list; m; m = m->next) {
+ if ( m->ontimeout )
+ m->ontimeout = unlabel(m->ontimeout);
+ if ( m->onerror )
+ m->onerror = unlabel(m->onerror);
+ }
}
#include <stdlib.h>
#include <string.h>
+#include <stdio.h>
#include "refstr.h"
-const char *refstr_mkn(const char *str, size_t len)
+const char *refstrndup(const char *str, size_t len)
{
char *r;
return r;
}
-const char *refstr_mk(const char *str)
+const char *refstrdup(const char *str)
{
- refstr *r;
+ char *r;
size_t len;
len = strlen(str);
return r;
}
+int vrsprintf(const char **bufp, const char *fmt, va_list ap)
+{
+ va_list ap1;
+ int bytes;
+ char *p;
+
+ va_copy(ap1, ap);
+ bytes = vsnprintf(NULL, 0, fmt, ap1)+1;
+ va_end(ap1);
+
+ p = malloc(bytes+sizeof(unsigned int));
+ if ( !p ) {
+ *bufp = NULL;
+ return -1;
+ }
+
+ *(unsigned int *)p = 1;
+ p += sizeof(unsigned int);
+
+ return vsnprintf(p, bytes, fmt, ap);
+}
+
+int rsprintf(const char **bufp, const char *fmt, ...)
+{
+ int rv;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rv = vrsprintf(bufp, fmt, ap);
+ va_end(ap);
+
+ return rv;
+}
+
void refstr_put(const char *r)
{
- unsigned int *ref = (unsigned int *)r - 1;
+ unsigned int *ref;
- if (!--*ref)
- free(ref);
+ if (r) {
+ ref = (unsigned int *)r - 1;
+
+ if (!--*ref)
+ free(ref);
+ }
}
#define REFSTR_H
#include <stddef.h>
+#include <stdarg.h>
static inline const char *refstr_get(const char *r)
{
return r;
}
-const char *refstr_mk(const char *);
-const char *refstr_mkn(const char *, size_t);
void refstr_put(const char *);
+const char *refstrdup(const char *);
+const char *refstrndup(const char *, size_t);
+int rsprintf(const char **, const char *, ...);
+int vrsprintf(const char **, const char *, va_list);
#endif