176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* ----------------------------------------------------------------------- *
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Copyright 2009-2014 Intel Corporation; author: H. Peter Anvin
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   This program is free software; you can redistribute it and/or modify
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   it under the terms of the GNU General Public License as published by
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Boston MA 02110-1301, USA; either version 2 of the License, or
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   (at your option) any later version; incorporated herein by reference.
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ----------------------------------------------------------------------- */
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * menumain.c
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Simple menu system which displays a list and allows the user to select
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a command line and/or edit it.
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <ctype.h>
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h>
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h>
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <consoles.h>
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <getkey.h>
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <minmax.h>
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <setjmp.h>
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <limits.h>
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <com32.h>
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <core.h>
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <syslinux/adv.h>
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <syslinux/boot.h>
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "menu.h"
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* The symbol "cm" always refers to the current menu across this file... */
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct menu *cm;
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanconst struct menu_parameter mparm[NPARAMS] = {
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_WIDTH] = {"width", 0},
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_MARGIN] = {"margin", 10},
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_PASSWD_MARGIN] = {"passwordmargin", 3},
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_MENU_ROWS] = {"rows", 12},
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_TABMSG_ROW] = {"tabmsgrow", 18},
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_CMDLINE_ROW] = {"cmdlinerow", 18},
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_END_ROW] = {"endrow", -1},
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_PASSWD_ROW] = {"passwordrow", 11},
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_TIMEOUT_ROW] = {"timeoutrow", 20},
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_HELPMSG_ROW] = {"helpmsgrow", 22},
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_HELPMSGEND_ROW] = {"helpmsgendrow", -1},
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_HSHIFT] = {"hshift", 0},
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_VSHIFT] = {"vshift", 0},
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    [P_HIDDEN_ROW] = {"hiddenrow", -2},
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* These macros assume "cm" is a pointer to the current menu */
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define WIDTH		(cm->mparm[P_WIDTH])
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define MARGIN		(cm->mparm[P_MARGIN])
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define PASSWD_MARGIN	(cm->mparm[P_PASSWD_MARGIN])
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define MENU_ROWS	(cm->mparm[P_MENU_ROWS])
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define TABMSG_ROW	(cm->mparm[P_TABMSG_ROW]+VSHIFT)
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define CMDLINE_ROW	(cm->mparm[P_CMDLINE_ROW]+VSHIFT)
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define END_ROW		(cm->mparm[P_END_ROW])
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define PASSWD_ROW	(cm->mparm[P_PASSWD_ROW]+VSHIFT)
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define TIMEOUT_ROW	(cm->mparm[P_TIMEOUT_ROW]+VSHIFT)
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define HELPMSG_ROW	(cm->mparm[P_HELPMSG_ROW]+VSHIFT)
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define HELPMSGEND_ROW	(cm->mparm[P_HELPMSGEND_ROW])
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define HSHIFT		(cm->mparm[P_HSHIFT])
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define VSHIFT		(cm->mparm[P_VSHIFT])
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define HIDDEN_ROW	(cm->mparm[P_HIDDEN_ROW])
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic char *pad_line(const char *text, int align, int width)
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static char buffer[MAX_CMDLINE_LEN];
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int n, p;
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (width >= (int)sizeof buffer)
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return NULL;		/* Can't do it */
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    n = strlen(text);
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (n >= width)
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	n = width;
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(buffer, ' ', width);
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    buffer[width] = 0;
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    p = ((width - n) * align) >> 1;
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memcpy(buffer + p, text, n);
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return buffer;
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Display an entry, with possible hotkey highlight.  Assumes
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   that the current attribute is the non-hotkey one, and will
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   guarantee that as an exit condition as well. */
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmandisplay_entry(const struct menu_entry *entry, const char *attrib,
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	      const char *hotattrib, int width)
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char *p = entry->displayname;
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char marker;
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!p)
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	p = "";
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    switch (entry->action) {
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case MA_SUBMENU:
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	marker = '>';
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case MA_EXIT:
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	marker = '<';
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    default:
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	marker = 0;
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	break;
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (marker)
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	width -= 2;
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (width) {
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (*p) {
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (*p == '^') {
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		p++;
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (*p && ((unsigned char)*p & ~0x20) == entry->hotkey) {
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    fputs(hotattrib, stdout);
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    putchar(*p++);
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    fputs(attrib, stdout);
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    width--;
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    } else {
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		putchar(*p++);
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		width--;
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    putchar(' ');
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    width--;
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (marker) {
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	putchar(' ');
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	putchar(marker);
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void draw_row(int y, int sel, int top, int sbtop, int sbbot)
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i = (y - 4 - VSHIFT) + top;
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int dis = (i < cm->nentries) && is_disabled(cm->menu_entries[i]);
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("\033[%d;%dH\1#1\016x\017%s ",
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   y, MARGIN + 1 + HSHIFT,
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   (i == sel) ? "\1#5" : dis ? "\2#17" : "\1#3");
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (i >= cm->nentries) {
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fputs(pad_line("", 0, WIDTH - 2 * MARGIN - 4), stdout);
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	display_entry(cm->menu_entries[i],
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		      (i == sel) ? "\1#5" : dis ? "\2#17" : "\1#3",
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		      (i == sel) ? "\1#6" : dis ? "\2#17" : "\1#4",
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		      WIDTH - 2 * MARGIN - 4);
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (cm->nentries <= MENU_ROWS) {
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf(" \1#1\016x\017");
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (sbtop > 0) {
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (y >= sbtop && y <= sbbot)
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    printf(" \1#7\016a\017");
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    printf(" \1#1\016x\017");
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	putchar(' ');		/* Don't modify the scrollbar */
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic jmp_buf timeout_jump;
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint mygetkey(clock_t timeout)
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    clock_t t0, t;
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    clock_t tto, to;
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int key;
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!totaltimeout)
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return get_key(stdin, timeout);
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (;;) {
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tto = min(totaltimeout, INT_MAX);
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	to = timeout ? min(tto, timeout) : tto;
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	t0 = times(NULL);
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	key = get_key(stdin, to);
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	t = times(NULL) - t0;
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (totaltimeout <= t)
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    longjmp(timeout_jump, 1);
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	totaltimeout -= t;
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (key != KEY_NONE)
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    return key;
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (timeout) {
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (timeout <= t)
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return KEY_NONE;
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    timeout -= t;
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ask_passwd(const char *menu_entry)
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char user_passwd[WIDTH], *p;
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int done;
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int key;
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int x;
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int rv;
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("\033[%d;%dH\2#11\016l", PASSWD_ROW, PASSWD_MARGIN + 1);
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (x = 2; x <= WIDTH - 2 * PASSWD_MARGIN - 1; x++)
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	putchar('q');
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("k\033[%d;%dHx", PASSWD_ROW + 1, PASSWD_MARGIN + 1);
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (x = 2; x <= WIDTH - 2 * PASSWD_MARGIN - 1; x++)
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	putchar(' ');
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("x\033[%d;%dHm", PASSWD_ROW + 2, PASSWD_MARGIN + 1);
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (x = 2; x <= WIDTH - 2 * PASSWD_MARGIN - 1; x++)
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	putchar('q');
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("j\017\033[%d;%dH\2#12 %s \033[%d;%dH\2#13",
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   PASSWD_ROW, (WIDTH - (strlen(cm->messages[MSG_PASSPROMPT]) + 2)) / 2,
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   cm->messages[MSG_PASSPROMPT], PASSWD_ROW + 1, PASSWD_MARGIN + 3);
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    drain_keyboard();
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Actually allow user to type a password, then compare to the SHA1 */
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    done = 0;
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    p = user_passwd;
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (!done) {
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	key = mygetkey(0);
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch (key) {
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_ENTER:
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('J'):
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    done = 1;
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_ESC:
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('C'):
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    p = user_passwd;	/* No password entered */
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    done = 1;
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_BACKSPACE:
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_DEL:
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_DELETE:
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (p > user_passwd) {
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf("\b \b");
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		p--;
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('U'):
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (p > user_passwd) {
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		printf("\b \b");
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		p--;
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default:
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (key >= ' ' && key <= 0xFF &&
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		(p - user_passwd) < WIDTH - 2 * PASSWD_MARGIN - 5) {
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		*p++ = key;
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		putchar('*');
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (p == user_passwd)
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 0;		/* No password entered */
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *p = '\0';
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    rv = (cm->menu_master_passwd &&
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	  passwd_compare(cm->menu_master_passwd, user_passwd))
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	|| (menu_entry && passwd_compare(menu_entry, user_passwd));
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Clean up */
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(user_passwd, 0, WIDTH);
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    drain_keyboard();
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return rv;
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void draw_menu(int sel, int top, int edit_line)
30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int x, y;
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int sbtop = 0, sbbot = 0;
30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char *tabmsg;
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int tabmsg_len;
30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (cm->nentries > MENU_ROWS) {
30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	int sblen = max(MENU_ROWS * MENU_ROWS / cm->nentries, 1);
30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	sbtop = (MENU_ROWS - sblen + 1) * top / (cm->nentries - MENU_ROWS + 1);
31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	sbbot = sbtop + sblen - 1;
31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	sbtop += 4;
31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	sbbot += 4;		/* Starting row of scrollbar */
31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("\033[%d;%dH\1#1\016l", VSHIFT + 1, HSHIFT + MARGIN + 1);
31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (x = 2 + HSHIFT; x <= (WIDTH - 2 * MARGIN - 1) + HSHIFT; x++)
31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	putchar('q');
31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("k\033[%d;%dH\1#1x\017\1#2 %s \1#1\016x",
32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   VSHIFT + 2,
32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   HSHIFT + MARGIN + 1, pad_line(cm->title, 1, WIDTH - 2 * MARGIN - 4));
32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("\033[%d;%dH\1#1t", VSHIFT + 3, HSHIFT + MARGIN + 1);
32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (x = 2 + HSHIFT; x <= (WIDTH - 2 * MARGIN - 1) + HSHIFT; x++)
32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	putchar('q');
32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    fputs("u\017", stdout);
32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (y = 4 + VSHIFT; y < 4 + VSHIFT + MENU_ROWS; y++)
32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	draw_row(y, sel, top, sbtop, sbbot);
33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("\033[%d;%dH\1#1\016m", y, HSHIFT + MARGIN + 1);
33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (x = 2 + HSHIFT; x <= (WIDTH - 2 * MARGIN - 1) + HSHIFT; x++)
33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	putchar('q');
33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    fputs("j\017", stdout);
33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (edit_line && cm->allowedit && !cm->menu_master_passwd)
33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tabmsg = cm->messages[MSG_TAB];
33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else
33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tabmsg = cm->messages[MSG_NOTAB];
34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tabmsg_len = strlen(tabmsg);
34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("\1#8\033[%d;%dH%s",
34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   TABMSG_ROW, 1 + HSHIFT + ((WIDTH - tabmsg_len) >> 1), tabmsg);
34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("\1#0\033[%d;1H", END_ROW);
34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void clear_screen(void)
34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout);
35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void display_help(const char *text)
35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int row;
35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char *p;
35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!text) {
35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	text = "";
36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("\1#0\033[%d;1H", HELPMSG_ROW);
36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("\2#16\033[%d;1H", HELPMSG_ROW);
36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (p = text, row = HELPMSG_ROW; *p && row <= HELPMSGEND_ROW; p++) {
36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch (*p) {
36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case '\r':
36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case '\f':
36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case '\v':
37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case '\033':
37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case '\n':
37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    printf("\033[K\033[%d;1H", ++row);
37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default:
37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    putchar(*p);
37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    fputs("\033[K", stdout);
38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (row <= HELPMSGEND_ROW) {
38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("\033[K\033[%d;1H", ++row);
38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void show_fkey(int key)
38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int fkey;
39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (1) {
39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch (key) {
39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F1:
39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 0;
39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F2:
39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 1;
39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F3:
40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 2;
40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F4:
40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 3;
40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F5:
40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 4;
40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F6:
40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 5;
41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F7:
41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 6;
41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F8:
41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 7;
41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F9:
41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 8;
41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F10:
42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 9;
42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F11:
42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 10;
42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F12:
42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = 11;
42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default:
43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    fkey = -1;
43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (fkey == -1)
43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (cm->fkeyhelp[fkey].textname)
43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    key = show_message_file(cm->fkeyhelp[fkey].textname,
43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				    cm->fkeyhelp[fkey].background);
44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else
44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const char *edit_cmdline(const char *input, int top)
44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static char cmdline[MAX_CMDLINE_LEN];
44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int key, len, prev_len, cursor;
44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int redraw = 1;		/* We enter with the menu already drawn */
45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    strlcpy(cmdline, input, MAX_CMDLINE_LEN);
45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    cmdline[MAX_CMDLINE_LEN - 1] = '\0';
45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    len = cursor = strlen(cmdline);
45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    prev_len = 0;
45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (;;) {
45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (redraw > 1) {
45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* Clear and redraw whole screen */
46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* Enable ASCII on G0 and DEC VT on G1; do it in this order
46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       to avoid confusing the Linux console */
46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    clear_screen();
46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    draw_menu(-1, top, 1);
46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    prev_len = 0;
46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (redraw > 0) {
46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* Redraw the command line */
46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    printf("\033[?25l\033[%d;1H\1#9> \2#10%s",
47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   CMDLINE_ROW, pad_line(cmdline, 0, max(len, prev_len)));
47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    printf("\2#10\033[%d;3H%s\033[?25h",
47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   CMDLINE_ROW, pad_line(cmdline, 0, cursor));
47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    prev_len = len;
47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    redraw = 0;
47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	key = mygetkey(0);
47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch (key) {
48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('L'):
48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    redraw = 2;
48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_ENTER:
48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('J'):
48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    return cmdline;
48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_ESC:
48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('C'):
49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    return NULL;
49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_BACKSPACE:
49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_DEL:
49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cursor) {
49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		memmove(cmdline + cursor - 1, cmdline + cursor,
49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			len - cursor + 1);
49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		len--;
49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		cursor--;
49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		redraw = 1;
50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('D'):
50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_DELETE:
50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cursor < len) {
50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		memmove(cmdline + cursor, cmdline + cursor + 1, len - cursor);
50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		len--;
50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		redraw = 1;
50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('U'):
51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (len) {
51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		len = cursor = 0;
51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		cmdline[len] = '\0';
51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		redraw = 1;
51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('W'):
52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cursor) {
52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		int prevcursor = cursor;
52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		while (cursor && my_isspace(cmdline[cursor - 1]))
52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    cursor--;
52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		while (cursor && !my_isspace(cmdline[cursor - 1]))
52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    cursor--;
52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		memmove(cmdline + cursor, cmdline + prevcursor,
53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			len - prevcursor + 1);
53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		len -= (prevcursor - cursor);
53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		redraw = 1;
53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_LEFT:
53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('B'):
53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cursor) {
54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		cursor--;
54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		redraw = 1;
54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_RIGHT:
54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('F'):
54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cursor < len) {
54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		putchar(cmdline[cursor++]);
54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('K'):
55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cursor < len) {
55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		cmdline[len = cursor] = '\0';
55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		redraw = 1;
55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_HOME:
56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('A'):
56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cursor) {
56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		cursor = 0;
56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		redraw = 1;
56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_END:
56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('E'):
56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cursor != len) {
57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		cursor = len;
57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		redraw = 1;
57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F1:
57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F2:
57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F3:
57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F4:
57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F5:
58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F6:
58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F7:
58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F8:
58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F9:
58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F10:
58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F11:
58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F12:
58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    show_fkey(key);
58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    redraw = 1;
58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default:
59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) {
59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (cursor == len) {
59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    cmdline[len] = key;
59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    cmdline[++len] = '\0';
59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    cursor++;
59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    putchar(key);
59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    prev_len++;
59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		} else {
60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    memmove(cmdline + cursor + 1, cmdline + cursor,
60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			    len - cursor + 1);
60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    cmdline[cursor++] = key;
60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    len++;
60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    redraw = 1;
60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void print_timeout_message(int tol, int row, const char *msg)
61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    static int last_msg_len = 0;
61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char buf[256];
61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int nc = 0, nnc, padc;
61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char *tp = msg;
61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char tc;
61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char *tq = buf;
62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while ((size_t) (tq - buf) < (sizeof buf - 16) && (tc = *tp)) {
62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	tp++;
62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (tc == '#') {
62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    nnc = sprintf(tq, "\2#15%d\2#14", tol);
62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    tq += nnc;
62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    nc += nnc - 8;	/* 8 formatting characters */
62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else if (tc == '{') {
62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* Deal with {singular[,dual],plural} constructs */
62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    struct {
63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		const char *s, *e;
63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    } tx[3];
63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    const char *tpp;
63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    int n = 0;
63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    memset(tx, 0, sizeof tx);
63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    tx[0].s = tp;
63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (*tp && *tp != '}') {
64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (*tp == ',' && n < 2) {
64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    tx[n].e = tp;
64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    n++;
64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    tx[n].s = tp + 1;
64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp++;
64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    tx[n].e = tp;
64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (*tp)
65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tp++;		/* Skip final bracket */
65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (!tx[1].s)
65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tx[1] = tx[0];
65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (!tx[2].s)
65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		tx[2] = tx[1];
65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* Now [0] is singular, [1] is dual, and [2] is plural,
65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       even if the user only specified some of them. */
65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    switch (tol) {
66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    case 1:
66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		n = 0;
66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    case 2:
66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		n = 1;
66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    default:
66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		n = 2;
66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		break;
67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    for (tpp = tx[n].s; tpp < tx[n].e; tpp++) {
67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if ((size_t) (tq - buf) < (sizeof buf)) {
67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    *tq++ = *tpp;
67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    nc++;
67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    *tq++ = tc;
68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    nc++;
68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *tq = '\0';
68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (nc >= last_msg_len) {
68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	padc = 0;
68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	padc = (last_msg_len - nc + 1) >> 1;
68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("\033[%d;%dH\2#14%*s%s%*s", row,
69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   HSHIFT + 1 + ((WIDTH - nc) >> 1) - padc,
69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   padc, "", buf, padc, "");
69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    last_msg_len = nc;
69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Set the background screen, etc. */
69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void prepare_screen_for_menu(void)
70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    console_color_table = cm->color_table;
70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    console_color_table_size = menu_color_table_size;
70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    set_background(cm->menu_background);
70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const char *do_hidden_menu(void)
70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int key;
70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int timeout_left, this_timeout;
71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    clear_screen();
71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!setjmp(timeout_jump)) {
71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	timeout_left = cm->timeout;
71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	while (!cm->timeout || timeout_left) {
71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    int tol = timeout_left / CLK_TCK;
71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    print_timeout_message(tol, HIDDEN_ROW, cm->messages[MSG_AUTOBOOT]);
72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    this_timeout = min(timeout_left, CLK_TCK);
72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    key = mygetkey(this_timeout);
72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (key != KEY_NONE) {
72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Clear the message from the screen */
72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		print_timeout_message(0, HIDDEN_ROW, "");
72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		return hide_key[key]; /* NULL if no MENU HIDEKEY in effect */
72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    timeout_left -= this_timeout;
73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Clear the message from the screen */
73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    print_timeout_message(0, HIDDEN_ROW, "");
73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (cm->ontimeout)
73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return cm->ontimeout;
73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else
74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return cm->menu_entries[cm->defentry]->cmdline; /* Default entry */
74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const char *run_menu(void)
74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int key;
74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int done = 0;
74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    volatile int entry = cm->curentry;
74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int prev_entry = -1;
74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    volatile int top = cm->curtop;
75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int prev_top = -1;
75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int clear = 1, to_clear;
75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char *cmdline = NULL;
75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    volatile clock_t key_timeout, timeout_left, this_timeout;
75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const struct menu_entry *me;
75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    bool hotkey = false;
75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Note: for both key_timeout and timeout == 0 means no limit */
75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    timeout_left = key_timeout = cm->timeout;
75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* If we're in shiftkey mode, exit immediately unless a shift key
76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       is pressed */
76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (shiftkey && !shift_is_held()) {
76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return cm->menu_entries[cm->defentry]->cmdline;
76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	shiftkey = 0;
76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Do this before hiddenmenu handling, so we show the background */
76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    prepare_screen_for_menu();
77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Handle hiddenmenu */
77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (hiddenmenu) {
77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cmdline = do_hidden_menu();
77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (cmdline)
77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    return cmdline;
77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Otherwise display the menu now; the timeout has already been
77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   cancelled, since the user pressed a key. */
77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	hiddenmenu = 0;
78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	key_timeout = 0;
78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Handle both local and global timeout */
78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (setjmp(timeout_jump)) {
78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	entry = cm->defentry;
78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (top < 0 || top < entry - MENU_ROWS + 1)
78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    top = max(0, entry - MENU_ROWS + 1);
78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else if (top > entry || top > max(0, cm->nentries - MENU_ROWS))
79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    top = min(entry, max(0, cm->nentries - MENU_ROWS));
79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	draw_menu(cm->ontimeout ? -1 : entry, top, 1);
79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cmdline =
79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    cm->ontimeout ? cm->ontimeout : cm->menu_entries[entry]->cmdline;
79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	done = 1;
79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (!done) {
79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (entry <= 0) {
80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    entry = 0;
80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (entry < cm->nentries && is_disabled(cm->menu_entries[entry]))
80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry++;
80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (entry >= cm->nentries - 1) {
80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    entry = cm->nentries - 1;
80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (entry > 0 && is_disabled(cm->menu_entries[entry]))
80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry--;
80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	me = cm->menu_entries[entry];
81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (top < 0 || top < entry - MENU_ROWS + 1)
81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    top = max(0, entry - MENU_ROWS + 1);
81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else if (top > entry || top > max(0, cm->nentries - MENU_ROWS))
81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    top = min(entry, max(0, cm->nentries - MENU_ROWS));
81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Start with a clear screen */
81876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (clear) {
81976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* Clear and redraw whole screen */
82076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* Enable ASCII on G0 and DEC VT on G1; do it in this order
82176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       to avoid confusing the Linux console */
82276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (clear >= 2)
82376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		prepare_screen_for_menu();
82476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    clear_screen();
82576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    clear = 0;
82676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    prev_entry = prev_top = -1;
82776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
82876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
82976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (top != prev_top) {
83076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    draw_menu(entry, top, 1);
83176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    display_help(me->helptext);
83276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else if (entry != prev_entry) {
83376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    draw_row(prev_entry - top + 4 + VSHIFT, entry, top, 0, 0);
83476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    draw_row(entry - top + 4 + VSHIFT, entry, top, 0, 0);
83576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    display_help(me->helptext);
83676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
83776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
83876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	prev_entry = entry;
83976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	prev_top = top;
84076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cm->curentry = entry;
84176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cm->curtop = top;
84276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Cursor movement cancels timeout */
84476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (entry != cm->defentry)
84576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    key_timeout = 0;
84676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (key_timeout) {
84876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    int tol = timeout_left / CLK_TCK;
84976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    print_timeout_message(tol, TIMEOUT_ROW, cm->messages[MSG_AUTOBOOT]);
85076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    to_clear = 1;
85176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
85276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    to_clear = 0;
85376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
85476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (hotkey && me->immediate) {
85676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* If the hotkey was flagged immediate, simulate pressing ENTER */
85776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    key = KEY_ENTER;
85876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
85976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    this_timeout = min(min(key_timeout, timeout_left),
86076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			       (clock_t) CLK_TCK);
86176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    key = mygetkey(this_timeout);
86276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
86376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (key != KEY_NONE) {
86476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		timeout_left = key_timeout;
86576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (to_clear)
86676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    printf("\033[%d;1H\1#0\033[K", TIMEOUT_ROW);
86776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
86876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
86976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
87076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	hotkey = false;
87176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
87276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	switch (key) {
87376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_NONE:		/* Timeout */
87476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    /* This is somewhat hacky, but this at least lets the user
87576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       know what's going on, and still deals with "phantom inputs"
87676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       e.g. on serial ports.
87776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
87876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       Warning: a timeout will boot the default entry without any
87976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	       password! */
88076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (key_timeout) {
88176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (timeout_left <= this_timeout)
88276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    longjmp(timeout_jump, 1);
88376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
88476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		timeout_left -= this_timeout;
88576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
88676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
88776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
88876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('L'):
88976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    clear = 1;
89076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
89176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
89276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_ENTER:
89376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('J'):
89476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    key_timeout = 0;	/* Cancels timeout */
89576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (me->passwd) {
89676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		clear = 1;
89776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		done = ask_passwd(me->passwd);
89876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    } else {
89976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		done = 1;
90076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
90176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    cmdline = NULL;
90276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (done) {
90376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		switch (me->action) {
90476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		case MA_CMD:
90576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    cmdline = me->cmdline;
90676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    break;
90776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		case MA_SUBMENU:
90876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		case MA_GOTO:
90976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		case MA_EXIT:
91076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    done = 0;
91176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    clear = 2;
91276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    cm = me->submenu;
91376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    entry = cm->curentry;
91476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    top = cm->curtop;
91576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    break;
91676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		case MA_QUIT:
91776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    /* Quit menu system */
91876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    done = 1;
91976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    clear = 1;
92076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0);
92176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    break;
92276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		case MA_HELP:
92376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    key = show_message_file(me->cmdline, me->background);
92476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    /* If the exit was an F-key, display that help screen */
92576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    show_fkey(key);
92676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    done = 0;
92776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    clear = 1;
92876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    break;
92976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		default:
93076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    done = 0;
93176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    break;
93276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
93376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
93476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (done && !me->passwd) {
93576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		/* Only save a new default if we don't have a password... */
93676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (me->save && me->label) {
93776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    syslinux_setadv(ADV_MENUSAVE, strlen(me->label), me->label);
93876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    syslinux_adv_write();
93976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
94076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
94176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
94276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
94376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_UP:
94476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('P'):
94576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (entry > 0) {
94676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry--;
94776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (entry < top)
94876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    top -= MENU_ROWS;
94976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!is_disabled(cm->menu_entries[entry]))
95076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    break;
95176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
95276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
95376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
95476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_DOWN:
95576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('N'):
95676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (entry < cm->nentries - 1) {
95776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry++;
95876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (entry >= top + MENU_ROWS)
95976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    top += MENU_ROWS;
96076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!is_disabled(cm->menu_entries[entry]))
96176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    break;
96276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
96376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
96476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
96576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_PGUP:
96676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_LEFT:
96776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('B'):
96876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case '<':
96976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    entry -= MENU_ROWS;
97076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    top -= MENU_ROWS;
97176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (entry > 0 && is_disabled(cm->menu_entries[entry])) {
97276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry--;
97376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (entry < top)
97476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    top -= MENU_ROWS;
97576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
97676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
97776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
97876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_PGDN:
97976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_RIGHT:
98076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('F'):
98176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case '>':
98276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case ' ':
98376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    entry += MENU_ROWS;
98476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    top += MENU_ROWS;
98576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (entry < cm->nentries - 1
98676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   && is_disabled(cm->menu_entries[entry])) {
98776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry++;
98876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (entry >= top + MENU_ROWS)
98976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    top += MENU_ROWS;
99076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
99176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
99276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
99376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case '-':
99476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (entry > 0) {
99576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry--;
99676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		top--;
99776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!is_disabled(cm->menu_entries[entry]))
99876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    break;
99976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
100076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
100176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
100276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case '+':
100376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    while (entry < cm->nentries - 1) {
100476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry++;
100576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		top++;
100676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (!is_disabled(cm->menu_entries[entry]))
100776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    break;
100876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
100976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
101076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
101176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('A'):
101276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_HOME:
101376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    top = entry = 0;
101476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
101576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
101676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('E'):
101776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_END:
101876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    entry = cm->nentries - 1;
101976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    top = max(0, cm->nentries - MENU_ROWS);
102076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
102176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
102276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F1:
102376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F2:
102476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F3:
102576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F4:
102676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F5:
102776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F6:
102876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F7:
102976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F8:
103076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F9:
103176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F10:
103276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F11:
103376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_F12:
103476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    show_fkey(key);
103576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    clear = 1;
103676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
103776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
103876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_TAB:
103976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cm->allowedit && me->action == MA_CMD) {
104076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		int ok = 1;
104176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
104276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		key_timeout = 0;	/* Cancels timeout */
104376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0);
104476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
104576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (cm->menu_master_passwd) {
104676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    ok = ask_passwd(NULL);
104776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    clear_screen();
104876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    draw_menu(-1, top, 0);
104976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		} else {
105076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    /* Erase [Tab] message and help text */
105176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    printf("\033[%d;1H\1#0\033[K", TABMSG_ROW);
105276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    display_help(NULL);
105376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
105476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
105576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (ok) {
105676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    cmdline = edit_cmdline(me->cmdline, top);
105776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    done = !!cmdline;
105876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    clear = 1;	/* In case we hit [Esc] and done is null */
105976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		} else {
106076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    draw_row(entry - top + 4 + VSHIFT, entry, top, 0, 0);
106176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
106276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
106376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
106476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_CTRL('C'):	/* Ctrl-C */
106576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	case KEY_ESC:		/* Esc */
106676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cm->parent) {
106776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		cm = cm->parent;
106876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		clear = 2;
106976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		entry = cm->curentry;
107076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		top = cm->curtop;
107176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    } else if (cm->allowedit) {
107276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		done = 1;
107376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		clear = 1;
107476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		key_timeout = 0;
107576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
107676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0);
107776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
107876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (cm->menu_master_passwd)
107976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    done = ask_passwd(NULL);
108076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
108176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
108276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	default:
108376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (key > 0 && key < 0xFF) {
108476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		key &= ~0x20;	/* Upper case */
108576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		if (cm->menu_hotkeys[key]) {
108676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    key_timeout = 0;
108776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    entry = cm->menu_hotkeys[key]->entry;
108876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    /* Should we commit at this point? */
108976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		    hotkey = true;
109076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		}
109176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
109276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    break;
109376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
109476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
109576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
109676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    printf("\033[?25h");	/* Show cursor */
109776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
109876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Return the label name so localboot and ipappend work */
109976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return cmdline;
110076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
110176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
110276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint main(int argc, char *argv[])
110376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
110476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    const char *cmdline;
110576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct menu *m;
110676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int rows, cols;
110776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int i;
110876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
110976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    (void)argc;
111076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
111176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    parse_configs(argv + 1);
111276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
111376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /*
111476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * We don't start the console until we have parsed the configuration
111576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * file, since the configuration file might impact the console
111676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * configuration, e.g. MENU RESOLUTION.
111776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     */
111876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    start_console();
111976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (getscreensize(1, &rows, &cols)) {
112076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* Unknown screen size? */
112176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rows = 24;
112276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cols = 80;
112376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
112476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
112576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Some postprocessing for all menus */
112676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (m = menu_list; m; m = m->next) {
112776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!m->mparm[P_WIDTH])
112876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    m->mparm[P_WIDTH] = cols;
112976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
113076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	/* If anyone has specified negative parameters, consider them
113176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	   relative to the bottom row of the screen. */
113276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	for (i = 0; i < NPARAMS; i++)
113376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (m->mparm[i] < 0)
113476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		m->mparm[i] = max(m->mparm[i] + rows, 0);
113576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
113676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
113776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    cm = start_menu;
113876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
113976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!cm->nentries) {
114076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	fputs("Initial menu has no LABEL entries!\n", stdout);
114176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return 1;		/* Error! */
114276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
114376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
114476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for (;;) {
114576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	local_cursor_enable(true);
114676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cmdline = run_menu();
114776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
114876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (clearmenu)
114976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    clear_screen();
115076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
115176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	local_cursor_enable(false);
115276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	printf("\033[?25h\033[%d;1H\033[0m", END_ROW);
115376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
115476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (cmdline) {
115576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    uint32_t type = parse_image_type(cmdline);
115676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
115776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    execute(cmdline, type, false);
115876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if (cm->onerror) {
115976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		type = parse_image_type(cm->onerror);
116076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		execute(cm->onerror, type, true);
116176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
116276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	} else {
116376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    return 0;		/* Exit */
116476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
116576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
116676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
1167