menu=Start MINIX 3:load_mods /boot/minix_default/mod*;multiboot /boot/minix_default/kernel rootdevname=$rootdevname
menu=Start latest MINIX 3:load_mods /boot/minix_latest/mod*;multiboot /boot/minix_latest/kernel rootdevname=$rootdevname
menu=Start latest MINIX 3 in single user mode:load_mods /boot/minix_latest/mod*;multiboot /boot/minix_latest/kernel rootdevname=$rootdevname bootopts=-s
+menu=Edit menu option:edit
menu=Drop to boot prompt:prompt
and so can be any valid command that would be accepted at the
normal boot prompt.
In addition,
+.Dq Ic edit
+can be used to put the menu in editing mode, allowing the user to modify the
+next selected option before executing it, and
.Dq Ic prompt
can be used to drop to the normal boot prompt.
.It Sy timeout
banner================================================================================
banner=
menu=Regular MINIX 3:multiboot /kernel bootcd=1 cdproberoot=1 rootdevname=ram disable=inet
+menu=Edit menu option:edit
menu=Drop to boot prompt:prompt
clear=1
timeout=10
cat >$RELEASEMNTDIR/boot.cfg <<END_BOOT_CFG
menu=Regular MINIX 3:load_mods /boot/minix_default/mod*;multiboot /boot/minix_default/kernel bootcd=2 disable=inet bios_wini=yes bios_remap_first=1 ramimagedev=c0d7p0s0
+menu=Edit menu option:edit
menu=Drop to boot prompt:prompt
clear=1
timeout=10
echo \
cat >$RELEASEMNTDIR/boot.cfg <<END_BOOT_CFG
menu=Regular MINIX 3:load_mods /boot/minix_default/mod*;multiboot /boot/minix_default/kernel bios_wini=yes bios_remap_first=1 rootdevname=c0d7p0s0
+menu=Edit menu option:edit
menu=Drop to boot prompt:prompt
clear=1
timeout=10
return choice;
}
-void
-doboottypemenu(void)
+static void
+showmenu(void)
{
int choice;
- char input[80], *ic, *oc;
printf("\n");
/* Display menu */
choice + 1,
bootconf.desc[choice]);
}
+}
+
+void
+doboottypemenu(void)
+{
+ int choice, editing;
+ char input[256], *ic, *oc;
+
+ showmenu();
choice = -1;
+ editing = 0;
for (;;) {
input[0] = '\0';
if (bootconf.timeout < 0) {
if (bootconf.menuformat == MENUFORMAT_LETTER)
- printf("\nOption: [%c]:",
+ printf("\nOption%s: [%c]:",
+ editing ? " (edit)" : "",
bootconf.def + 'A');
else
- printf("\nOption: [%d]:",
+ printf("\nOption%s: [%d]:",
+ editing ? " (edit)" : "",
bootconf.def + 1);
- gets(input);
+ editline(input, sizeof(input), NULL);
choice = getchoicefrominput(input, bootconf.def);
} else if (bootconf.timeout == 0)
choice = bootconf.def;
}
if (choice < 0)
continue;
- if (!strcmp(bootconf.command[choice], "prompt") &&
+ ic = bootconf.command[choice];
+ if (editing) {
+ printf("> ");
+ editline(input, sizeof(input), ic);
+ ic = input;
+ }
+ if (!strcmp(ic, "edit") &&
+ ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 ||
+ check_password((char *)boot_params.bp_password))) {
+ editing = 1;
+ bootconf.timeout = -1;
+ } else if (!strcmp(ic, "prompt") &&
((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 ||
check_password((char *)boot_params.bp_password))) {
- printf("type \"?\" or \"help\" for help.\n");
- bootmenu(); /* does not return */
+ printf("type \"?\" or \"help\" for help, "
+ "or \"menu\" to return to the menu.\n");
+ prompt(1);
+ showmenu();
+ editing = 0;
+ bootconf.timeout = -1;
} else {
- ic = bootconf.command[choice];
/* Split command string at ; into separate commands */
do {
+ /*
+ * This must support inline editing, since ic
+ * may also point to input.
+ */
oc = input;
/* Look for ; separator */
for (; *ic && *ic != COMMAND_SEPARATOR; ic++)
*oc++ = *ic;
- if (*input == '\0')
+ if (*ic == COMMAND_SEPARATOR)
+ ic++;
+ if (oc == input)
continue;
/* Strip out any trailing spaces */
oc--;
for (; *oc == ' ' && oc > input; oc--);
*++oc = '\0';
- if (*ic == COMMAND_SEPARATOR)
- ic++;
/* Stop silly command strings like ;;; */
if (*input != '\0')
docommand(input);
call _C_LABEL(prot_to_real) # enter real mode
.code16
+ cmp $0x08, %al # backspace?
+ jne print_char
+
+ # Multiline backspace support.
+ push %ax
+ movb $0x3, %ah # get cursor position
+ xorw %bx, %bx
+ int $0x10
+ pop %ax
+ testb %dl, %dl # cursor on first column?
+ jnz print_char
+ testb %dh, %dh # cursor not on first row?
+ jz print_char
+ decb %dh # move up one row
+ movb $0x4f, %dl # move to last column
+ xorw %bx, %bx
+ movb $0x02, %ah # set cursor position
+ jmp do_int
+
+print_char:
movw $1,%bx
- movb $0x0e,%ah
+ movb $0x0e,%ah # print character
movb %al, %cl
+do_int:
int $0x10
calll _C_LABEL(real_to_prot) # back to protected mode
movb $0x0,%ah
int $0x16
- movb %al,%bl
+ movw %ax,%bx
calll _C_LABEL(real_to_prot) # back to protected mode
.code32
- movb %bl, 28(%esp)
+ movw %bx, 28(%esp)
popa
ret
void (*c_fn)(char *);
};
void bootmenu(void);
+void prompt(int);
void docommand(char *);
+void editline(char *, size_t, char *);
/* in "user code": */
void command_help(char *);
__compactcall void conputc(int);
void conclr(void);
+int getchar_ex(void);
+
int getextmem2(int *);
__compactcall int getextmemps2(void *);
int getmementry(int *, int *);
}
void
-bootmenu(void)
+prompt(int allowreturn)
{
char input[80];
for (;;) {
char *c = input;
- input[0] = '\0';
printf("> ");
- gets(input);
+ editline(input, sizeof(input), NULL);
/*
* Skip leading whitespace.
*/
while (*c == ' ')
c++;
+ if (allowreturn && !strcmp(c, "menu"))
+ break;
if (*c)
docommand(c);
}
}
+
+void
+bootmenu(void)
+{
+ prompt(0);
+}
+
+/* Derived from libsa gets(). */
+void
+editline(char *buf, size_t size, char *input)
+{
+ int c, i, pos, len = 0;
+
+ /* If an initial input has been given, copy and print this first. */
+ if (input != NULL) {
+ while (*input && len < size - 1)
+ putchar(buf[len++] = *input++);
+ }
+ pos = len;
+
+ for (;;) {
+ c = getchar_ex();
+ switch (c & 0177) {
+ case '\0':
+ switch (c) {
+ case 0x4b00: /* Left arrow: move cursor to left. */
+ if (pos > 0) {
+ putchar('\b');
+ pos--;
+ }
+ break;
+ case 0x4d00: /* Right arrow: move cursor to right. */
+ if (pos < len) putchar(buf[pos++]);
+ break;
+ }
+ break;
+ case 'b' & 037: /* Ctrl+B: move cursor to left. */
+ if (pos > 0) {
+ putchar('\b');
+ pos--;
+ }
+ break;
+ case 'f' & 037: /* Ctrl+F: move cursor to right. */
+ if (pos < len) putchar(buf[pos++]);
+ break;
+ case 'a' & 037: /* Ctrl+A: move cursor to start of line. */
+ for ( ; pos > 0; pos--) putchar('\b');
+ break;
+ case 'e' & 037: /* Ctrl+E: move cursor to end of line. */
+ for ( ; pos < len; pos++) putchar(buf[pos]);
+ break;
+ case '\n': /* Enter: return line. */
+ case '\r':
+ for ( ; pos < len; pos++) putchar(buf[pos]);
+ buf[len] = '\0';
+ putchar('\n');
+ return;
+#if HASH_ERASE
+ case '#':
+#endif
+ case '\b': /* Backspace: erase character before cursor. */
+ case '\177':
+ if (pos > 0) {
+ pos--;
+ len--;
+ putchar('\b');
+ for (i = pos; i < len; i++)
+ putchar(buf[i] = buf[i + 1]);
+ putchar(' ');
+ for (i = pos; i < len; i++) putchar('\b');
+ putchar('\b');
+ }
+ break;
+ case 'r' & 037: /* Ctrl+R: reprint line. */
+ putchar('\n');
+ for (i = 0; i < len; i++) putchar(buf[i]);
+ for (i = len; i > pos; i--) putchar('\b');
+ break;
+#if AT_ERASE
+ case '@':
+#endif
+ case 'u' & 037: /* Ctrl+U: clear entire line. */
+ case 'w' & 037:
+ for ( ; pos > 0; pos--) putchar('\b');
+ for ( ; pos < len; pos++) putchar(' ');
+ for ( ; pos > 0; pos--) putchar('\b');
+ len = 0;
+ break;
+ case '\a': /* Ctrl+G: sound bell but do not store character. */
+ putchar(c);
+ break;
+ case '\t': /* Tab: convert to single space. */
+ c = ' ';
+ /*FALLTHROUGH*/
+ default: /* Insert character at cursor position. */
+ if (len < size - 1) {
+ for (i = len; i > pos; i--)
+ buf[i] = buf[i - 1];
+ buf[pos] = c;
+ pos++;
+ len++;
+ putchar(c);
+ for (i = pos; i < len; i++) putchar(buf[i]);
+ for (i = pos; i < len; i++) putchar('\b');
+ } else {
+ putchar('\a');
+ }
+ break;
+ }
+ }
+ /*NOTREACHED*/
+}
}
int
-getchar(void)
+getchar_ex(void)
{
int c;
#ifdef SUPPORT_SERIAL
c = congetc();
#ifdef CONSOLE_KEYMAP
{
- char *cp = strchr(CONSOLE_KEYMAP, c);
+ char *cp = strchr(CONSOLE_KEYMAP, c & 0xff);
if (cp != 0 && cp[1] != 0)
- c = cp[1];
+ c = cp[1] | (c & 0xff00);
}
#endif
return c;
#endif /* SUPPORT_SERIAL */
}
+int
+getchar(void)
+{
+ return getchar_ex() & 0xff;
+}
+
int
iskey(int intr)
{