Index: bootcd/isolinux/syslinux-6.03/com32/menu/Makefile
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/Makefile	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/Makefile	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,48 @@
+## -----------------------------------------------------------------------
+##
+##   Copyright 2001-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.
+##
+## -----------------------------------------------------------------------
+
+##
+## Simple menu system
+##
+
+VPATH = $(SRC)
+include $(MAKEDIR)/elf.mk
+
+LNXLIBS	   = $(objdir)/com32/libutil/libutil_lnx.a
+
+MODULES	  = menu.c32 vesamenu.c32
+TESTFILES =
+
+COMMONOBJS = menumain.o readconfig.o passwd.o drain.o \
+		printmsg.o colors.o background.o refstr.o
+
+all: $(MODULES) $(TESTFILES)
+
+menu.elf : menu.o $(COMMONOBJS) $(C_LIBS)
+	$(LD) $(LDFLAGS) -o $@ $^
+
+vesamenu.elf : vesamenu.o $(COMMONOBJS) $(C_LIBS)
+	$(LD) $(LDFLAGS) -o $@ $^
+
+tidy dist:
+	rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+
+clean: tidy
+	rm -f *.lnx
+
+spotless: clean
+	rm -f *.lss *.c32 *.com
+	rm -f *~ \#*
+
+install:
+
+-include .*.d
Index: bootcd/isolinux/syslinux-6.03/com32/menu/background.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/background.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/background.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,26 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   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 || !new_background ||
+	strcmp(current_background, new_background)) {
+	draw_background(new_background);
+	current_background = new_background;
+    }
+}
Index: bootcd/isolinux/syslinux-6.03/com32/menu/colors.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/colors.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/colors.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,184 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <colortbl.h>
+#include "menu.h"
+
+/*
+ * The color/attribute indexes (\1#X, \2#XX, \3#XXX) are as follows
+ *
+ * 00 - screen		Rest of the screen
+ * 01 - border		Border area
+ * 02 - title		Title bar
+ * 03 - unsel		Unselected menu item
+ * 04 - hotkey		Unselected hotkey
+ * 05 - sel		Selection bar
+ * 06 - hotsel		Selected hotkey
+ * 07 - scrollbar	Scroll bar
+ * 08 - tabmsg		Press [Tab] message
+ * 09 - cmdmark		Command line marker
+ * 10 - cmdline		Command line
+ * 11 - pwdborder	Password box border
+ * 12 - pwdheader	Password box header
+ * 13 - pwdentry	Password box contents
+ * 14 - timeout_msg	Timeout message
+ * 15 - timeout		Timeout counter
+ * 16 - help		Current entry help text
+ * 17 - disabled        Disabled menu item
+ */
+
+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},
+    {"unsel", "37;44", 0x90ffffff, 0x00000000, SHADOW_NORMAL},
+    {"hotkey", "1;37;44", 0xffffffff, 0x00000000, SHADOW_NORMAL},
+    {"sel", "7;37;40", 0xe0000000, 0x20ff8000, SHADOW_ALL},
+    {"hotsel", "1;7;37;40", 0xe0400000, 0x20ff8000, SHADOW_ALL},
+    {"scrollbar", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL},
+    {"tabmsg", "31;40", 0x90ffff00, 0x00000000, SHADOW_NORMAL},
+    {"cmdmark", "1;36;40", 0xc000ffff, 0x00000000, SHADOW_NORMAL},
+    {"cmdline", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL},
+    {"pwdborder", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL},
+    {"pwdheader", "31;47", 0x80ff8080, 0x20ffffff, SHADOW_NORMAL},
+    {"pwdentry", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL},
+    {"timeout_msg", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL},
+    {"timeout", "1;37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL},
+    {"help", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL},
+    {"disabled", "1;30;44", 0x60cccccc, 0x00000000, SHADOW_NORMAL},
+};
+
+#define NCOLORS (sizeof default_colors/sizeof default_colors[0])
+const int message_base_color = NCOLORS;
+const int menu_color_table_size = NCOLORS + 256;
+
+/* 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 *cp = tbl + message_base_color;
+    unsigned int i;
+    unsigned int fga, bga;
+    unsigned int fgh, bgh;
+    unsigned int fg_idx, bg_idx;
+    unsigned int fg_rgb, bg_rgb;
+
+    static const unsigned int pc2rgb[8] =
+	{ 0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00,
+	0xffffff
+    };
+
+    /* Converting PC RGBI to sensible RGBA values is an "interesting"
+       proposition.  This algorithm may need plenty of tweaking. */
+
+    fga = fg & 0xff000000;
+    fgh = ((fg >> 1) & 0xff000000) | 0x80000000;
+
+    bga = bg & 0xff000000;
+    bgh = ((bg >> 1) & 0xff000000) | 0x80000000;
+
+    for (i = 0; i < 256; i++) {
+	fg_idx = i & 15;
+	bg_idx = i >> 4;
+
+	fg_rgb = pc2rgb[fg_idx & 7] & fg;
+	bg_rgb = pc2rgb[bg_idx & 7] & bg;
+
+	if (fg_idx & 8) {
+	    /* High intensity foreground */
+	    fg_rgb |= fgh;
+	} else {
+	    fg_rgb |= fga;
+	}
+
+	if (bg_idx == 0) {
+	    /* Default black background, assume transparent */
+	    bg_rgb = 0;
+	} else if (bg_idx & 8) {
+	    bg_rgb |= bgh;
+	} else {
+	    bg_rgb |= bga;
+	}
+
+	cp->argb_fg = fg_rgb;
+	cp->argb_bg = bg_rgb;
+	cp->shadow = shadow;
+	cp++;
+    }
+}
+
+struct color_table *default_color_table(void)
+{
+    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 };
+    static char msg_names[6 * 256];
+    char *mp;
+
+    color_table = calloc(NCOLORS + 256, sizeof(struct color_table));
+
+    dp = default_colors;
+    cp = color_table;
+
+    for (i = 0; i < NCOLORS; i++) {
+	*cp = *dp;
+	cp->ansi = refstrdup(dp->ansi);
+	cp++;
+	dp++;
+    }
+
+    mp = msg_names;
+    for (i = 0; i < 256; i++) {
+	cp->name = mp;
+	mp += sprintf(mp, "msg%02x", i) + 1;
+
+	rsprintf(&cp->ansi, "%s3%d;4%d", (i & 8) ? "1;" : "",
+		 pc2ansi[i & 7], pc2ansi[(i >> 4) & 7]);
+	cp++;
+    }
+
+  /*** 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;
+}
Index: bootcd/isolinux/syslinux-6.03/com32/menu/drain.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/drain.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/drain.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/cpu.h>
+
+void drain_keyboard(void)
+{
+    /* Prevent "ghost typing" and keyboard buffer snooping */
+    volatile char junk;
+    int rv;
+
+    do {
+	rv = read(0, (char *)&junk, 1);
+    } while (rv > 0);
+
+    junk = 0;
+
+    cli();
+    *(volatile uint8_t *)0x419 = 0;	/* Alt-XXX keyboard area */
+    *(volatile uint16_t *)0x41a = 0x1e;	/* Keyboard buffer empty */
+    *(volatile uint16_t *)0x41c = 0x1e;
+    memset((void *)0x41e, 0, 32);	/* Clear the actual keyboard buffer */
+    sti();
+}
Index: bootcd/isolinux/syslinux-6.03/com32/menu/menu.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/menu.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/menu.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,44 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * menu.c
+ *
+ * Simple menu system which displays a list and allows the user to select
+ * a command line and/or edit it.
+ */
+
+#include <consoles.h>
+#include "menu.h"
+
+int draw_background(const char *arg)
+{
+    /* Nothing to do... */
+    (void)arg;
+    return 0;
+}
+
+void set_resolution(int x, int y)
+{
+    (void)x;
+    (void)y;
+}
+
+void local_cursor_enable(bool enabled)
+{
+    (void)enabled;
+}
+
+void start_console(void)
+{
+    console_ansi_raw();
+}
Index: bootcd/isolinux/syslinux-6.03/com32/menu/menumain.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/menumain.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/menumain.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,1166 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2014 Intel Corporation; author: H. Peter Anvin
+ *
+ *   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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * menumain.c
+ *
+ * Simple menu system which displays a list and allows the user to select
+ * a command line and/or edit it.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <consoles.h>
+#include <getkey.h>
+#include <minmax.h>
+#include <setjmp.h>
+#include <limits.h>
+#include <com32.h>
+#include <core.h>
+#include <syslinux/adv.h>
+#include <syslinux/boot.h>
+
+#include "menu.h"
+
+/* The symbol "cm" always refers to the current menu across this file... */
+static struct menu *cm;
+
+const struct menu_parameter mparm[NPARAMS] = {
+    [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},
+};
+
+/* 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)
+{
+    static char buffer[MAX_CMDLINE_LEN];
+    int n, p;
+
+    if (width >= (int)sizeof buffer)
+	return NULL;		/* Can't do it */
+
+    n = strlen(text);
+    if (n >= width)
+	n = width;
+
+    memset(buffer, ' ', width);
+    buffer[width] = 0;
+    p = ((width - n) * align) >> 1;
+    memcpy(buffer + p, text, n);
+
+    return buffer;
+}
+
+/* Display an entry, with possible hotkey highlight.  Assumes
+   that the current attribute is the non-hotkey one, and will
+   guarantee that as an exit condition as well. */
+static void
+display_entry(const struct menu_entry *entry, const char *attrib,
+	      const char *hotattrib, int width)
+{
+    const char *p = entry->displayname;
+    char marker;
+
+    if (!p)
+	p = "";
+
+    switch (entry->action) {
+    case MA_SUBMENU:
+	marker = '>';
+	break;
+    case MA_EXIT:
+	marker = '<';
+	break;
+    default:
+	marker = 0;
+	break;
+    }
+
+    if (marker)
+	width -= 2;
+
+    while (width) {
+	if (*p) {
+	    if (*p == '^') {
+		p++;
+		if (*p && ((unsigned char)*p & ~0x20) == entry->hotkey) {
+		    fputs(hotattrib, stdout);
+		    putchar(*p++);
+		    fputs(attrib, stdout);
+		    width--;
+		}
+	    } else {
+		putchar(*p++);
+		width--;
+	    }
+	} else {
+	    putchar(' ');
+	    width--;
+	}
+    }
+
+    if (marker) {
+	putchar(' ');
+	putchar(marker);
+    }
+}
+
+static void draw_row(int y, int sel, int top, int sbtop, int sbbot)
+{
+    int i = (y - 4 - VSHIFT) + top;
+    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 >= cm->nentries) {
+	fputs(pad_line("", 0, WIDTH - 2 * MARGIN - 4), stdout);
+    } else {
+	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 (cm->nentries <= MENU_ROWS) {
+	printf(" \1#1\016x\017");
+    } else if (sbtop > 0) {
+	if (y >= sbtop && y <= sbbot)
+	    printf(" \1#7\016a\017");
+	else
+	    printf(" \1#1\016x\017");
+    } else {
+	putchar(' ');		/* Don't modify the scrollbar */
+    }
+}
+
+static jmp_buf timeout_jump;
+
+int mygetkey(clock_t timeout)
+{
+    clock_t t0, t;
+    clock_t tto, to;
+    int key;
+
+    if (!totaltimeout)
+	return get_key(stdin, timeout);
+
+    for (;;) {
+	tto = min(totaltimeout, INT_MAX);
+	to = timeout ? min(tto, timeout) : tto;
+
+	t0 = times(NULL);
+	key = get_key(stdin, to);
+	t = times(NULL) - t0;
+
+	if (totaltimeout <= t)
+	    longjmp(timeout_jump, 1);
+
+	totaltimeout -= t;
+
+	if (key != KEY_NONE)
+	    return key;
+
+	if (timeout) {
+	    if (timeout <= t)
+		return KEY_NONE;
+
+	    timeout -= t;
+	}
+    }
+}
+
+static int ask_passwd(const char *menu_entry)
+{
+    char user_passwd[WIDTH], *p;
+    int done;
+    int key;
+    int x;
+    int rv;
+
+    printf("\033[%d;%dH\2#11\016l", PASSWD_ROW, PASSWD_MARGIN + 1);
+    for (x = 2; x <= WIDTH - 2 * PASSWD_MARGIN - 1; x++)
+	putchar('q');
+
+    printf("k\033[%d;%dHx", PASSWD_ROW + 1, PASSWD_MARGIN + 1);
+    for (x = 2; x <= WIDTH - 2 * PASSWD_MARGIN - 1; x++)
+	putchar(' ');
+
+    printf("x\033[%d;%dHm", PASSWD_ROW + 2, PASSWD_MARGIN + 1);
+    for (x = 2; x <= WIDTH - 2 * PASSWD_MARGIN - 1; x++)
+	putchar('q');
+
+    printf("j\017\033[%d;%dH\2#12 %s \033[%d;%dH\2#13",
+	   PASSWD_ROW, (WIDTH - (strlen(cm->messages[MSG_PASSPROMPT]) + 2)) / 2,
+	   cm->messages[MSG_PASSPROMPT], PASSWD_ROW + 1, PASSWD_MARGIN + 3);
+
+    drain_keyboard();
+
+    /* Actually allow user to type a password, then compare to the SHA1 */
+    done = 0;
+    p = user_passwd;
+
+    while (!done) {
+	key = mygetkey(0);
+
+	switch (key) {
+	case KEY_ENTER:
+	case KEY_CTRL('J'):
+	    done = 1;
+	    break;
+
+	case KEY_ESC:
+	case KEY_CTRL('C'):
+	    p = user_passwd;	/* No password entered */
+	    done = 1;
+	    break;
+
+	case KEY_BACKSPACE:
+	case KEY_DEL:
+	case KEY_DELETE:
+	    if (p > user_passwd) {
+		printf("\b \b");
+		p--;
+	    }
+	    break;
+
+	case KEY_CTRL('U'):
+	    while (p > user_passwd) {
+		printf("\b \b");
+		p--;
+	    }
+	    break;
+
+	default:
+	    if (key >= ' ' && key <= 0xFF &&
+		(p - user_passwd) < WIDTH - 2 * PASSWD_MARGIN - 5) {
+		*p++ = key;
+		putchar('*');
+	    }
+	    break;
+	}
+    }
+
+    if (p == user_passwd)
+	return 0;		/* No password entered */
+
+    *p = '\0';
+
+    rv = (cm->menu_master_passwd &&
+	  passwd_compare(cm->menu_master_passwd, user_passwd))
+	|| (menu_entry && passwd_compare(menu_entry, user_passwd));
+
+    /* Clean up */
+    memset(user_passwd, 0, WIDTH);
+    drain_keyboard();
+
+    return rv;
+}
+
+static void draw_menu(int sel, int top, int edit_line)
+{
+    int x, y;
+    int sbtop = 0, sbbot = 0;
+    const char *tabmsg;
+    int tabmsg_len;
+
+    if (cm->nentries > MENU_ROWS) {
+	int sblen = max(MENU_ROWS * MENU_ROWS / cm->nentries, 1);
+	sbtop = (MENU_ROWS - sblen + 1) * top / (cm->nentries - MENU_ROWS + 1);
+	sbbot = sbtop + sblen - 1;
+	sbtop += 4;
+	sbbot += 4;		/* Starting row of scrollbar */
+    }
+
+    printf("\033[%d;%dH\1#1\016l", VSHIFT + 1, HSHIFT + MARGIN + 1);
+    for (x = 2 + HSHIFT; x <= (WIDTH - 2 * MARGIN - 1) + HSHIFT; x++)
+	putchar('q');
+
+    printf("k\033[%d;%dH\1#1x\017\1#2 %s \1#1\016x",
+	   VSHIFT + 2,
+	   HSHIFT + MARGIN + 1, pad_line(cm->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("u\017", stdout);
+
+    for (y = 4 + VSHIFT; y < 4 + VSHIFT + MENU_ROWS; y++)
+	draw_row(y, sel, top, sbtop, sbbot);
+
+    printf("\033[%d;%dH\1#1\016m", y, HSHIFT + MARGIN + 1);
+    for (x = 2 + HSHIFT; x <= (WIDTH - 2 * MARGIN - 1) + HSHIFT; x++)
+	putchar('q');
+    fputs("j\017", stdout);
+
+    if (edit_line && cm->allowedit && !cm->menu_master_passwd)
+	tabmsg = cm->messages[MSG_TAB];
+    else
+	tabmsg = cm->messages[MSG_NOTAB];
+
+    tabmsg_len = strlen(tabmsg);
+
+    printf("\1#8\033[%d;%dH%s",
+	   TABMSG_ROW, 1 + HSHIFT + ((WIDTH - tabmsg_len) >> 1), tabmsg);
+    printf("\1#0\033[%d;1H", END_ROW);
+}
+
+static void clear_screen(void)
+{
+    fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout);
+}
+
+static void display_help(const char *text)
+{
+    int row;
+    const char *p;
+
+    if (!text) {
+	text = "";
+	printf("\1#0\033[%d;1H", HELPMSG_ROW);
+    } else {
+	printf("\2#16\033[%d;1H", HELPMSG_ROW);
+    }
+
+    for (p = text, row = HELPMSG_ROW; *p && row <= HELPMSGEND_ROW; p++) {
+	switch (*p) {
+	case '\r':
+	case '\f':
+	case '\v':
+	case '\033':
+	    break;
+	case '\n':
+	    printf("\033[K\033[%d;1H", ++row);
+	    break;
+	default:
+	    putchar(*p);
+	}
+    }
+
+    fputs("\033[K", stdout);
+
+    while (row <= HELPMSGEND_ROW) {
+	printf("\033[K\033[%d;1H", ++row);
+    }
+}
+
+static void show_fkey(int key)
+{
+    int fkey;
+
+    while (1) {
+	switch (key) {
+	case KEY_F1:
+	    fkey = 0;
+	    break;
+	case KEY_F2:
+	    fkey = 1;
+	    break;
+	case KEY_F3:
+	    fkey = 2;
+	    break;
+	case KEY_F4:
+	    fkey = 3;
+	    break;
+	case KEY_F5:
+	    fkey = 4;
+	    break;
+	case KEY_F6:
+	    fkey = 5;
+	    break;
+	case KEY_F7:
+	    fkey = 6;
+	    break;
+	case KEY_F8:
+	    fkey = 7;
+	    break;
+	case KEY_F9:
+	    fkey = 8;
+	    break;
+	case KEY_F10:
+	    fkey = 9;
+	    break;
+	case KEY_F11:
+	    fkey = 10;
+	    break;
+	case KEY_F12:
+	    fkey = 11;
+	    break;
+	default:
+	    fkey = -1;
+	    break;
+	}
+
+	if (fkey == -1)
+	    break;
+
+	if (cm->fkeyhelp[fkey].textname)
+	    key = show_message_file(cm->fkeyhelp[fkey].textname,
+				    cm->fkeyhelp[fkey].background);
+	else
+	    break;
+    }
+}
+
+static const char *edit_cmdline(const char *input, int top)
+{
+    static char cmdline[MAX_CMDLINE_LEN];
+    int key, len, prev_len, cursor;
+    int redraw = 1;		/* We enter with the menu already drawn */
+
+    strlcpy(cmdline, input, MAX_CMDLINE_LEN);
+    cmdline[MAX_CMDLINE_LEN - 1] = '\0';
+
+    len = cursor = strlen(cmdline);
+    prev_len = 0;
+
+    for (;;) {
+	if (redraw > 1) {
+	    /* 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 */
+	    clear_screen();
+	    draw_menu(-1, top, 1);
+	    prev_len = 0;
+	}
+
+	if (redraw > 0) {
+	    /* Redraw the command line */
+	    printf("\033[?25l\033[%d;1H\1#9> \2#10%s",
+		   CMDLINE_ROW, pad_line(cmdline, 0, max(len, prev_len)));
+	    printf("\2#10\033[%d;3H%s\033[?25h",
+		   CMDLINE_ROW, pad_line(cmdline, 0, cursor));
+	    prev_len = len;
+	    redraw = 0;
+	}
+
+	key = mygetkey(0);
+
+	switch (key) {
+	case KEY_CTRL('L'):
+	    redraw = 2;
+	    break;
+
+	case KEY_ENTER:
+	case KEY_CTRL('J'):
+	    return cmdline;
+
+	case KEY_ESC:
+	case KEY_CTRL('C'):
+	    return NULL;
+
+	case KEY_BACKSPACE:
+	case KEY_DEL:
+	    if (cursor) {
+		memmove(cmdline + cursor - 1, cmdline + cursor,
+			len - cursor + 1);
+		len--;
+		cursor--;
+		redraw = 1;
+	    }
+	    break;
+
+	case KEY_CTRL('D'):
+	case KEY_DELETE:
+	    if (cursor < len) {
+		memmove(cmdline + cursor, cmdline + cursor + 1, len - cursor);
+		len--;
+		redraw = 1;
+	    }
+	    break;
+
+	case KEY_CTRL('U'):
+	    if (len) {
+		len = cursor = 0;
+		cmdline[len] = '\0';
+		redraw = 1;
+	    }
+	    break;
+
+	case KEY_CTRL('W'):
+	    if (cursor) {
+		int prevcursor = cursor;
+
+		while (cursor && my_isspace(cmdline[cursor - 1]))
+		    cursor--;
+
+		while (cursor && !my_isspace(cmdline[cursor - 1]))
+		    cursor--;
+
+		memmove(cmdline + cursor, cmdline + prevcursor,
+			len - prevcursor + 1);
+		len -= (prevcursor - cursor);
+		redraw = 1;
+	    }
+	    break;
+
+	case KEY_LEFT:
+	case KEY_CTRL('B'):
+	    if (cursor) {
+		cursor--;
+		redraw = 1;
+	    }
+	    break;
+
+	case KEY_RIGHT:
+	case KEY_CTRL('F'):
+	    if (cursor < len) {
+		putchar(cmdline[cursor++]);
+	    }
+	    break;
+
+	case KEY_CTRL('K'):
+	    if (cursor < len) {
+		cmdline[len = cursor] = '\0';
+		redraw = 1;
+	    }
+	    break;
+
+	case KEY_HOME:
+	case KEY_CTRL('A'):
+	    if (cursor) {
+		cursor = 0;
+		redraw = 1;
+	    }
+	    break;
+
+	case KEY_END:
+	case KEY_CTRL('E'):
+	    if (cursor != len) {
+		cursor = len;
+		redraw = 1;
+	    }
+	    break;
+
+	case KEY_F1:
+	case KEY_F2:
+	case KEY_F3:
+	case KEY_F4:
+	case KEY_F5:
+	case KEY_F6:
+	case KEY_F7:
+	case KEY_F8:
+	case KEY_F9:
+	case KEY_F10:
+	case KEY_F11:
+	case KEY_F12:
+	    show_fkey(key);
+	    redraw = 1;
+	    break;
+
+	default:
+	    if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) {
+		if (cursor == len) {
+		    cmdline[len] = key;
+		    cmdline[++len] = '\0';
+		    cursor++;
+		    putchar(key);
+		    prev_len++;
+		} else {
+		    memmove(cmdline + cursor + 1, cmdline + cursor,
+			    len - cursor + 1);
+		    cmdline[cursor++] = key;
+		    len++;
+		    redraw = 1;
+		}
+	    }
+	    break;
+	}
+    }
+}
+
+static void print_timeout_message(int tol, int row, const char *msg)
+{
+    static int last_msg_len = 0;
+    char buf[256];
+    int nc = 0, nnc, padc;
+    const char *tp = msg;
+    char tc;
+    char *tq = buf;
+
+    while ((size_t) (tq - buf) < (sizeof buf - 16) && (tc = *tp)) {
+	tp++;
+	if (tc == '#') {
+	    nnc = sprintf(tq, "\2#15%d\2#14", tol);
+	    tq += nnc;
+	    nc += nnc - 8;	/* 8 formatting characters */
+	} else if (tc == '{') {
+	    /* Deal with {singular[,dual],plural} constructs */
+	    struct {
+		const char *s, *e;
+	    } tx[3];
+	    const char *tpp;
+	    int n = 0;
+
+	    memset(tx, 0, sizeof tx);
+
+	    tx[0].s = tp;
+
+	    while (*tp && *tp != '}') {
+		if (*tp == ',' && n < 2) {
+		    tx[n].e = tp;
+		    n++;
+		    tx[n].s = tp + 1;
+		}
+		tp++;
+	    }
+	    tx[n].e = tp;
+
+	    if (*tp)
+		tp++;		/* Skip final bracket */
+
+	    if (!tx[1].s)
+		tx[1] = tx[0];
+	    if (!tx[2].s)
+		tx[2] = tx[1];
+
+	    /* Now [0] is singular, [1] is dual, and [2] is plural,
+	       even if the user only specified some of them. */
+
+	    switch (tol) {
+	    case 1:
+		n = 0;
+		break;
+	    case 2:
+		n = 1;
+		break;
+	    default:
+		n = 2;
+		break;
+	    }
+
+	    for (tpp = tx[n].s; tpp < tx[n].e; tpp++) {
+		if ((size_t) (tq - buf) < (sizeof buf)) {
+		    *tq++ = *tpp;
+		    nc++;
+		}
+	    }
+	} else {
+	    *tq++ = tc;
+	    nc++;
+	}
+    }
+    *tq = '\0';
+
+    if (nc >= last_msg_len) {
+	padc = 0;
+    } else {
+	padc = (last_msg_len - nc + 1) >> 1;
+    }
+
+    printf("\033[%d;%dH\2#14%*s%s%*s", row,
+	   HSHIFT + 1 + ((WIDTH - nc) >> 1) - padc,
+	   padc, "", buf, padc, "");
+
+    last_msg_len = nc;
+}
+
+/* Set the background screen, etc. */
+static void prepare_screen_for_menu(void)
+{
+    console_color_table = cm->color_table;
+    console_color_table_size = menu_color_table_size;
+    set_background(cm->menu_background);
+}
+
+static const char *do_hidden_menu(void)
+{
+    int key;
+    int timeout_left, this_timeout;
+
+    clear_screen();
+
+    if (!setjmp(timeout_jump)) {
+	timeout_left = cm->timeout;
+
+	while (!cm->timeout || timeout_left) {
+	    int tol = timeout_left / CLK_TCK;
+
+	    print_timeout_message(tol, HIDDEN_ROW, cm->messages[MSG_AUTOBOOT]);
+
+	    this_timeout = min(timeout_left, CLK_TCK);
+	    key = mygetkey(this_timeout);
+
+	    if (key != KEY_NONE) {
+		/* Clear the message from the screen */
+		print_timeout_message(0, HIDDEN_ROW, "");
+		return hide_key[key]; /* NULL if no MENU HIDEKEY in effect */
+	    }
+
+	    timeout_left -= this_timeout;
+	}
+    }
+
+    /* Clear the message from the screen */
+    print_timeout_message(0, HIDDEN_ROW, "");
+
+    if (cm->ontimeout)
+	return cm->ontimeout;
+    else
+	return cm->menu_entries[cm->defentry]->cmdline; /* Default entry */
+}
+
+static const char *run_menu(void)
+{
+    int key;
+    int done = 0;
+    volatile int entry = cm->curentry;
+    int prev_entry = -1;
+    volatile int top = cm->curtop;
+    int prev_top = -1;
+    int clear = 1, to_clear;
+    const char *cmdline = NULL;
+    volatile clock_t key_timeout, timeout_left, this_timeout;
+    const struct menu_entry *me;
+    bool hotkey = false;
+
+    /* Note: for both key_timeout and timeout == 0 means no limit */
+    timeout_left = key_timeout = cm->timeout;
+
+    /* If we're in shiftkey mode, exit immediately unless a shift key
+       is pressed */
+    if (shiftkey && !shift_is_held()) {
+	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();
+	if (cmdline)
+	    return cmdline;
+
+	/* Otherwise display the menu now; the timeout has already been
+	   cancelled, since the user pressed a key. */
+	hiddenmenu = 0;
+	key_timeout = 0;
+    }
+
+    /* Handle both local and global timeout */
+    if (setjmp(timeout_jump)) {
+	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, cm->nentries - MENU_ROWS))
+	    top = min(entry, max(0, cm->nentries - MENU_ROWS));
+
+	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 < cm->nentries && is_disabled(cm->menu_entries[entry]))
+		entry++;
+	}
+	if (entry >= cm->nentries - 1) {
+	    entry = cm->nentries - 1;
+	    while (entry > 0 && is_disabled(cm->menu_entries[entry]))
+		entry--;
+	}
+
+	me = cm->menu_entries[entry];
+
+	if (top < 0 || top < entry - MENU_ROWS + 1)
+	    top = max(0, entry - MENU_ROWS + 1);
+	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) {
+	    /* 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;
+	}
+
+	if (top != prev_top) {
+	    draw_menu(entry, top, 1);
+	    display_help(me->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(me->helptext);
+	}
+
+	prev_entry = entry;
+	prev_top = top;
+	cm->curentry = entry;
+	cm->curtop = top;
+
+	/* Cursor movement cancels timeout */
+	if (entry != cm->defentry)
+	    key_timeout = 0;
+
+	if (key_timeout) {
+	    int tol = timeout_left / CLK_TCK;
+	    print_timeout_message(tol, TIMEOUT_ROW, cm->messages[MSG_AUTOBOOT]);
+	    to_clear = 1;
+	} else {
+	    to_clear = 0;
+	}
+
+	if (hotkey && me->immediate) {
+	    /* If the hotkey was flagged immediate, simulate pressing ENTER */
+	    key = KEY_ENTER;
+	} else {
+	    this_timeout = min(min(key_timeout, timeout_left),
+			       (clock_t) CLK_TCK);
+	    key = mygetkey(this_timeout);
+
+	    if (key != KEY_NONE) {
+		timeout_left = key_timeout;
+		if (to_clear)
+		    printf("\033[%d;1H\1#0\033[K", TIMEOUT_ROW);
+	    }
+	}
+
+	hotkey = false;
+
+	switch (key) {
+	case KEY_NONE:		/* Timeout */
+	    /* This is somewhat hacky, but this at least lets the user
+	       know what's going on, and still deals with "phantom inputs"
+	       e.g. on serial ports.
+
+	       Warning: a timeout will boot the default entry without any
+	       password! */
+	    if (key_timeout) {
+		if (timeout_left <= this_timeout)
+		    longjmp(timeout_jump, 1);
+
+		timeout_left -= this_timeout;
+	    }
+	    break;
+
+	case KEY_CTRL('L'):
+	    clear = 1;
+	    break;
+
+	case KEY_ENTER:
+	case KEY_CTRL('J'):
+	    key_timeout = 0;	/* Cancels timeout */
+	    if (me->passwd) {
+		clear = 1;
+		done = ask_passwd(me->passwd);
+	    } else {
+		done = 1;
+	    }
+	    cmdline = NULL;
+	    if (done) {
+		switch (me->action) {
+		case MA_CMD:
+		    cmdline = me->cmdline;
+		    break;
+		case MA_SUBMENU:
+		case MA_GOTO:
+		case MA_EXIT:
+		    done = 0;
+		    clear = 2;
+		    cm = me->submenu;
+		    entry = cm->curentry;
+		    top = cm->curtop;
+		    break;
+		case MA_QUIT:
+		    /* Quit menu system */
+		    done = 1;
+		    clear = 1;
+		    draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0);
+		    break;
+		case MA_HELP:
+		    key = show_message_file(me->cmdline, me->background);
+		    /* If the exit was an F-key, display that help screen */
+		    show_fkey(key);
+		    done = 0;
+		    clear = 1;
+		    break;
+		default:
+		    done = 0;
+		    break;
+		}
+	    }
+	    if (done && !me->passwd) {
+		/* Only save a new default if we don't have a password... */
+		if (me->save && me->label) {
+		    syslinux_setadv(ADV_MENUSAVE, strlen(me->label), me->label);
+		    syslinux_adv_write();
+		}
+	    }
+	    break;
+
+	case KEY_UP:
+	case KEY_CTRL('P'):
+	    while (entry > 0) {
+		entry--;
+		if (entry < top)
+		    top -= MENU_ROWS;
+		if (!is_disabled(cm->menu_entries[entry]))
+		    break;
+	    }
+	    break;
+
+	case KEY_DOWN:
+	case KEY_CTRL('N'):
+	    while (entry < cm->nentries - 1) {
+		entry++;
+		if (entry >= top + MENU_ROWS)
+		    top += MENU_ROWS;
+		if (!is_disabled(cm->menu_entries[entry]))
+		    break;
+	    }
+	    break;
+
+	case KEY_PGUP:
+	case KEY_LEFT:
+	case KEY_CTRL('B'):
+	case '<':
+	    entry -= MENU_ROWS;
+	    top -= MENU_ROWS;
+	    while (entry > 0 && is_disabled(cm->menu_entries[entry])) {
+		entry--;
+		if (entry < top)
+		    top -= MENU_ROWS;
+	    }
+	    break;
+
+	case KEY_PGDN:
+	case KEY_RIGHT:
+	case KEY_CTRL('F'):
+	case '>':
+	case ' ':
+	    entry += MENU_ROWS;
+	    top += MENU_ROWS;
+	    while (entry < cm->nentries - 1
+		   && is_disabled(cm->menu_entries[entry])) {
+		entry++;
+		if (entry >= top + MENU_ROWS)
+		    top += MENU_ROWS;
+	    }
+	    break;
+
+	case '-':
+	    while (entry > 0) {
+		entry--;
+		top--;
+		if (!is_disabled(cm->menu_entries[entry]))
+		    break;
+	    }
+	    break;
+
+	case '+':
+	    while (entry < cm->nentries - 1) {
+		entry++;
+		top++;
+		if (!is_disabled(cm->menu_entries[entry]))
+		    break;
+	    }
+	    break;
+
+	case KEY_CTRL('A'):
+	case KEY_HOME:
+	    top = entry = 0;
+	    break;
+
+	case KEY_CTRL('E'):
+	case KEY_END:
+	    entry = cm->nentries - 1;
+	    top = max(0, cm->nentries - MENU_ROWS);
+	    break;
+
+	case KEY_F1:
+	case KEY_F2:
+	case KEY_F3:
+	case KEY_F4:
+	case KEY_F5:
+	case KEY_F6:
+	case KEY_F7:
+	case KEY_F8:
+	case KEY_F9:
+	case KEY_F10:
+	case KEY_F11:
+	case KEY_F12:
+	    show_fkey(key);
+	    clear = 1;
+	    break;
+
+	case KEY_TAB:
+	    if (cm->allowedit && me->action == MA_CMD) {
+		int ok = 1;
+
+		key_timeout = 0;	/* Cancels timeout */
+		draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0);
+
+		if (cm->menu_master_passwd) {
+		    ok = ask_passwd(NULL);
+		    clear_screen();
+		    draw_menu(-1, top, 0);
+		} else {
+		    /* Erase [Tab] message and help text */
+		    printf("\033[%d;1H\1#0\033[K", TABMSG_ROW);
+		    display_help(NULL);
+		}
+
+		if (ok) {
+		    cmdline = edit_cmdline(me->cmdline, top);
+		    done = !!cmdline;
+		    clear = 1;	/* In case we hit [Esc] and done is null */
+		} else {
+		    draw_row(entry - top + 4 + VSHIFT, entry, top, 0, 0);
+		}
+	    }
+	    break;
+	case KEY_CTRL('C'):	/* Ctrl-C */
+	case KEY_ESC:		/* Esc */
+	    if (cm->parent) {
+		cm = cm->parent;
+		clear = 2;
+		entry = cm->curentry;
+		top = cm->curtop;
+	    } else if (cm->allowedit) {
+		done = 1;
+		clear = 1;
+		key_timeout = 0;
+
+		draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0);
+
+		if (cm->menu_master_passwd)
+		    done = ask_passwd(NULL);
+	    }
+	    break;
+	default:
+	    if (key > 0 && key < 0xFF) {
+		key &= ~0x20;	/* Upper case */
+		if (cm->menu_hotkeys[key]) {
+		    key_timeout = 0;
+		    entry = cm->menu_hotkeys[key]->entry;
+		    /* Should we commit at this point? */
+		    hotkey = true;
+		}
+	    }
+	    break;
+	}
+    }
+
+    printf("\033[?25h");	/* Show cursor */
+
+    /* Return the label name so localboot and ipappend work */
+    return cmdline;
+}
+
+int main(int argc, char *argv[])
+{
+    const char *cmdline;
+    struct menu *m;
+    int rows, cols;
+    int i;
+
+    (void)argc;
+
+    parse_configs(argv + 1);
+
+    /*
+     * We don't start the console until we have parsed the configuration
+     * file, since the configuration file might impact the console
+     * configuration, e.g. MENU RESOLUTION.
+     */
+    start_console();
+    if (getscreensize(1, &rows, &cols)) {
+	/* Unknown screen size? */
+	rows = 24;
+	cols = 80;
+    }
+
+    /* 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);
+    }
+
+    cm = start_menu;
+
+    if (!cm->nentries) {
+	fputs("Initial menu has no LABEL entries!\n", stdout);
+	return 1;		/* Error! */
+    }
+
+    for (;;) {
+	local_cursor_enable(true);
+	cmdline = run_menu();
+
+	if (clearmenu)
+	    clear_screen();
+
+	local_cursor_enable(false);
+	printf("\033[?25h\033[%d;1H\033[0m", END_ROW);
+
+	if (cmdline) {
+	    uint32_t type = parse_image_type(cmdline);
+
+	    execute(cmdline, type, false);
+	    if (cm->onerror) {
+		type = parse_image_type(cm->onerror);
+		execute(cm->onerror, type, true);
+	    }
+	} else {
+	    return 0;		/* Exit */
+	}
+    }
+}
Index: bootcd/isolinux/syslinux-6.03/com32/menu/passwd.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/passwd.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/passwd.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,96 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-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 <string.h>
+#include <xcrypt.h>
+#include <sha1.h>
+#include <base64.h>
+
+#include "menu.h"
+
+static int passwd_compare_sha1(const char *passwd, const char *entry)
+{
+    struct {
+	SHA1_CTX ctx;
+	unsigned char sha1[20], pwdsha1[20];
+    } d;
+    const char *p;
+    int rv;
+
+    SHA1Init(&d.ctx);
+
+    if ((p = strchr(passwd + 3, '$'))) {
+	SHA1Update(&d.ctx, (void *)passwd + 3, p - (passwd + 3));
+	p++;
+    } else {
+	p = passwd + 3;		/* Assume no salt */
+    }
+
+    SHA1Update(&d.ctx, (void *)entry, strlen(entry));
+    SHA1Final(d.sha1, &d.ctx);
+
+    memset(d.pwdsha1, 0, 20);
+    unbase64(d.pwdsha1, 20, p);
+
+    rv = !memcmp(d.sha1, d.pwdsha1, 20);
+
+    memset(&d, 0, sizeof d);
+    return rv;
+}
+
+static int passwd_compare_md5(const char *passwd, const char *entry)
+{
+    const char *crypted = crypt_md5(entry, passwd + 3);
+    int len = strlen(crypted);
+
+    return !strncmp(crypted, passwd, len) &&
+	(passwd[len] == '\0' || passwd[len] == '$');
+}
+
+static int passwd_compare_sha256(const char *passwd, const char *entry)
+{
+    const char *crypted = sha256_crypt(entry, passwd + 3);
+    int len = strlen(crypted);
+
+    return !strncmp(crypted, passwd, len) &&
+	(passwd[len] == '\0' || passwd[len] == '$');
+}
+
+static int passwd_compare_sha512(const char *passwd, const char *entry)
+{
+    const char *crypted = sha512_crypt(entry, passwd + 3);
+    int len = strlen(crypted);
+
+    return !strncmp(crypted, passwd, len) &&
+	(passwd[len] == '\0' || passwd[len] == '$');
+}
+
+int passwd_compare(const char *passwd, const char *entry)
+{
+    if (passwd[0] != '$' || !passwd[1] || passwd[2] != '$') {
+	/* Plaintext passwd, yuck! */
+	return !strcmp(entry, passwd);
+    } else {
+	switch (passwd[1]) {
+	case '1':
+	    return passwd_compare_md5(passwd, entry);
+	case '4':
+	    return passwd_compare_sha1(passwd, entry);
+	case '5':
+	    return passwd_compare_sha256(passwd, entry);
+	case '6':
+	    return passwd_compare_sha512(passwd, entry);
+	default:
+	    return 0;		/* Unknown encryption algorithm -> false */
+	}
+    }
+}
Index: bootcd/isolinux/syslinux-6.03/com32/menu/printmsg.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/printmsg.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/printmsg.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,119 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-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 <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <consoles.h>
+#include <getkey.h>
+#include <minmax.h>
+#include <setjmp.h>
+#include <limits.h>
+#include <sha1.h>
+#include <base64.h>
+#include <colortbl.h>
+#ifdef __COM32__
+#include <com32.h>
+#endif
+
+#include "menu.h"
+
+static int draw_message_file(const char *filename)
+{
+    FILE *f;
+    int ch;
+    enum msgname_state {
+	st_init,		/* Base state */
+	st_si_1,		/* <SI> digit 1 */
+	st_si_2,		/* <SI> digit 2 */
+	st_skipline,		/* Skip until NL */
+    } state = st_init;
+    int eof = 0;
+    int attr = 0;
+
+    f = fopen(filename, "r");
+    if (!f)
+	return -1;
+
+    /* Clear screen, hide cursor, default attribute */
+    printf("\033e\033%%@\033)0\033(B\3#%03d\033[?25l\033[2J\033[H",
+	   message_base_color + 0x07);
+
+    while (!eof && (ch = getc(f)) != EOF) {
+	switch (state) {
+	case st_init:
+	    switch (ch) {
+	    case '\f':
+		fputs("\033[2J\033[H", stdout);
+		break;
+	    case 15:		/* SI */
+		state = st_si_1;
+		break;
+	    case 24:
+		state = st_skipline;
+		break;
+	    case 26:
+		eof = 1;
+		break;
+	    case '\a':
+	    case '\n':
+	    case '\r':
+		putchar(ch);
+		break;
+	    default:
+		if (ch >= 32)
+		    putchar(ch);
+		break;
+	    }
+	    break;
+
+	case st_si_1:
+	    attr = hexval(ch) << 4;
+	    state = st_si_2;
+	    break;
+
+	case st_si_2:
+	    attr |= hexval(ch);
+	    printf("\3#%03d", attr + message_base_color);
+	    state = st_init;
+	    break;
+
+	case st_skipline:
+	    if (ch == '\n')
+		state = st_init;
+	    break;
+	}
+    }
+
+    fclose(f);
+    return 0;
+}
+
+int show_message_file(const char *filename, const char *background)
+{
+    int rv = KEY_NONE;
+    const char *old_background = NULL;
+
+    if (background) {
+	old_background = current_background;
+	set_background(background);
+    }
+
+    if (!(rv = draw_message_file(filename)))
+	rv = mygetkey(0);	/* Wait for keypress */
+
+    if (old_background)
+	set_background(old_background);
+
+    return rv;
+}
Index: bootcd/isolinux/syslinux-6.03/com32/menu/readconfig.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/readconfig.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/readconfig.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,1177 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
+ *
+ *   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 <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <minmax.h>
+#include <alloca.h>
+#include <inttypes.h>
+#include <colortbl.h>
+#include <com32.h>
+#include <syslinux/adv.h>
+#include <syslinux/config.h>
+
+#include "menu.h"
+
+/* Empty refstring */
+const char *empty_string;
+
+/* 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;
+int clearmenu = 0;
+long long totaltimeout = 0;
+const char *hide_key[KEY_MAX];
+
+/* Keep track of global default */
+static int has_ui = 0;		/* DEFAULT only counts if UI is found */
+static const char *globaldefault = NULL;
+static bool menusave = false;	/* True if there is any "menu save" */
+
+/* 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;
+
+static const struct messages messages[MSG_COUNT] = {
+    [MSG_AUTOBOOT] = {"autoboot", "Automatic boot in # second{,s}..."},
+    [MSG_TAB] = {"tabmsg", "Press [Tab] to edit options"},
+    [MSG_NOTAB] = {"notabmsg", ""},
+    [MSG_PASSPROMPT] = {"passprompt", "Password required"},
+};
+
+#define astrdup(x) ({ char *__x = (x); \
+                      size_t __n = strlen(__x) + 1; \
+                      char *__p = alloca(__n); \
+                      if ( __p ) memcpy(__p, __x, __n); \
+                      __p; })
+
+/* Must match enum kernel_type */
+static const char *const kernel_types[] = {
+    "none",
+    "localboot",
+    "kernel",
+    "linux",
+    "boot",
+    "bss",
+    "pxe",
+    "fdimage",
+    "comboot",
+    "com32",
+    "config",
+    NULL
+};
+
+/*
+ * Search the list of all menus for a specific label
+ */
+static struct menu *find_menu(const char *label)
+{
+    struct menu *m;
+
+    for (m = menu_list; m; m = m->next) {
+	if (!strcmp(label, m->label))
+	    return m;
+    }
+
+    return NULL;
+}
+
+#define MAX_LINE 4096
+
+/* Strip ^ from a string, returning a new reference to the same refstring
+   if none present */
+static const char *strip_caret(const char *str)
+{
+    const char *p, *r;
+    char *q;
+    int carets = 0;
+
+    p = str;
+    for (;;) {
+	p = strchr(p, '^');
+	if (!p)
+	    break;
+	carets++;
+	p++;
+    }
+
+    if (!carets)
+	return refstr_get(str);
+
+    r = q = refstr_alloc(strlen(str) - carets);
+    for (p = str; *p; p++)
+	if (*p != '^')
+	    *q++ = *p;
+
+    *q = '\0';			/* refstr_alloc() already did this... */
+
+    return r;
+}
+
+/* Check to see if we are at a certain keyword (case insensitive) */
+/* Returns a pointer to the first character past the keyword */
+static char *looking_at(char *line, const char *kwd)
+{
+    char *p = line;
+    const char *q = kwd;
+
+    while (*p && *q && ((*p ^ *q) & ~0x20) == 0) {
+	p++;
+	q++;
+    }
+
+    if (*q)
+	return NULL;		/* Didn't see the keyword */
+
+    return my_isspace(*p) ? p : NULL;	/* Must be EOL or whitespace */
+}
+
+/* Get a single word into a new refstr; advances the input pointer */
+static char *get_word(char *str, char **word)
+{
+    char *p = str;
+    char *q;
+
+    while (*p && !my_isspace(*p))
+	p++;
+
+    *word = q = refstr_alloc(p - str);
+    memcpy(q, str, p - str);
+    /* refstr_alloc() already inserted a terminating NUL */
+
+    return p;
+}
+
+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;
+
+    m->label = label;
+    m->title = refstr_get(empty_string);
+
+    if (parent) {
+	/* Submenu */
+	m->parent = parent;
+	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]);
+
+	memcpy(m->mparm, parent->mparm, sizeof m->mparm);
+
+	m->allowedit = parent->allowedit;
+	m->timeout = parent->timeout;
+	m->save = parent->save;
+	m->immediate = parent->immediate;
+
+	m->ontimeout = refstr_get(parent->ontimeout);
+	m->onerror = refstr_get(parent->onerror);
+	m->menu_master_passwd = refstr_get(parent->menu_master_passwd);
+	m->menu_background = refstr_get(parent->menu_background);
+
+	m->color_table = copy_color_table(parent->color_table);
+
+	for (i = 0; i < 12; i++) {
+	    m->fkeyhelp[i].textname = refstr_get(parent->fkeyhelp[i].textname);
+	    m->fkeyhelp[i].background =
+		refstr_get(parent->fkeyhelp[i].background);
+	}
+    } else {
+	/* Root menu */
+	for (i = 0; i < MSG_COUNT; i++)
+	    m->messages[i] = refstrdup(messages[i].defmsg);
+	for (i = 0; i < NPARAMS; i++)
+	    m->mparm[i] = mparm[i].value;
+
+	m->allowedit = true;	/* Allow edits of the command line */
+	m->color_table = default_color_table();
+    }
+
+    m->next = menu_list;
+    menu_list = m;
+
+    return m;
+}
+
+struct labeldata {
+    const char *label;
+    const char *kernel;
+    enum kernel_type type;
+    const char *append;
+    const char *initrd;
+    const char *menulabel;
+    const char *passwd;
+    char *helptext;
+    unsigned int ipappend;
+    unsigned int menuhide;
+    unsigned int menudefault;
+    unsigned int menuseparator;
+    unsigned int menudisabled;
+    unsigned int menuindent;
+    enum menu_action action;
+    int save;
+    int immediate;
+    struct menu *submenu;
+};
+
+/* Menu currently being parsed */
+static struct menu *current_menu;
+
+static void clear_label_data(struct labeldata *ld)
+{
+    refstr_put(ld->label);
+    refstr_put(ld->kernel);
+    refstr_put(ld->append);
+    refstr_put(ld->initrd);
+    refstr_put(ld->menulabel);
+    refstr_put(ld->passwd);
+
+    memset(ld, 0, sizeof *ld);
+}
+
+static struct menu_entry *new_entry(struct menu *m)
+{
+    struct menu_entry *me;
+
+    if (m->nentries >= m->nentries_space) {
+	if (!m->nentries_space)
+	    m->nentries_space = 1;
+	else
+	    m->nentries_space <<= 1;
+
+	m->menu_entries = realloc(m->menu_entries, m->nentries_space *
+				  sizeof(struct menu_entry *));
+    }
+
+    me = calloc(1, sizeof(struct menu_entry));
+    me->menu = m;
+    me->entry = m->nentries;
+    m->menu_entries[m->nentries++] = me;
+    *all_entries_end = me;
+    all_entries_end = &me->next;
+
+    return me;
+}
+
+static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
+{
+    const char *p = strchr(me->displayname, '^');
+
+    if (me->action != MA_DISABLED) {
+	if (p && p[1]) {
+	    unsigned char hotkey = p[1] & ~0x20;
+	    if (!m->menu_hotkeys[hotkey]) {
+		me->hotkey = hotkey;
+		m->menu_hotkeys[hotkey] = me;
+	    }
+	}
+    }
+}
+
+/*
+ * Copy a string, converting whitespace characters to underscores
+ * and compacting them.  Return a pointer to the final null.
+ */
+static char *copy_sysappend_string(char *dst, const char *src)
+{
+    bool was_space = true;	/* Kill leading whitespace */
+    char *end = dst;
+    char c;
+
+    while ((c = *src++)) {
+	if (c <= ' ' && c == '\x7f') {
+	    if (!was_space)
+		*dst++ = '_';
+	    was_space = true;
+	} else {
+	    *dst++ = c;
+	    end = dst;
+	    was_space = false;
+	}
+    }
+    *end = '\0';
+    return end;
+}
+
+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 = 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 = ld->action ? ld->action : MA_CMD;
+	me->save = ld->save ? (ld->save > 0) : m->save;
+	me->immediate = ld->immediate ? (ld->immediate > 0) : m->immediate;
+
+	if (ld->menuindent) {
+	    const char *dn;
+
+	    rsprintf(&dn, "%*s%s", ld->menuindent, "", me->displayname);
+	    refstr_put(me->displayname);
+	    me->displayname = dn;
+	}
+
+	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;
+	}
+
+	if (ld->menulabel)
+	    consider_for_hotkey(m, me);
+
+	switch (me->action) {
+	case MA_CMD:
+	    ipp = ipoptions;
+	    *ipp = '\0';
+
+	    if (ld->initrd)
+		ipp += sprintf(ipp, " initrd=%s", ld->initrd);
+
+	    if (ld->ipappend) {
+		ipappend = syslinux_ipappend_strings();
+		for (i = 0; i < ipappend->count; i++) {
+		    if ((ld->ipappend & (1U << i)) &&
+			ipappend->ptr[i] && ipappend->ptr[i][0]) {
+			*ipp++ = ' ';
+			ipp = copy_sysappend_string(ipp, 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;
+
+	case MA_GOTO_UNRES:
+	case MA_EXIT_UNRES:
+	    me->cmdline = refstr_get(ld->kernel);
+	    break;
+
+	case MA_GOTO:
+	case MA_EXIT:
+	    me->submenu = ld->submenu;
+	    break;
+
+	case MA_HELP:
+	    me->cmdline = refstr_get(ld->kernel);
+	    me->background = refstr_get(ld->append);
+	    break;
+
+	default:
+	    break;
+	}
+
+	if (ld->menudefault && (me->action == MA_CMD ||
+				me->action == MA_GOTO ||
+				me->action == MA_GOTO_UNRES))
+	    m->defentry = m->nentries - 1;
+    }
+
+    clear_label_data(ld);
+}
+
+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, refstr_get(me->displayname));
+}
+
+static struct menu *end_submenu(void)
+{
+    return current_menu->parent ? current_menu->parent : current_menu;
+}
+
+static struct menu_entry *find_label(const char *str)
+{
+    const char *p;
+    struct menu_entry *me;
+    int pos;
+
+    p = str;
+    while (*p && !my_isspace(*p))
+	p++;
+
+    /* p now points to the first byte beyond the kernel name */
+    pos = p - str;
+
+    for (me = all_entries; me; me = me->next) {
+	if (!strncmp(str, me->label, pos) && !me->label[pos])
+	    return me;
+    }
+
+    return NULL;
+}
+
+static const char *unlabel(const char *str)
+{
+    /* Convert a CLI-style command line to an executable command line */
+    const char *p;
+    const char *q;
+    struct menu_entry *me;
+    int pos;
+
+    p = str;
+    while (*p && !my_isspace(*p))
+	p++;
+
+    /* p now points to the first byte beyond the kernel name */
+    pos = p - str;
+
+    for (me = all_entries; me; me = me->next) {
+	if (!strncmp(str, me->label, pos) && !me->label[pos]) {
+	    /* Found matching label */
+	    rsprintf(&q, "%s%s", me->cmdline, p);
+	    refstr_put(str);
+	    return q;
+	}
+    }
+
+    return str;
+}
+
+static const char *refdup_word(char **p)
+{
+    char *sp = *p;
+    char *ep = sp;
+
+    while (*ep && !my_isspace(*ep))
+	ep++;
+
+    *p = ep;
+    return refstrndup(sp, ep - sp);
+}
+
+int my_isxdigit(char c)
+{
+    unsigned int uc = c;
+
+    return (uc - '0') < 10 || ((uc | 0x20) - 'a') < 6;
+}
+
+unsigned int hexval(char c)
+{
+    unsigned char uc = c | 0x20;
+    unsigned int v;
+
+    v = uc - '0';
+    if (v < 10)
+	return v;
+
+    return uc - 'a' + 10;
+}
+
+unsigned int hexval2(const char *p)
+{
+    return (hexval(p[0]) << 4) + hexval(p[1]);
+}
+
+uint32_t parse_argb(char **p)
+{
+    char *sp = *p;
+    char *ep;
+    uint32_t argb;
+    size_t len, dl;
+
+    if (*sp == '#')
+	sp++;
+
+    ep = sp;
+
+    while (my_isxdigit(*ep))
+	ep++;
+
+    *p = ep;
+    len = ep - sp;
+
+    switch (len) {
+    case 3:			/* #rgb */
+	argb =
+	    0xff000000 +
+	    (hexval(sp[0]) * 0x11 << 16) +
+	    (hexval(sp[1]) * 0x11 << 8) + (hexval(sp[2]) * 0x11);
+	break;
+    case 4:			/* #argb */
+	argb =
+	    (hexval(sp[0]) * 0x11 << 24) +
+	    (hexval(sp[1]) * 0x11 << 16) +
+	    (hexval(sp[2]) * 0x11 << 8) + (hexval(sp[3]) * 0x11);
+	break;
+    case 6:			/* #rrggbb */
+    case 9:			/* #rrrgggbbb */
+    case 12:			/* #rrrrggggbbbb */
+	dl = len / 3;
+	argb =
+	    0xff000000 +
+	    (hexval2(sp + 0) << 16) +
+	    (hexval2(sp + dl) << 8) + hexval2(sp + dl * 2);
+	break;
+    case 8:			/* #aarrggbb */
+	/* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
+	   assume the latter is a more common format */
+    case 16:			/* #aaaarrrrggggbbbb */
+	dl = len / 4;
+	argb =
+	    (hexval2(sp + 0) << 24) +
+	    (hexval2(sp + dl) << 16) +
+	    (hexval2(sp + dl * 2) << 8) + hexval2(sp + dl * 3);
+	break;
+    default:
+	argb = 0xffff0000;	/* Bright red (error indication) */
+	break;
+    }
+
+    return argb;
+}
+
+/*
+ * Parser state.  This is global so that including multiple
+ * files work as expected, which is that everything works the
+ * same way as if the files had been concatenated together.
+ */
+static const char *append = NULL;
+static unsigned int ipappend = 0;
+static struct labeldata ld;
+
+static int parse_one_config(const char *filename);
+
+static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
+{
+    const char *const *p;
+    char *q;
+    enum kernel_type t = KT_NONE;
+
+    for (p = kernel_types; *p; p++, t++) {
+	if ((q = looking_at(cmdstr, *p))) {
+	    *type = t;
+	    return q;
+	}
+    }
+
+    return NULL;
+}
+
+static char *is_message_name(char *cmdstr, enum message_number *msgnr)
+{
+    char *q;
+    enum message_number i;
+
+    for (i = 0; i < MSG_COUNT; i++) {
+	if ((q = looking_at(cmdstr, messages[i].name))) {
+	    *msgnr = i;
+	    return q;
+	}
+    }
+
+    return NULL;
+}
+
+static char *is_fkey(char *cmdstr, int *fkeyno)
+{
+    char *q;
+    int no;
+
+    if ((cmdstr[0] | 0x20) != 'f')
+	return NULL;
+
+    no = strtoul(cmdstr + 1, &q, 10);
+    if (!my_isspace(*q))
+	return NULL;
+
+    if (no < 0 || no > 12)
+	return NULL;
+
+    *fkeyno = (no == 0) ? 10 : no - 1;
+    return q;
+}
+
+static void parse_config_file(FILE * f)
+{
+    char line[MAX_LINE], *p, *ep, ch;
+    enum kernel_type type = -1;
+    enum message_number msgnr = -1;
+    int fkeyno = 0;
+    struct menu *m = current_menu;
+
+    while (fgets(line, sizeof line, f)) {
+	p = strchr(line, '\r');
+	if (p)
+	    *p = '\0';
+	p = strchr(line, '\n');
+	if (p)
+	    *p = '\0';
+
+	p = skipspace(line);
+
+	if (looking_at(p, "menu")) {
+	    p = skipspace(p + 4);
+
+	    if (looking_at(p, "label")) {
+		if (ld.label) {
+		    refstr_put(ld.menulabel);
+		    ld.menulabel = refstrdup(skipspace(p + 5));
+		} else if (m->parent_entry) {
+		    refstr_put(m->parent_entry->displayname);
+		    m->parent_entry->displayname = refstrdup(skipspace(p + 5));
+		    consider_for_hotkey(m->parent, m->parent_entry);
+		    if (!m->title[0]) {
+			/* MENU LABEL -> MENU TITLE on submenu */
+			refstr_put(m->title);
+			m->title = strip_caret(m->parent_entry->displayname);
+		    }
+		}
+	    } else if (looking_at(p, "title")) {
+		refstr_put(m->title);
+		m->title = refstrdup(skipspace(p + 5));
+		if (m->parent_entry) {
+		    /* MENU TITLE -> MENU LABEL on submenu */
+		    if (m->parent_entry->displayname == m->label) {
+			refstr_put(m->parent_entry->displayname);
+			m->parent_entry->displayname = refstr_get(m->title);
+		    }
+		}
+	    } else if (looking_at(p, "default")) {
+		if (ld.label) {
+		    ld.menudefault = 1;
+		} else if (m->parent_entry) {
+		    m->parent->defentry = m->parent_entry->entry;
+		}
+	    } else if (looking_at(p, "hide")) {
+		ld.menuhide = 1;
+	    } else if (looking_at(p, "passwd")) {
+		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, "save")) {
+		menusave = true;
+		if (ld.label)
+		    ld.save = 1;
+		else
+		    m->save = true;
+	    } else if (looking_at(p, "nosave")) {
+		if (ld.label)
+		    ld.save = -1;
+		else
+		    m->save = false;
+	    } else if (looking_at(p, "immediate")) {
+		if (ld.label)
+		    ld.immediate = 1;
+		else
+		    m->immediate = true;
+	    } else if (looking_at(p, "noimmediate")) {
+		if (ld.label)
+		    ld.immediate = -1;
+		else
+		    m->immediate = false;
+	    } else if (looking_at(p, "onerror")) {
+		refstr_put(m->onerror);
+		m->onerror = refstrdup(skipspace(p + 7));
+	    } else if (looking_at(p, "master")) {
+		p = skipspace(p + 6);
+		if (looking_at(p, "passwd")) {
+		    refstr_put(m->menu_master_passwd);
+		    m->menu_master_passwd = refstrdup(skipspace(p + 6));
+		}
+	    } else if ((ep = looking_at(p, "include"))) {
+		goto do_include;
+	    } else if ((ep = looking_at(p, "background"))) {
+		p = skipspace(ep);
+		refstr_put(m->menu_background);
+		m->menu_background = refdup_word(&p);
+	    } else if ((ep = looking_at(p, "hidden"))) {
+		hiddenmenu = 1;
+	    } else if (looking_at(p, "hiddenkey")) {
+		char *key_name, *k, *ek;
+		const char *command;
+		int key;
+		p = get_word(skipspace(p + 9), &key_name);
+		command = refstrdup(skipspace(p));
+		k = key_name;
+		for (;;) {
+		    ek = strchr(k+1, ',');
+		    if (ek)
+			*ek = '\0';
+		    key = key_name_to_code(k);
+		    if (key >= 0) {
+			refstr_put(hide_key[key]);
+			hide_key[key] = refstr_get(command);
+		    }
+		    if (!ek)
+			break;
+		    k = ek+1;
+		}
+		refstr_put(key_name);
+		refstr_put(command);
+	    } else if ((ep = looking_at(p, "clear"))) {
+		clearmenu = 1;
+	    } else if ((ep = is_message_name(p, &msgnr))) {
+		refstr_put(m->messages[msgnr]);
+		m->messages[msgnr] = refstrdup(skipspace(ep));
+	    } else if ((ep = looking_at(p, "color")) ||
+		       (ep = looking_at(p, "colour"))) {
+		int i;
+		struct color_table *cptr;
+		p = skipspace(ep);
+		cptr = m->color_table;
+		for (i = 0; i < menu_color_table_size; i++) {
+		    if ((ep = looking_at(p, cptr->name))) {
+			p = skipspace(ep);
+			if (*p) {
+			    if (looking_at(p, "*")) {
+				p++;
+			    } else {
+				refstr_put(cptr->ansi);
+				cptr->ansi = refdup_word(&p);
+			    }
+
+			    p = skipspace(p);
+			    if (*p) {
+				if (looking_at(p, "*"))
+				    p++;
+				else
+				    cptr->argb_fg = parse_argb(&p);
+
+				p = skipspace(p);
+				if (*p) {
+				    if (looking_at(p, "*"))
+					p++;
+				    else
+					cptr->argb_bg = parse_argb(&p);
+
+				    /* Parse a shadow mode */
+				    p = skipspace(p);
+				    ch = *p | 0x20;
+				    if (ch == 'n')	/* none */
+					cptr->shadow = SHADOW_NONE;
+				    else if (ch == 's')	/* std, standard */
+					cptr->shadow = SHADOW_NORMAL;
+				    else if (ch == 'a')	/* all */
+					cptr->shadow = SHADOW_ALL;
+				    else if (ch == 'r')	/* rev, reverse */
+					cptr->shadow = SHADOW_REVERSE;
+				}
+			    }
+			}
+			break;
+		    }
+		    cptr++;
+		}
+	    } else if ((ep = looking_at(p, "msgcolor")) ||
+		       (ep = looking_at(p, "msgcolour"))) {
+		unsigned int fg_mask = MSG_COLORS_DEF_FG;
+		unsigned int bg_mask = MSG_COLORS_DEF_BG;
+		enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW;
+
+		p = skipspace(ep);
+		if (*p) {
+		    if (!looking_at(p, "*"))
+			fg_mask = parse_argb(&p);
+
+		    p = skipspace(p);
+		    if (*p) {
+			if (!looking_at(p, "*"))
+			    bg_mask = parse_argb(&p);
+
+			p = skipspace(p);
+			switch (*p | 0x20) {
+			case 'n':
+			    shadow = SHADOW_NONE;
+			    break;
+			case 's':
+			    shadow = SHADOW_NORMAL;
+			    break;
+			case 'a':
+			    shadow = SHADOW_ALL;
+			    break;
+			case 'r':
+			    shadow = SHADOW_REVERSE;
+			    break;
+			default:
+			    /* go with default */
+			    break;
+			}
+		    }
+		}
+		set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow);
+	    } else if (looking_at(p, "separator")) {
+		record(m, &ld, append);
+		ld.label = refstr_get(empty_string);
+		ld.menuseparator = 1;
+		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, "exit")) {
+		p = skipspace(p + 4);
+		if (ld.label && m->parent) {
+		    if (*p) {
+			/* This is really just a goto, except for the marker */
+			ld.action = MA_EXIT_UNRES;
+			refstr_put(ld.kernel);
+			ld.kernel = refstrdup(p);
+		    } else {
+			ld.action = MA_EXIT;
+			ld.submenu = m->parent;
+		    }
+		}
+	    } else if (looking_at(p, "start")) {
+		start_menu = m;
+	    } else if (looking_at(p, "help")) {
+		if (ld.label) {
+		    ld.action = MA_HELP;
+		    p = skipspace(p + 4);
+
+		    refstr_put(ld.kernel);
+		    ld.kernel = refdup_word(&p);
+
+		    if (ld.append) {
+			refstr_put(ld.append);
+			ld.append = NULL;
+		    }
+
+		    if (*p) {
+			p = skipspace(p);
+			ld.append = refdup_word(&p); /* Background */
+		    }
+		}
+	    } else if ((ep = looking_at(p, "resolution"))) {
+		int x, y;
+		x = strtoul(ep, &ep, 0);
+		y = strtoul(skipspace(ep), NULL, 0);
+		set_resolution(x, y);
+	    } else {
+		/* Unknown, check for layout parameters */
+		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 (looking_at(p, "text")) {
+	    enum text_cmd {
+		TEXT_UNKNOWN,
+		TEXT_HELP
+	    } cmd = TEXT_UNKNOWN;
+	    int len = ld.helptext ? strlen(ld.helptext) : 0;
+	    int xlen;
+
+	    p = skipspace(p + 4);
+
+	    if (looking_at(p, "help"))
+		cmd = TEXT_HELP;
+
+	    while (fgets(line, sizeof line, f)) {
+		p = skipspace(line);
+		if (looking_at(p, "endtext"))
+		    break;
+
+		xlen = strlen(line);
+
+		switch (cmd) {
+		case TEXT_UNKNOWN:
+		    break;
+		case TEXT_HELP:
+		    ld.helptext = realloc(ld.helptext, len + xlen + 1);
+		    memcpy(ld.helptext + len, line, xlen + 1);
+		    len += xlen;
+		    break;
+		}
+	    }
+	} else if ((ep = is_fkey(p, &fkeyno))) {
+	    p = skipspace(ep);
+	    if (m->fkeyhelp[fkeyno].textname) {
+		refstr_put(m->fkeyhelp[fkeyno].textname);
+		m->fkeyhelp[fkeyno].textname = NULL;
+	    }
+	    if (m->fkeyhelp[fkeyno].background) {
+		refstr_put(m->fkeyhelp[fkeyno].background);
+		m->fkeyhelp[fkeyno].background = NULL;
+	    }
+
+	    refstr_put(m->fkeyhelp[fkeyno].textname);
+	    m->fkeyhelp[fkeyno].textname = refdup_word(&p);
+	    if (*p) {
+		p = skipspace(p);
+		m->fkeyhelp[fkeyno].background = refdup_word(&p);
+	    }
+	} else if ((ep = looking_at(p, "include"))) {
+do_include:
+	    {
+		const char *file;
+		p = skipspace(ep);
+		file = refdup_word(&p);
+		p = skipspace(p);
+		if (*p) {
+		    record(m, &ld, append);
+		    m = current_menu = begin_submenu(p);
+		    parse_one_config(file);
+		    record(m, &ld, append);
+		    m = current_menu = end_submenu();
+		} else {
+		    parse_one_config(file);
+		}
+		refstr_put(file);
+	    }
+	} else if (looking_at(p, "append")) {
+	    const char *a = refstrdup(skipspace(p + 6));
+	    if (ld.label) {
+		refstr_put(ld.append);
+		ld.append = a;
+	    } else {
+		refstr_put(append);
+		append = a;
+	    }
+	} else if (looking_at(p, "initrd")) {
+	    const char *a = refstrdup(skipspace(p + 6));
+	    if (ld.label) {
+		refstr_put(ld.initrd);
+		ld.initrd = a;
+	    } else {
+		/* Ignore */
+	    }
+	} else if (looking_at(p, "label")) {
+	    p = skipspace(p + 5);
+	    record(m, &ld, append);
+	    ld.label = refstrdup(p);
+	    ld.kernel = refstrdup(p);
+	    ld.type = KT_KERNEL;
+	    ld.passwd = NULL;
+	    ld.append = NULL;
+	    ld.initrd = NULL;
+	    ld.menulabel = NULL;
+	    ld.helptext = NULL;
+	    ld.ipappend = ipappend;
+	    ld.menudefault = ld.menuhide = ld.menuseparator =
+		ld.menudisabled = ld.menuindent = 0;
+	} else if ((ep = is_kernel_type(p, &type))) {
+	    if (ld.label) {
+		refstr_put(ld.kernel);
+		ld.kernel = refstrdup(skipspace(ep));
+		ld.type = type;
+	    }
+	} else if (looking_at(p, "timeout")) {
+	    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")) {
+	    m->ontimeout = refstrdup(skipspace(p + 9));
+	} else if (looking_at(p, "allowoptions")) {
+	    m->allowedit = !!atoi(skipspace(p + 12));
+	} else if ((ep = looking_at(p, "ipappend")) ||
+		   (ep = looking_at(p, "sysappend"))) {
+	    uint32_t s = strtoul(skipspace(ep), NULL, 0);
+	    if (ld.label)
+		ld.ipappend = s;
+	    else
+		ipappend = s;
+	} else if (looking_at(p, "default")) {
+	    refstr_put(globaldefault);
+	    globaldefault = refstrdup(skipspace(p + 7));
+	} else if (looking_at(p, "ui")) {
+	    has_ui = 1;
+	}
+    }
+}
+
+static int parse_one_config(const char *filename)
+{
+    FILE *f;
+
+    if (!strcmp(filename, "~"))
+	filename = syslinux_config_file();
+
+    dprintf("Opening config file: %s ", filename);
+
+    f = fopen(filename, "r");
+    dprintf("%s\n", f ? "ok" : "failed");
+    
+    if (!f)
+	return -1;
+
+    parse_config_file(f);
+    fclose(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 || me->action == MA_EXIT_UNRES) {
+	    m = find_menu(me->cmdline);
+	    refstr_put(me->cmdline);
+	    me->cmdline = NULL;
+	    if (m) {
+		me->submenu = m;
+		me->action--;	/* Drop the _UNRES */
+	    } else {
+		me->action = MA_DISABLED;
+	    }
+	}
+    }
+}
+
+void parse_configs(char **argv)
+{
+    const char *filename;
+    struct menu *m;
+    struct menu_entry *me;
+    int k;
+
+    empty_string = refstrdup("");
+
+    /* Initialize defaults for the root and hidden menus */
+    hide_menu = new_menu(NULL, NULL, refstrdup(".hidden"));
+    root_menu = new_menu(NULL, NULL, refstrdup(".top"));
+    start_menu = root_menu;
+
+    /* Other initialization */
+    memset(&ld, 0, sizeof(struct labeldata));
+
+    /* Actually process the files */
+    current_menu = root_menu;
+    if (!*argv) {
+	parse_one_config("~");
+    } else {
+	while ((filename = *argv++))
+	    parse_one_config(filename);
+    }
+
+    /* On final EOF process the last label statement */
+    record(current_menu, &ld, append);
+
+    /* Common postprocessing */
+    resolve_gotos();
+
+    /* Handle global default */
+    if (has_ui && globaldefault) {
+	me = find_label(globaldefault);
+	if (me && me->menu != hide_menu) {
+	    me->menu->defentry = me->entry;
+	    start_menu = me->menu;
+	}
+    }
+
+    /* If "menu save" is active, let the ADV override the global default */
+    if (menusave) {
+	size_t len;
+	const char *lbl = syslinux_getadv(ADV_MENUSAVE, &len);
+	char *lstr;
+	if (lbl && len) {
+	    lstr = refstr_alloc(len);
+	    memcpy(lstr, lbl, len);	/* refstr_alloc() adds the final null */
+	    me = find_label(lstr);
+	    if (me && me->menu != hide_menu) {
+		me->menu->defentry = me->entry;
+		start_menu = me->menu;
+	    }
+	    refstr_put(lstr);
+	}
+    }
+
+    /* Final per-menu initialization, with all labels known */
+    for (m = menu_list; m; m = m->next) {
+	m->curentry = m->defentry;	/* All menus start at their defaults */
+
+	if (m->ontimeout)
+	    m->ontimeout = unlabel(m->ontimeout);
+	if (m->onerror)
+	    m->onerror = unlabel(m->onerror);
+    }
+
+    /* Final global initialization, with all labels known */
+    for (k = 0; k < KEY_MAX; k++) {
+	if (hide_key[k])
+	    hide_key[k] = unlabel(hide_key[k]);
+    }
+}
Index: bootcd/isolinux/syslinux-6.03/com32/menu/refstr.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/refstr.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/refstr.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,105 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * refstr.c
+ *
+ * Simple reference-counted strings
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "refstr.h"
+
+/* Allocate space for a refstring of len bytes, plus final null */
+/* The final null is inserted in the string; the rest is uninitialized. */
+char *refstr_alloc(size_t len)
+{
+    char *r = malloc(sizeof(unsigned int) + len + 1);
+    if (!r)
+	return NULL;
+    *(unsigned int *)r = 1;
+    r += sizeof(unsigned int);
+    r[len] = '\0';
+    return r;
+}
+
+const char *refstrndup(const char *str, size_t len)
+{
+    char *r;
+
+    if (!str)
+	return NULL;
+
+    len = strnlen(str, len);
+    r = refstr_alloc(len);
+    if (r)
+	memcpy(r, str, len);
+    return r;
+}
+
+const char *refstrdup(const char *str)
+{
+    char *r;
+    size_t len;
+
+    if (!str)
+	return NULL;
+
+    len = strlen(str);
+    r = refstr_alloc(len);
+    if (r)
+	memcpy(r, str, len);
+    return r;
+}
+
+int vrsprintf(const char **bufp, const char *fmt, va_list ap)
+{
+    va_list ap1;
+    int len;
+    char *p;
+
+    va_copy(ap1, ap);
+    len = vsnprintf(NULL, 0, fmt, ap1);
+    va_end(ap1);
+
+    *bufp = p = refstr_alloc(len);
+    if (!p)
+	return -1;
+
+    return vsnprintf(p, len + 1, 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;
+
+    if (r) {
+	ref = (unsigned int *)r - 1;
+
+	if (!--*ref)
+	    free(ref);
+    }
+}
Index: bootcd/isolinux/syslinux-6.03/com32/menu/vesamenu.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/menu/vesamenu.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/menu/vesamenu.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,52 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ *   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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * vesamenu.c
+ *
+ * Simple menu system which displays a list and allows the user to select
+ * a command line and/or edit it.
+ *
+ * VESA graphics version.
+ */
+
+#include <stdio.h>
+#include <console.h>
+#include <syslinux/vesacon.h>
+
+#include "menu.h"
+
+int draw_background(const char *what)
+{
+    if (!what)
+	return vesacon_default_background();
+    else if (what[0] == '#')
+	return vesacon_set_background(parse_argb((char **)&what));
+    else
+	return vesacon_load_background(what);
+}
+
+void set_resolution(int x, int y)
+{
+    vesacon_set_resolution(x, y);
+}
+
+void local_cursor_enable(bool enabled)
+{
+    vesacon_cursor_enable(enabled);
+}
+
+void start_console(void)
+{
+    openconsole(&dev_rawcon_r, &dev_vesaserial_w);
+}
