1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2007 H. Peter Anvin - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
16 * Simple menu system which displays a list and allows the user to select
17 * a command line and/or edit it.
20 #define _GNU_SOURCE /* Needed for asprintf() on Linux */
39 * The color/attribute indexes (\1#X, \2#XX, \3#XXX) are as follows
41 * 00 - screen Rest of the screen
42 * 01 - border Border area
43 * 02 - title Title bar
44 * 03 - unsel Unselected menu item
45 * 04 - hotkey Unselected hotkey
46 * 05 - sel Selection bar
47 * 06 - hotsel Selected hotkey
48 * 07 - scrollbar Scroll bar
49 * 08 - tabmsg Press [Tab] message
50 * 09 - cmdmark Command line marker
51 * 10 - cmdline Command line
52 * 11 - pwdborder Password box border
53 * 12 - pwdheader Password box header
54 * 13 - pwdentry Password box contents
55 * 14 - timeout_msg Timeout message
56 * 15 - timeout Timeout counter
57 * 16 - help Current entry help text
60 static const struct color_table default_color_table
[] = {
61 { "screen", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL
},
62 { "border", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL
},
63 { "title", "1;36;44", 0xc00090f0, 0x00000000, SHADOW_NORMAL
},
64 { "unsel", "37;44", 0x90ffffff, 0x00000000, SHADOW_NORMAL
},
65 { "hotkey", "1;37;44", 0xffffffff, 0x00000000, SHADOW_NORMAL
},
66 { "sel", "7;37;40", 0xe0000000, 0x20ff8000, SHADOW_ALL
},
67 { "hotsel", "1;7;37;40", 0xe0400000, 0x20ff8000, SHADOW_ALL
},
68 { "scrollbar", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL
},
69 { "tabmsg", "31;40", 0x90ffff00, 0x00000000, SHADOW_NORMAL
},
70 { "cmdmark", "1;36;40", 0xc000ffff, 0x00000000, SHADOW_NORMAL
},
71 { "cmdline", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL
},
72 { "pwdborder", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL
},
73 { "pwdheader", "31;47", 0x80ff8080, 0x20ffffff, SHADOW_NORMAL
},
74 { "pwdentry", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL
},
75 { "timeout_msg", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL
},
76 { "timeout", "1;37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL
},
77 { "help", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL
},
80 #define NCOLORS (sizeof default_color_table/sizeof(struct color_table))
81 const int message_base_color
= NCOLORS
;
83 struct menu_parameter mparm
[] = {
86 { "passwordmargin", 3 },
91 { "passwordrow", 11 },
94 { "helpmsgendrow", -1 },
101 #define WIDTH mparm[0].value
102 #define MARGIN mparm[1].value
103 #define PASSWD_MARGIN mparm[2].value
104 #define MENU_ROWS mparm[3].value
105 #define TABMSG_ROW (mparm[4].value+VSHIFT)
106 #define CMDLINE_ROW (mparm[5].value+VSHIFT)
107 #define END_ROW mparm[6].value
108 #define PASSWD_ROW (mparm[7].value+VSHIFT)
109 #define TIMEOUT_ROW (mparm[8].value+VSHIFT)
110 #define HELPMSG_ROW (mparm[9].value+VSHIFT)
111 #define HELPMSGEND_ROW mparm[10].value
112 #define HSHIFT mparm[11].value
113 #define VSHIFT mparm[12].value
114 #define HIDDEN_ROW mparm[13].value
116 void set_msg_colors_global(unsigned int fg
, unsigned int bg
,
117 enum color_table_shadow shadow
)
119 struct color_table
*cp
= console_color_table
+message_base_color
;
121 unsigned int fga
, bga
;
122 unsigned int fgh
, bgh
;
123 unsigned int fg_idx
, bg_idx
;
124 unsigned int fg_rgb
, bg_rgb
;
126 static const unsigned int pc2rgb
[8] =
127 { 0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00,
130 /* Converting PC RGBI to sensible RGBA values is an "interesting"
131 proposition. This algorithm may need plenty of tweaking. */
133 fga
= fg
& 0xff000000;
134 fgh
= ((fg
>> 1) & 0xff000000) | 0x80000000;
136 bga
= bg
& 0xff000000;
137 bgh
= ((bg
>> 1) & 0xff000000) | 0x80000000;
139 for (i
= 0; i
< 256; i
++) {
143 fg_rgb
= pc2rgb
[fg_idx
& 7] & fg
;
144 bg_rgb
= pc2rgb
[bg_idx
& 7] & bg
;
147 /* High intensity foreground */
154 /* Default black background, assume transparent */
156 } else if (bg_idx
& 8) {
162 cp
->argb_fg
= fg_rgb
;
163 cp
->argb_bg
= bg_rgb
;
170 install_default_color_table(void)
173 const struct color_table
*dp
;
174 struct color_table
*cp
;
175 static struct color_table color_table
[NCOLORS
+256];
176 static const int pc2ansi
[8] = {0, 4, 2, 6, 1, 5, 3, 7};
178 dp
= default_color_table
;
181 for (i
= 0; i
< NCOLORS
; i
++) {
183 free((void *)cp
->ansi
);
186 cp
->ansi
= strdup(dp
->ansi
);
192 for (i
= 0; i
< 256; i
++) {
194 asprintf((char **)&cp
->name
, "msg%02x", i
);
197 free((void *)cp
->ansi
);
199 asprintf((char **)&cp
->ansi
, "%s3%d;4%d", (i
& 8) ? "1;" : "",
200 pc2ansi
[i
& 7], pc2ansi
[(i
>> 4) & 7]);
205 console_color_table
= color_table
;
206 console_color_table_size
= NCOLORS
+256;
208 set_msg_colors_global(MSG_COLORS_DEF_FG
, MSG_COLORS_DEF_BG
,
209 MSG_COLORS_DEF_SHADOW
);
213 pad_line(const char *text
, int align
, int width
)
215 static char buffer
[MAX_CMDLINE_LEN
];
218 if ( width
>= (int) sizeof buffer
)
219 return NULL
; /* Can't do it */
225 memset(buffer
, ' ', width
);
227 p
= ((width
-n
)*align
)>>1;
228 memcpy(buffer
+p
, text
, n
);
233 /* Display an entry, with possible hotkey highlight. Assumes
234 that the current attribute is the non-hotkey one, and will
235 guarantee that as an exit condition as well. */
237 display_entry(const struct menu_entry
*entry
, const char *attrib
,
238 const char *hotattrib
, int width
)
240 const char *p
= entry
->displayname
;
246 if ( *p
&& ((unsigned char)*p
& ~0x20) == entry
->hotkey
) {
247 fputs(hotattrib
, stdout
);
249 fputs(attrib
, stdout
);
264 draw_row(int y
, int sel
, int top
, int sbtop
, int sbbot
)
266 int i
= (y
-4-VSHIFT
)+top
;
268 printf("\033[%d;%dH\1#1\016x\017%s ",
269 y
, MARGIN
+1+HSHIFT
, (i
== sel
) ? "\1#5" : "\1#3");
271 if ( i
>= nentries
) {
272 fputs(pad_line("", 0, WIDTH
-2*MARGIN
-4), stdout
);
274 display_entry(&menu_entries
[i
],
275 (i
== sel
) ? "\1#5" : "\1#3",
276 (i
== sel
) ? "\1#6" : "\1#4",
280 if ( nentries
<= MENU_ROWS
) {
281 printf(" \1#1\016x\017");
282 } else if ( sbtop
> 0 ) {
283 if ( y
>= sbtop
&& y
<= sbbot
)
284 printf(" \1#7\016a\017");
286 printf(" \1#1\016x\017");
288 putchar(' '); /* Don't modify the scrollbar */
292 static int passwd_compare_sha1(const char *passwd
, const char *entry
)
296 unsigned char sha1
[20], pwdsha1
[20];
298 if ( (p
= strchr(passwd
+3, '$')) ) {
299 SHA1Update(&ctx
, (void *)passwd
+3, p
-(passwd
+3));
302 p
= passwd
+3; /* Assume no salt */
307 SHA1Update(&ctx
, (void *)entry
, strlen(entry
));
308 SHA1Final(sha1
, &ctx
);
310 memset(pwdsha1
, 0, 20);
311 unbase64(pwdsha1
, 20, p
);
313 return !memcmp(sha1
, pwdsha1
, 20);
316 static int passwd_compare_md5(const char *passwd
, const char *entry
)
318 const char *crypted
= crypt_md5(entry
, passwd
+3);
319 int len
= strlen(crypted
);
321 return !strncmp(crypted
, passwd
, len
) &&
322 (passwd
[len
] == '\0' || passwd
[len
] == '$');
326 passwd_compare(const char *passwd
, const char *entry
)
328 if ( passwd
[0] != '$' ) /* Plaintext passwd, yuck! */
329 return !strcmp(entry
, passwd
);
330 else if ( !strncmp(passwd
, "$4$", 3) )
331 return passwd_compare_sha1(passwd
, entry
);
332 else if ( !strncmp(passwd
, "$1$", 3) )
333 return passwd_compare_md5(passwd
, entry
);
335 return 0; /* Invalid encryption algorithm */
338 static jmp_buf timeout_jump
;
340 int mygetkey(clock_t timeout
)
347 return get_key(stdin
, timeout
);
350 tto
= min(totaltimeout
, INT_MAX
);
351 to
= timeout
? min(tto
, timeout
) : tto
;
354 key
= get_key(stdin
, to
);
355 t
= times(NULL
) - t0
;
357 if ( totaltimeout
<= t
)
358 longjmp(timeout_jump
, 1);
362 if ( key
!= KEY_NONE
)
375 ask_passwd(const char *menu_entry
)
377 char user_passwd
[WIDTH
], *p
;
382 printf("\033[%d;%dH\2#11\016l", PASSWD_ROW
, PASSWD_MARGIN
+1);
383 for ( x
= 2 ; x
<= WIDTH
-2*PASSWD_MARGIN
-1 ; x
++ )
386 printf("k\033[%d;%dHx", PASSWD_ROW
+1, PASSWD_MARGIN
+1);
387 for ( x
= 2 ; x
<= WIDTH
-2*PASSWD_MARGIN
-1 ; x
++ )
390 printf("x\033[%d;%dHm", PASSWD_ROW
+2, PASSWD_MARGIN
+1);
391 for ( x
= 2 ; x
<= WIDTH
-2*PASSWD_MARGIN
-1 ; x
++ )
394 printf("j\017\033[%d;%dH\2#12 %s \033[%d;%dH\2#13",
395 PASSWD_ROW
, (WIDTH
-(strlen(messages
[MSG_PASSPROMPT
].msg
)+2))/2,
396 messages
[MSG_PASSPROMPT
].msg
, PASSWD_ROW
+1, PASSWD_MARGIN
+3);
398 /* Actually allow user to type a password, then compare to the SHA1 */
413 p
= user_passwd
; /* No password entered */
420 if ( p
> user_passwd
) {
427 while ( p
> user_passwd
) {
434 if ( key
>= ' ' && key
<= 0xFF &&
435 (p
-user_passwd
) < WIDTH
-2*PASSWD_MARGIN
-5 ) {
443 if ( p
== user_passwd
)
444 return 0; /* No password entered */
448 return (menu_master_passwd
&& passwd_compare(menu_master_passwd
, user_passwd
))
449 || (menu_entry
&& passwd_compare(menu_entry
, user_passwd
));
454 draw_menu(int sel
, int top
, int edit_line
)
457 int sbtop
= 0, sbbot
= 0;
461 if ( nentries
> MENU_ROWS
) {
462 int sblen
= MENU_ROWS
*MENU_ROWS
/nentries
;
463 sbtop
= (MENU_ROWS
-sblen
+1)*top
/(nentries
-MENU_ROWS
+1);
464 sbbot
= sbtop
+ sblen
- 1;
466 sbtop
+= 4; sbbot
+= 4; /* Starting row of scrollbar */
469 printf("\033[%d;%dH\1#1\016l", VSHIFT
+1, HSHIFT
+MARGIN
+1);
470 for ( x
= 2+HSHIFT
; x
<= (WIDTH
-2*MARGIN
-1)+HSHIFT
; x
++ )
473 printf("k\033[%d;%dH\1#1x\017\1#2 %s \1#1\016x",
476 pad_line(messages
[MSG_TITLE
].msg
, 1, WIDTH
-2*MARGIN
-4));
478 printf("\033[%d;%dH\1#1t", VSHIFT
+3, HSHIFT
+MARGIN
+1);
479 for ( x
= 2+HSHIFT
; x
<= (WIDTH
-2*MARGIN
-1)+HSHIFT
; x
++ )
481 fputs("u\017", stdout
);
483 for ( y
= 4+VSHIFT
; y
< 4+VSHIFT
+MENU_ROWS
; y
++ )
484 draw_row(y
, sel
, top
, sbtop
, sbbot
);
486 printf("\033[%d;%dH\1#1\016m", y
, HSHIFT
+MARGIN
+1);
487 for ( x
= 2+HSHIFT
; x
<= (WIDTH
-2*MARGIN
-1)+HSHIFT
; x
++ )
489 fputs("j\017", stdout
);
491 if ( edit_line
&& allowedit
&& !menu_master_passwd
)
492 tabmsg
= messages
[MSG_TAB
].msg
;
494 tabmsg
= messages
[MSG_NOTAB
].msg
;
496 tabmsg_len
= strlen(tabmsg
);
498 printf("\1#8\033[%d;%dH%s",
499 TABMSG_ROW
, 1+HSHIFT
+((WIDTH
-tabmsg_len
)>>1), tabmsg
);
500 printf("\1#0\033[%d;1H", END_ROW
);
506 fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout
);
510 display_help(const char *text
)
517 printf("\1#0\033[%d;1H", HELPMSG_ROW
);
519 printf("\2#16\033[%d;1H", HELPMSG_ROW
);
522 for (p
= text
, row
= HELPMSG_ROW
; *p
&& row
<= HELPMSGEND_ROW
; p
++) {
530 printf("\033[K\033[%d;1H", ++row
);
537 fputs("\033[K", stdout
);
539 while (row
<= HELPMSGEND_ROW
) {
540 printf("\033[K\033[%d;1H", ++row
);
544 static void show_fkey(int key
)
550 case KEY_F1
: fkey
= 0; break;
551 case KEY_F2
: fkey
= 1; break;
552 case KEY_F3
: fkey
= 2; break;
553 case KEY_F4
: fkey
= 3; break;
554 case KEY_F5
: fkey
= 4; break;
555 case KEY_F6
: fkey
= 5; break;
556 case KEY_F7
: fkey
= 6; break;
557 case KEY_F8
: fkey
= 7; break;
558 case KEY_F9
: fkey
= 8; break;
559 case KEY_F10
: fkey
= 9; break;
560 case KEY_F11
: fkey
= 10; break;
561 case KEY_F12
: fkey
= 11; break;
562 default: fkey
= -1; break;
568 if (fkeyhelp
[fkey
].textname
)
569 key
= show_message_file(fkeyhelp
[fkey
].textname
,
570 fkeyhelp
[fkey
].background
);
577 edit_cmdline(char *input
, int top
)
579 static char cmdline
[MAX_CMDLINE_LEN
];
580 int key
, len
, prev_len
, cursor
;
581 int redraw
= 1; /* We enter with the menu already drawn */
583 strncpy(cmdline
, input
, MAX_CMDLINE_LEN
);
584 cmdline
[MAX_CMDLINE_LEN
-1] = '\0';
586 len
= cursor
= strlen(cmdline
);
591 /* Clear and redraw whole screen */
592 /* Enable ASCII on G0 and DEC VT on G1; do it in this order
593 to avoid confusing the Linux console */
595 draw_menu(-1, top
, 1);
600 /* Redraw the command line */
601 printf("\033[?25l\033[%d;1H\1#9> \2#10%s",
602 CMDLINE_ROW
, pad_line(cmdline
, 0, max(len
, prev_len
)));
603 printf("\2#10\033[%d;3H%s\033[?25h",
604 CMDLINE_ROW
, pad_line(cmdline
, 0, cursor
));
627 memmove(cmdline
+cursor
-1, cmdline
+cursor
, len
-cursor
+1);
636 if ( cursor
< len
) {
637 memmove(cmdline
+cursor
, cmdline
+cursor
+1, len
-cursor
);
653 int prevcursor
= cursor
;
655 while ( cursor
&& my_isspace(cmdline
[cursor
-1]) )
658 while ( cursor
&& !my_isspace(cmdline
[cursor
-1]) )
661 memmove(cmdline
+cursor
, cmdline
+prevcursor
, len
-prevcursor
+1);
662 len
-= (cursor
-prevcursor
);
677 if ( cursor
< len
) {
678 putchar(cmdline
[cursor
++]);
683 if ( cursor
< len
) {
684 cmdline
[len
= cursor
] = '\0';
699 if ( cursor
!= len
) {
722 if ( key
>= ' ' && key
<= 0xFF && len
< MAX_CMDLINE_LEN
-1 ) {
723 if ( cursor
== len
) {
725 cmdline
[++len
] = '\0';
730 memmove(cmdline
+cursor
+1, cmdline
+cursor
, len
-cursor
+1);
731 cmdline
[cursor
++] = key
;
744 uint8_t shift_bits
= *(uint8_t *)0x417;
746 return !!(shift_bits
& 0x5d); /* Caps/Scroll/Alt/Shift */
750 print_timeout_message(int tol
, int row
, const char *msg
)
754 const char *tp
= msg
;
758 while ((size_t)(tq
-buf
) < (sizeof buf
-16) && (tc
= *tp
)) {
761 nnc
= sprintf(tq
, "\2#15%d\2#14", tol
);
763 nc
+= nnc
-8; /* 8 formatting characters */
764 } else if (tc
== '{') {
765 /* Deal with {singular[,dual],plural} constructs */
772 memset(tx
, 0, sizeof tx
);
776 while (*tp
&& *tp
!= '}') {
777 if (*tp
== ',' && n
< 2) {
787 tp
++; /* Skip final bracket */
794 /* Now [0] is singular, [1] is dual, and [2] is plural,
795 even if the user only specified some of them. */
798 case 1: n
= 0; break;
799 case 2: n
= 1; break;
800 default: n
= 2; break;
803 for (tpp
= tx
[n
].s
; tpp
< tx
[n
].e
; tpp
++) {
804 if ((size_t)(tq
-buf
) < (sizeof buf
)) {
816 /* Let's hope 4 spaces on each side is enough... */
817 printf("\033[%d;%dH\2#14 %s ", row
, HSHIFT
+1+((WIDTH
-nc
-8)>>1), buf
);
824 int timeout_left
, this_timeout
;
828 if ( !setjmp(timeout_jump
) ) {
829 timeout_left
= timeout
;
831 while (!timeout
|| timeout_left
) {
832 int tol
= timeout_left
/CLK_TCK
;
834 print_timeout_message(tol
, HIDDEN_ROW
, messages
[MSG_AUTOBOOT
].msg
);
836 this_timeout
= min(timeout_left
, CLK_TCK
);
837 key
= mygetkey(this_timeout
);
840 return NULL
; /* Key pressed */
842 timeout_left
-= this_timeout
;
846 return menu_entries
[defentry
].cmdline
; /* Default entry */
854 volatile int entry
= defentry
, prev_entry
= -1;
855 int top
= 0, prev_top
= -1;
856 int clear
= 1, to_clear
;
857 const char *cmdline
= NULL
;
858 volatile clock_t key_timeout
, timeout_left
, this_timeout
;
860 /* Note: for both key_timeout and timeout == 0 means no limit */
861 timeout_left
= key_timeout
= timeout
;
863 /* If we're in shiftkey mode, exit immediately unless a shift key is pressed */
864 if ( shiftkey
&& !shift_is_held() ) {
865 return menu_entries
[defentry
].cmdline
;
868 /* Handle hiddenmenu */
870 cmdline
= do_hidden_menu();
874 /* Otherwise display the menu now; the timeout has already been
875 cancelled, since the user pressed a key. */
880 /* Handle both local and global timeout */
881 if ( setjmp(timeout_jump
) ) {
884 if ( top
< 0 || top
< entry
-MENU_ROWS
+1 )
885 top
= max(0, entry
-MENU_ROWS
+1);
886 else if ( top
> entry
|| top
> max(0,nentries
-MENU_ROWS
) )
887 top
= min(entry
, max(0,nentries
-MENU_ROWS
));
889 draw_menu(ontimeout
? -1 : entry
, top
, 1);
890 cmdline
= ontimeout
? ontimeout
: menu_entries
[entry
].cmdline
;
897 else if ( entry
>= nentries
)
900 if ( top
< 0 || top
< entry
-MENU_ROWS
+1 )
901 top
= max(0, entry
-MENU_ROWS
+1);
902 else if ( top
> entry
|| top
> max(0,nentries
-MENU_ROWS
) )
903 top
= min(entry
, max(0,nentries
-MENU_ROWS
));
905 /* Start with a clear screen */
907 /* Clear and redraw whole screen */
908 /* Enable ASCII on G0 and DEC VT on G1; do it in this order
909 to avoid confusing the Linux console */
912 prev_entry
= prev_top
= -1;
915 if ( top
!= prev_top
) {
916 draw_menu(entry
, top
, 1);
917 display_help(menu_entries
[entry
].helptext
);
918 } else if ( entry
!= prev_entry
) {
919 draw_row(prev_entry
-top
+4+VSHIFT
, entry
, top
, 0, 0);
920 draw_row(entry
-top
+4+VSHIFT
, entry
, top
, 0, 0);
921 display_help(menu_entries
[entry
].helptext
);
924 prev_entry
= entry
; prev_top
= top
;
926 /* Cursor movement cancels timeout */
927 if ( entry
!= defentry
)
931 int tol
= timeout_left
/CLK_TCK
;
932 print_timeout_message(tol
, TIMEOUT_ROW
, messages
[MSG_AUTOBOOT
].msg
);
938 this_timeout
= min(min(key_timeout
, timeout_left
), CLK_TCK
);
939 key
= mygetkey(this_timeout
);
941 if ( key
!= KEY_NONE
) {
942 timeout_left
= key_timeout
;
944 printf("\033[%d;1H\1#0\033[K", TIMEOUT_ROW
);
948 case KEY_NONE
: /* Timeout */
949 /* This is somewhat hacky, but this at least lets the user
950 know what's going on, and still deals with "phantom inputs"
951 e.g. on serial ports.
953 Warning: a timeout will boot the default entry without any
956 if ( timeout_left
<= this_timeout
)
957 longjmp(timeout_jump
, 1);
959 timeout_left
-= this_timeout
;
969 key_timeout
= 0; /* Cancels timeout */
970 if ( menu_entries
[entry
].passwd
) {
972 done
= ask_passwd(menu_entries
[entry
].passwd
);
976 cmdline
= menu_entries
[entry
].cmdline
;
990 if ( entry
< nentries
-1 ) {
992 if ( entry
>= top
+MENU_ROWS
)
1031 entry
= nentries
- 1;
1032 top
= max(0, nentries
-MENU_ROWS
);
1055 key_timeout
= 0; /* Cancels timeout */
1056 draw_row(entry
-top
+4+VSHIFT
, -1, top
, 0, 0);
1058 if ( menu_master_passwd
) {
1059 ok
= ask_passwd(NULL
);
1061 draw_menu(-1, top
, 0);
1063 /* Erase [Tab] message and help text*/
1064 printf("\033[%d;1H\1#0\033[K", TABMSG_ROW
);
1069 cmdline
= edit_cmdline(menu_entries
[entry
].cmdline
, top
);
1071 clear
= 1; /* In case we hit [Esc] and done is null */
1073 draw_row(entry
-top
+4+VSHIFT
, entry
, top
, 0, 0);
1077 case KEY_CTRL('C'): /* Ctrl-C */
1078 case KEY_ESC
: /* Esc */
1084 draw_row(entry
-top
+4+VSHIFT
, -1, top
, 0, 0);
1086 if ( menu_master_passwd
)
1087 done
= ask_passwd(NULL
);
1091 if ( key
> 0 && key
< 0xFF ) {
1092 key
&= ~0x20; /* Upper case */
1093 if ( menu_hotkeys
[key
] ) {
1095 entry
= menu_hotkeys
[key
] - menu_entries
;
1096 /* Should we commit at this point? */
1103 printf("\033[?25h"); /* Show cursor */
1105 /* Return the label name so localboot and ipappend work */
1111 execute(const char *cmdline
, enum kernel_type type
)
1114 const char *p
, **pp
;
1115 char *q
= __com32
.cs_bounce
;
1116 const char *kernel
, *args
;
1118 memset(&ireg
, 0, sizeof ireg
);
1122 while ( *p
&& !my_isspace(*p
) ) {
1128 while ( *p
&& my_isspace(*p
) )
1133 if (kernel
[0] == '.' && type
== KT_NONE
) {
1134 /* It might be a type specifier */
1135 enum kernel_type type
= KT_NONE
;
1136 for (pp
= kernel_types
; *pp
; pp
++, type
++) {
1137 if (!strcmp(kernel
+1, *pp
)) {
1138 execute(p
, type
); /* Strip the type specifier and retry */
1143 if (type
== KT_LOCALBOOT
) {
1144 ireg
.eax
.w
[0] = 0x0014; /* Local boot */
1145 ireg
.edx
.w
[0] = strtoul(kernel
, NULL
, 0);
1147 if (type
< KT_KERNEL
)
1150 ireg
.eax
.w
[0] = 0x0016; /* Run kernel image */
1151 ireg
.esi
.w
[0] = OFFS(kernel
);
1152 ireg
.ds
= SEG(kernel
);
1153 ireg
.ebx
.w
[0] = OFFS(args
);
1154 ireg
.es
= SEG(args
);
1155 ireg
.edx
.l
= type
-KT_KERNEL
;
1156 /* ireg.ecx.l = 0; */ /* We do ipappend "manually" */
1159 __intcall(0x22, &ireg
, NULL
);
1161 /* If this returns, something went bad; return to menu */
1164 int menu_main(int argc
, char *argv
[])
1166 const char *cmdline
;
1174 install_default_color_table();
1175 if (getscreensize(1, &rows
, &cols
)) {
1176 /* Unknown screen size? */
1182 parse_configs(argv
+1);
1184 /* If anyone has specified negative parameters, consider them
1185 relative to the bottom row of the screen. */
1186 for (i
= 0; mparm
[i
].name
; i
++)
1187 if (mparm
[i
].value
< 0)
1188 mparm
[i
].value
= max(mparm
[i
].value
+rows
, 0);
1190 draw_background(menu_background
);
1193 fputs("No LABEL entries found in configuration file!\n", stdout
);
1194 return 1; /* Error! */
1198 cmdline
= run_menu();
1200 printf("\033[?25h\033[%d;1H\033[0m", END_ROW
);
1204 execute(cmdline
, KT_NONE
);
1206 execute(onerror
, KT_NONE
);
1208 return 0; /* Exit */
1211 console_prepare(); /* If we're looping... */