Hello, here is a patch to make the dumb serial support "more dumb". Not not only single keys pressed leads to reaction, the user has to push <ENTER> after a command key. With this change, the GRUB menu can also be used on cannonical terminals (with some restrictions to the command line editing, where I have nothing changed).
Short description: When after booting the timeout runs, the usercan select the highlighted (default) menu entry simple with <ENTER>. When a user want to boot a different entry, simple use <num><ENTER>, for example `3<ENTER>'. To go to command line interface, use `c<ENTER>'. To edit menu entry 1, simple use `e1<ENTER>'. The editing fiunctions `d', `o', `O' are also used with argument, like `o0<ENTER>' inserts a line after the first one. With `u<ENTER>' the user can back to main menu (instead of <ESC>). With `b<ENTER>' the user can boot the current edited boot sequence. The patch is quite simple. Instead of fetching only a single character from the serial line, a small parser gets the whole user entry, parses that, and sets `c' and eventually `entryno' to the appropriate values. For the rest of the menu processing this is completely transparent and therefore the code is untouched. Only the bey explanations below the menu have been changed for dumb serial support. The feature concerning the password I have not tested, but it should work in the same way (pressing `p<ENTER>'). The command line editing is not changed. For editing lines `emacs' is usable but not convinient. But at the moment, I don't think, that we should change here anything. I like the current version of the command line interface. The seriel support without `--dumb' options is not affected by the patch. With friendly regards Christoph P. -- ------------------------------------------------------- private: [EMAIL PROTECTED] company: [EMAIL PROTECTED]
Index: ChangeLog =================================================================== RCS file: /cvs/grub/ChangeLog,v retrieving revision 1.460 diff -u -r1.460 ChangeLog --- ChangeLog 8 Jan 2002 03:19:23 -0000 1.460 +++ ChangeLog 12 Jan 2002 15:36:17 -0000 @@ -1,3 +1,9 @@ +2002-01-12 C. Plattner <[EMAIL PROTECTED]> + + * stage2/stage2.c (run_menu): added command line parser + for a changed DUMB terminal support menu usage under + `emacs' and more simple for `expect', etc. + 2002-01-08 Yoshinori K. Okuji <[EMAIL PROTECTED]> * grub/main.c (use_preset_menu): New variable. Index: stage2/stage2.c =================================================================== RCS file: /cvs/grub/stage2/stage2.c,v retrieving revision 1.35 diff -u -r1.35 stage2.c --- stage2/stage2.c 8 Jan 2002 03:19:23 -0000 1.35 +++ stage2/stage2.c 12 Jan 2002 15:36:20 -0000 @@ -426,43 +426,63 @@ if (terminal & TERMINAL_DUMB) print_entries_raw (num_entries, first_entry, menu_entries); - - grub_printf ("\n\ + else + grub_printf ("\n\ Use the %c and %c keys to select which entry is highlighted.\n", disp_up, disp_down); - - if (! auth && password) + + if (terminal & TERMINAL_DUMB) { - printf ("\ - Press enter to boot the selected OS or \'p\' to enter a\n\ - password to unlock the next set of features."); + if (! auth && password) + { + printf ("\ + Press \'<NUM>\' and enter to boot an OS or \'p\' and enter\n\ + to enter a password to unlock the next set of features."); + } + else + { + if (config_entries) + printf ("\ + Press \'<NUM>\' and enter to boot an OS, \'e<NUM>\' to edit\n\ + the commands before booting, or \'c\' for a command-line.\n\n"); + else + printf ("\ + Press \'b\' to boot, \'e<NUM>' to edit the command in the\n\ + boot sequence, \'c\' for command-line, \'o<NUM>\' to open a\n\ + new line after (\'O<NUM>\' for before) the selected line, \n\ + \'d<NUM>\' to remove a line or \'u\' to go back to main menu.\n"); + } } else { - if (config_entries) - printf ("\ + if (! auth && password) + { + printf ("\ + Press enter to boot the selected OS or \'p\' to enter a\n\ + password to unlock the next set of features."); + } + else + { + if (config_entries) + printf ("\ Press enter to boot the selected OS, \'e\' to edit the\n\ commands before booting, or \'c\' for a command-line."); - else - printf ("\ + else + printf ("\ Press \'b\' to boot, \'e\' to edit the selected command in the\n\ boot sequence, \'c\' for a command-line, \'o\' to open a new line\n\ after (\'O\' for before) the selected line, \'d\' to remove the\n\ selected line, or escape to go back to the main menu."); - } - - if (terminal & TERMINAL_DUMB) - grub_printf ("\n\nThe selected entry is %d ", entryno); - else - { + } + print_entries (3, 12, first_entry, menu_entries); /* highlight initial line */ set_line_highlight (4 + entryno, first_entry + entryno, menu_entries); - } + } } - + /* XX using RT clock now, need to initialize value */ while ((time1 = getrtsecs()) == 0xFF); @@ -506,9 +526,193 @@ since we're comming in here also on GRUB_TIMEOUT == -1 and hang in GETKEY */ if (terminal & TERMINAL_DUMB) - grub_printf ("\r Highlighted entry is %d: ", entryno); + grub_printf ("\n select: "); - c = translate_keycode (getkey ()); + /* For DUMB terminal support, do complete line parsing, + setup the entry number and set an apporpriate 'c' */ + + if (! (terminal & TERMINAL_DUMB)) + c = translate_keycode (getkey ()); + else + { +#define DUMB_BUFLEN 32 + char dumb_buf [DUMB_BUFLEN + 1]; /* space for '\0' */ + int dumb_pos; + int dumb_sel; + char * dumb_p; + int c1; + int spaces; + int dumb_abort; + int dumb_empty; + + /* editing function only very simple with ^H */ + dumb_buf [0] = 0; + dumb_pos = 0; + + c = 0; /* ignore key */ + do + { + c1 = translate_keycode (getkey ()); + switch (c1) + { + case '\r': + case '\n': + dumb_buf [dumb_pos] = 0; + grub_putchar ('\n'); + c1 = '\r'; + break; + case '\b': + if (dumb_pos > 0) + { + dumb_pos --; + grub_printf ("\b \b"); + } + break; + default: + /* check for printable characters */ + if ((c1 >= ' ') && (c1 < 127)) + { + if ((dumb_pos + 1) < DUMB_BUFLEN) + { + dumb_buf [dumb_pos ++] = c1; + grub_putchar (c1); + } + /* else ignore key stroke */ + } + } + } while (c1 != '\r'); + + /* parse the string */ + dumb_sel = -1; + spaces = 0; + dumb_abort = 0; + dumb_empty = 1; + + dumb_p = dumb_buf; + while ((* dumb_p) && (dumb_abort == 0)) + { + dumb_empty = 0; + switch (* dumb_p) + { + case ' ': + spaces = 1; + break; + case 'p': + if ((c == 0) && (dumb_sel == -1) && (! auth && password)) + c = * dumb_p; + else + { + grub_printf ("Error: invalid command\n"); + dumb_abort = 1; + } + break; + case 'c': + case 'e': + if ((c == 0) && (dumb_sel == -1)) + c = * dumb_p; + else + { + grub_printf ("Error: invalid command\n"); + dumb_abort = 1; + } + break; + case 'b': + case 'd': + case 'o': + case 'O': + case 'u': + if ((c == 0) && (! config_entries) && (dumb_sel == -1)) + c = (* dumb_p == 'u') ? 0x1b : * dumb_p; + else + { + grub_printf ("Error: invalid command\n"); + dumb_abort = 1; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (spaces && (dumb_sel != -1)) + { + grub_printf ("Error: too many arguments\n"); + dumb_abort = 1; + } + else + { + if (dumb_sel == -1) + dumb_sel = (* dumb_p) - '0'; + else + dumb_sel = (dumb_sel * 10) + ((* dumb_p) - '0'); + spaces = 0; + } + break; + default: + grub_printf ("Error: invalid command\n"); + dumb_abort = 1; + break; + } + dumb_p ++; + } + + if (dumb_abort) + c = 0; + else + { + if (dumb_sel == -1) + { + /* for the commands e,d,o,O the selection number is + mandatory */ + if ((c == 'e') || (c == 'd') || (c == 'o') || (c == 'O')) + { + grub_printf ("Error: Selection number must " + "be given\n"); + c = 0; + } + /* check if we have an empty input string, then + the default selection is done, if timeout is + not expired, otherwise ignore command */ + if ((dumb_empty) && (grub_timeout >= 0)) + { + grub_printf (" selected was %d\n", entryno); + c = '\r'; + } + } + else + { + /* check if commands take a parameter */ + if ((c == 'c') || (c == 0x1b) || + (c == 'p') || (c == 'b')) + { + grub_printf ("Error: too many arguments\n"); + c = 0; + } + else + { + if (dumb_sel >= num_entries) + { + grub_printf ("Error: Selection number %d " + "invalid\n", dumb_sel); + c = 0; + } + else + { + entryno = dumb_sel; + /* if user has not given any command letter, + we assume a simple selection, c -> '\n' */ + if (c == 0) + c = '\n'; + } + } + } + } + } if (grub_timeout >= 0) {