Increase number of menu options to 20.

Add support for switching menu format between numbers and letters. Will
prefer numbers, but will automatically switch to letters if > 9 options
and timeout > 0 (i.e. need a single key press to choose).
Menu format can be explicitly set in boot.cfg file.
Add support for reading numeric choices of more than 1 digit.
This commit is contained in:
sborrill 2008-08-12 17:56:05 +00:00
parent 094d45b30f
commit c7b0526b9b

View File

@ -1,4 +1,4 @@
/* $NetBSD: boot2.c,v 1.33 2008/08/08 07:48:32 simonb Exp $ */ /* $NetBSD: boot2.c,v 1.34 2008/08/12 17:56:05 sborrill Exp $ */
/*- /*-
* Copyright (c) 2008 The NetBSD Foundation, Inc. * Copyright (c) 2008 The NetBSD Foundation, Inc.
@ -108,7 +108,7 @@ static const char * const names[][2] = {
#ifndef SMALL #ifndef SMALL
#define BOOTCONF "boot.cfg" #define BOOTCONF "boot.cfg"
#define MAXMENU 10 #define MAXMENU 20
#define MAXBANNER 12 #define MAXBANNER 12
#define COMMAND_SEPARATOR ';' #define COMMAND_SEPARATOR ';'
#endif /* !SMALL */ #endif /* !SMALL */
@ -151,6 +151,11 @@ const struct bootblk_command commands[] = {
}; };
#ifndef SMALL #ifndef SMALL
#define MENUFORMAT_AUTO 0
#define MENUFORMAT_NUMBER 1
#define MENUFORMAT_LETTER 2
struct bootconf_def { struct bootconf_def {
char *banner[MAXBANNER]; /* Banner text */ char *banner[MAXBANNER]; /* Banner text */
char *command[MAXMENU]; /* Menu commands per entry*/ char *command[MAXMENU]; /* Menu commands per entry*/
@ -159,6 +164,7 @@ struct bootconf_def {
char *desc[MAXMENU]; /* Menu text per entry */ char *desc[MAXMENU]; /* Menu text per entry */
int nummenu; /* Number of menu items */ int nummenu; /* Number of menu items */
int timeout; /* Timeout in seconds */ int timeout; /* Timeout in seconds */
int menuformat; /* Print letters instead of numbers? */
} bootconf; } bootconf;
#endif /* !SMALL */ #endif /* !SMALL */
@ -305,7 +311,7 @@ atoi(const char *in)
* (if present) and populates the global boot configuration. * (if present) and populates the global boot configuration.
* *
* The file consists of a number of lines each terminated by \n * The file consists of a number of lines each terminated by \n
* The lines are in the format keyword=value. There should be spaces * The lines are in the format keyword=value. There should not be spaces
* around the = sign. * around the = sign.
* *
* The recognised keywords are: * The recognised keywords are:
@ -314,6 +320,7 @@ atoi(const char *in)
* timeout: Timeout in seconds (overrides that set by installboot) * timeout: Timeout in seconds (overrides that set by installboot)
* default: the default menu option to use if Return is pressed * default: the default menu option to use if Return is pressed
* consdev: the console device to use * consdev: the console device to use
* format: how menu choices are displayed: (a)utomatic, (n)umbers or (l)etters
* *
* Example boot.cfg file: * Example boot.cfg file:
* banner=Welcome to NetBSD * banner=Welcome to NetBSD
@ -344,6 +351,9 @@ parsebootconf(const char *conf)
/* Set timeout to configured */ /* Set timeout to configured */
bootconf.timeout = boot_params.bp_timeout; bootconf.timeout = boot_params.bp_timeout;
/* automatically switch between letter and numbers on menu */
bootconf.menuformat = MENUFORMAT_AUTO;
/* don't try to open BOOTCONF if the target fs is ustarfs */ /* don't try to open BOOTCONF if the target fs is ustarfs */
#ifdef SUPPORT_USTARFS #ifdef SUPPORT_USTARFS
#if !defined(LIBSA_SINGLE_FILESYSTEM) #if !defined(LIBSA_SINGLE_FILESYSTEM)
@ -442,10 +452,44 @@ parsebootconf(const char *conf)
bootconf.def = atoi(value) - 1; bootconf.def = atoi(value) - 1;
} else if (!strncmp(key, "consdev", 7)) { } else if (!strncmp(key, "consdev", 7)) {
bootconf.consdev = value; bootconf.consdev = value;
} else if (!strncmp(key, "load", 6)) { } else if (!strncmp(key, "load", 4)) {
command_load(value); command_load(value);
} else if (!strncmp(key, "format", 6)) {
printf("value:%c\n", *value);
switch (*value) {
case 'a':
case 'A':
bootconf.menuformat = MENUFORMAT_AUTO;
break;
case 'n':
case 'N':
case 'd':
case 'D':
bootconf.menuformat = MENUFORMAT_NUMBER;
break;
case 'l':
case 'L':
bootconf.menuformat = MENUFORMAT_LETTER;
break;
}
} }
} }
switch (bootconf.menuformat) {
case MENUFORMAT_AUTO:
if (cmenu > 9 && bootconf.timeout > 0)
bootconf.menuformat = MENUFORMAT_LETTER;
else
bootconf.menuformat = MENUFORMAT_NUMBER;
break;
case MENUFORMAT_NUMBER:
if (cmenu > 9 && bootconf.timeout > 0)
cmenu = 9;
break;
}
bootconf.nummenu = cmenu; bootconf.nummenu = cmenu;
if (bootconf.def < 0) if (bootconf.def < 0)
bootconf.def = 0; bootconf.def = 0;
@ -457,46 +501,74 @@ parsebootconf(const char *conf)
* doboottypemenu will render the menu and parse any user input * doboottypemenu will render the menu and parse any user input
*/ */
static int getchoicefrominput(char *input, int def)
{
int choice;
choice = -1;
if (*input == '\0' || *input == '\r' || *input == '\n')
choice = def;
else if (*input >= 'A' && *input < bootconf.nummenu + 'A')
choice = (*input) - 'A';
else if (*input >= 'a' && *input < bootconf.nummenu + 'a')
choice = (*input) - 'a';
else if (isnum(*input)) {
choice = atoi(input) - 1;
if (choice < 0 || choice >= bootconf.nummenu)
choice = -1;
}
return choice;
}
void void
doboottypemenu(void) doboottypemenu(void)
{ {
int choice; int choice;
char input[80], c, *ic, *oc; char input[80], *ic, *oc;
printf("\n"); printf("\n");
/* Display menu */ /* Display menu */
for (choice = 0; choice < bootconf.nummenu; choice++) if (bootconf.menuformat == MENUFORMAT_LETTER) {
printf(" %d. %s\n", choice+1, bootconf.desc[choice]); for (choice = 0; choice < bootconf.nummenu; choice++)
printf(" %c. %s\n", choice + 'A',
bootconf.desc[choice]);
} else {
/* Can't use %2d format string with libsa */
for (choice = 0; choice < bootconf.nummenu; choice++)
printf(" %s%d. %s\n",
(choice < 9) ? " " : "",
choice + 1,
bootconf.desc[choice]);
}
choice = -1; choice = -1;
for(;;) { for(;;) {
input[0] = '\0'; input[0] = '\0';
if (bootconf.timeout < 0) { if (bootconf.timeout < 0) {
printf("\nOption: [%d]:", bootconf.def + 1); if (bootconf.menuformat == MENUFORMAT_LETTER)
printf("\nOption: [%c]:",
bootconf.def + 'A');
else
printf("\nOption: [%d]:",
bootconf.def + 1);
gets(input); gets(input);
if (input[0] == '\0') choice = bootconf.def; choice = getchoicefrominput(input, bootconf.def);
if (input[0] >= '1' &&
input[0] <= bootconf.nummenu + '0')
choice = input[0] - '1';
} else if (bootconf.timeout == 0) } else if (bootconf.timeout == 0)
choice = bootconf.def; choice = bootconf.def;
else { else {
printf("\nChoose an option; RETURN for default; " printf("\nChoose an option; RETURN for default; "
"SPACE to stop countdown.\n"); "SPACE to stop countdown.\n");
printf("Option %d will be chosen in ", if (bootconf.menuformat == MENUFORMAT_LETTER)
bootconf.def + 1); printf("Option %d will be chosen in ",
c = awaitkey(bootconf.timeout, 1); bootconf.def + 1);
if (c >= '1' && c <= bootconf.nummenu + '0') printf("Option %c will be chosen in ",
choice = c - '1'; bootconf.def + 'A');
else if (c == '\r' || c == '\n' || c == '\0') input[0] = awaitkey(bootconf.timeout, 1);
/* default if timed out or Return pressed */ input[1] = '\0';
choice = bootconf.def; choice = getchoicefrominput(input, bootconf.def);
else { /* If invalid key pressed, drop to menu */
/* If any other key pressed, drop to menu */ if (choice == -1)
bootconf.timeout = -1; bootconf.timeout = -1;
choice = -1;
}
} }
if (choice < 0) if (choice < 0)
continue; continue;