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
58 * 17 - disabled Disabled menu item
61 static const struct color_table default_color_table
[] = {
62 { "screen", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL
},
63 { "border", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL
},
64 { "title", "1;36;44", 0xc00090f0, 0x00000000, SHADOW_NORMAL
},
65 { "unsel", "37;44", 0x90ffffff, 0x00000000, SHADOW_NORMAL
},
66 { "hotkey", "1;37;44", 0xffffffff, 0x00000000, SHADOW_NORMAL
},
67 { "sel", "7;37;40", 0xe0000000, 0x20ff8000, SHADOW_ALL
},
68 { "hotsel", "1;7;37;40", 0xe0400000, 0x20ff8000, SHADOW_ALL
},
69 { "scrollbar", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL
},
70 { "tabmsg", "31;40", 0x90ffff00, 0x00000000, SHADOW_NORMAL
},
71 { "cmdmark", "1;36;40", 0xc000ffff, 0x00000000, SHADOW_NORMAL
},
72 { "cmdline", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL
},
73 { "pwdborder", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL
},
74 { "pwdheader", "31;47", 0x80ff8080, 0x20ffffff, SHADOW_NORMAL
},
75 { "pwdentry", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL
},
76 { "timeout_msg", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL
},
77 { "timeout", "1;37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL
},
78 { "help", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL
},
79 { "disabled", "1;30;44", 0x60cccccc, 0x00000000, SHADOW_NORMAL
},
82 #define NCOLORS (sizeof default_color_table/sizeof(struct color_table))
83 const int message_base_color
= NCOLORS
;
85 struct menu_parameter mparm
[] = {
88 { "passwordmargin", 3 },
93 { "passwordrow", 11 },
96 { "helpmsgendrow", -1 },
103 #define WIDTH mparm[0].value
104 #define MARGIN mparm[1].value
105 #define PASSWD_MARGIN mparm[2].value
106 #define MENU_ROWS mparm[3].value
107 #define TABMSG_ROW (mparm[4].value+VSHIFT)
108 #define CMDLINE_ROW (mparm[5].value+VSHIFT)
109 #define END_ROW mparm[6].value
110 #define PASSWD_ROW (mparm[7].value+VSHIFT)
111 #define TIMEOUT_ROW (mparm[8].value+VSHIFT)
112 #define HELPMSG_ROW (mparm[9].value+VSHIFT)
113 #define HELPMSGEND_ROW mparm[10].value
114 #define HSHIFT mparm[11].value
115 #define VSHIFT mparm[12].value
116 #define HIDDEN_ROW mparm[13].value
118 void set_msg_colors_global(unsigned int fg
, unsigned int bg
,
119 enum color_table_shadow shadow
)
121 struct color_table
*cp
= console_color_table
+message_base_color
;
123 unsigned int fga
, bga
;
124 unsigned int fgh
, bgh
;
125 unsigned int fg_idx
, bg_idx
;
126 unsigned int fg_rgb
, bg_rgb
;
128 static const unsigned int pc2rgb
[8] =
129 { 0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00,
132 /* Converting PC RGBI to sensible RGBA values is an "interesting"
133 proposition. This algorithm may need plenty of tweaking. */
135 fga
= fg
& 0xff000000;
136 fgh
= ((fg
>> 1) & 0xff000000) | 0x80000000;
138 bga
= bg
& 0xff000000;
139 bgh
= ((bg
>> 1) & 0xff000000) | 0x80000000;
141 for (i
= 0; i
< 256; i
++) {
145 fg_rgb
= pc2rgb
[fg_idx
& 7] & fg
;
146 bg_rgb
= pc2rgb
[bg_idx
& 7] & bg
;
149 /* High intensity foreground */
156 /* Default black background, assume transparent */
158 } else if (bg_idx
& 8) {
164 cp
->argb_fg
= fg_rgb
;
165 cp
->argb_bg
= bg_rgb
;
172 install_default_color_table(void)
175 const struct color_table
*dp
;
176 struct color_table
*cp
;
177 static struct color_table color_table
[NCOLORS
+256];
178 static const int pc2ansi
[8] = {0, 4, 2, 6, 1, 5, 3, 7};
180 dp
= default_color_table
;
183 for (i
= 0; i
< NCOLORS
; i
++) {
185 free((void *)cp
->ansi
);
188 cp
->ansi
= strdup(dp
->ansi
);
194 for (i
= 0; i
< 256; i
++) {
196 asprintf((char **)&cp
->name
, "msg%02x", i
);
199 free((void *)cp
->ansi
);
201 asprintf((char **)&cp
->ansi
, "%s3%d;4%d", (i
& 8) ? "1;" : "",
202 pc2ansi
[i
& 7], pc2ansi
[(i
>> 4) & 7]);
207 console_color_table
= color_table
;
208 console_color_table_size
= NCOLORS
+256;
210 set_msg_colors_global(MSG_COLORS_DEF_FG
, MSG_COLORS_DEF_BG
,
211 MSG_COLORS_DEF_SHADOW
);
215 pad_line(const char *text
, int align
, int width
)
217 static char buffer
[MAX_CMDLINE_LEN
];
220 if ( width
>= (int) sizeof buffer
)
221 return NULL
; /* Can't do it */
227 memset(buffer
, ' ', width
);
229 p
= ((width
-n
)*align
)>>1;
230 memcpy(buffer
+p
, text
, n
);
235 /* Display an entry, with possible hotkey highlight. Assumes
236 that the current attribute is the non-hotkey one, and will
237 guarantee that as an exit condition as well. */
239 display_entry(const struct menu_entry
*entry
, const char *attrib
,
240 const char *hotattrib
, int width
)
242 const char *p
= entry
->displayname
;
248 if ( *p
&& ((unsigned char)*p
& ~0x20) == entry
->hotkey
) {
249 fputs(hotattrib
, stdout
);
251 fputs(attrib
, stdout
);
266 draw_row(int y
, int sel
, int top
, int sbtop
, int sbbot
)
268 int i
= (y
-4-VSHIFT
)+top
;
269 int dis
= (i
< nentries
) && menu_entries
[i
].disabled
;
271 printf("\033[%d;%dH\1#1\016x\017%s ",
273 (i
== sel
) ? "\1#5" : dis
? "\2#17" : "\1#3");
275 if ( i
>= nentries
) {
276 fputs(pad_line("", 0, WIDTH
-2*MARGIN
-4), stdout
);
278 display_entry(&menu_entries
[i
],
279 (i
== sel
) ? "\1#5" : dis
? "\2#17" : "\1#3",
280 (i
== sel
) ? "\1#6" : dis
? "\2#17" : "\1#4",
284 if ( nentries
<= MENU_ROWS
) {
285 printf(" \1#1\016x\017");
286 } else if ( sbtop
> 0 ) {
287 if ( y
>= sbtop
&& y
<= sbbot
)
288 printf(" \1#7\016a\017");
290 printf(" \1#1\016x\017");
292 putchar(' '); /* Don't modify the scrollbar */
296 static int passwd_compare_sha1(const char *passwd
, const char *entry
)
300 unsigned char sha1
[20], pwdsha1
[20];
302 if ( (p
= strchr(passwd
+3, '$')) ) {
303 SHA1Update(&ctx
, (void *)passwd
+3, p
-(passwd
+3));
306 p
= passwd
+3; /* Assume no salt */
311 SHA1Update(&ctx
, (void *)entry
, strlen(entry
));
312 SHA1Final(sha1
, &ctx
);
314 memset(pwdsha1
, 0, 20);
315 unbase64(pwdsha1
, 20, p
);
317 return !memcmp(sha1
, pwdsha1
, 20);
320 static int passwd_compare_md5(const char *passwd
, const char *entry
)
322 const char *crypted
= crypt_md5(entry
, passwd
+3);
323 int len
= strlen(crypted
);
325 return !strncmp(crypted
, passwd
, len
) &&
326 (passwd
[len
] == '\0' || passwd
[len
] == '$');
330 passwd_compare(const char *passwd
, const char *entry
)
332 if ( passwd
[0] != '$' ) /* Plaintext passwd, yuck! */
333 return !strcmp(entry
, passwd
);
334 else if ( !strncmp(passwd
, "$4$", 3) )
335 return passwd_compare_sha1(passwd
, entry
);
336 else if ( !strncmp(passwd
, "$1$", 3) )
337 return passwd_compare_md5(passwd
, entry
);
339 return 0; /* Invalid encryption algorithm */
342 static jmp_buf timeout_jump
;
344 int mygetkey(clock_t timeout
)
351 return get_key(stdin
, timeout
);
354 tto
= min(totaltimeout
, INT_MAX
);
355 to
= timeout
? min(tto
, timeout
) : tto
;
358 key
= get_key(stdin
, to
);
359 t
= times(NULL
) - t0
;
361 if ( totaltimeout
<= t
)
362 longjmp(timeout_jump
, 1);
366 if ( key
!= KEY_NONE
)
379 ask_passwd(const char *menu_entry
)
381 char user_passwd
[WIDTH
], *p
;
386 printf("\033[%d;%dH\2#11\016l", PASSWD_ROW
, PASSWD_MARGIN
+1);
387 for ( x
= 2 ; x
<= WIDTH
-2*PASSWD_MARGIN
-1 ; x
++ )
390 printf("k\033[%d;%dHx", PASSWD_ROW
+1, PASSWD_MARGIN
+1);
391 for ( x
= 2 ; x
<= WIDTH
-2*PASSWD_MARGIN
-1 ; x
++ )
394 printf("x\033[%d;%dHm", PASSWD_ROW
+2, PASSWD_MARGIN
+1);
395 for ( x
= 2 ; x
<= WIDTH
-2*PASSWD_MARGIN
-1 ; x
++ )
398 printf("j\017\033[%d;%dH\2#12 %s \033[%d;%dH\2#13",
399 PASSWD_ROW
, (WIDTH
-(strlen(messages
[MSG_PASSPROMPT
].msg
)+2))/2,
400 messages
[MSG_PASSPROMPT
].msg
, PASSWD_ROW
+1, PASSWD_MARGIN
+3);
402 /* Actually allow user to type a password, then compare to the SHA1 */
417 p
= user_passwd
; /* No password entered */
424 if ( p
> user_passwd
) {
431 while ( p
> user_passwd
) {
438 if ( key
>= ' ' && key
<= 0xFF &&
439 (p
-user_passwd
) < WIDTH
-2*PASSWD_MARGIN
-5 ) {
447 if ( p
== user_passwd
)
448 return 0; /* No password entered */
452 return (menu_master_passwd
&& passwd_compare(menu_master_passwd
, user_passwd
))
453 || (menu_entry
&& passwd_compare(menu_entry
, user_passwd
));
458 draw_menu(int sel
, int top
, int edit_line
)
461 int sbtop
= 0, sbbot
= 0;
465 if ( nentries
> MENU_ROWS
) {
466 int sblen
= MENU_ROWS
*MENU_ROWS
/nentries
;
467 sbtop
= (MENU_ROWS
-sblen
+1)*top
/(nentries
-MENU_ROWS
+1);
468 sbbot
= sbtop
+ sblen
- 1;
470 sbtop
+= 4; sbbot
+= 4; /* Starting row of scrollbar */
473 printf("\033[%d;%dH\1#1\016l", VSHIFT
+1, HSHIFT
+MARGIN
+1);
474 for ( x
= 2+HSHIFT
; x
<= (WIDTH
-2*MARGIN
-1)+HSHIFT
; x
++ )
477 printf("k\033[%d;%dH\1#1x\017\1#2 %s \1#1\016x",
480 pad_line(messages
[MSG_TITLE
].msg
, 1, WIDTH
-2*MARGIN
-4));
482 printf("\033[%d;%dH\1#1t", VSHIFT
+3, HSHIFT
+MARGIN
+1);
483 for ( x
= 2+HSHIFT
; x
<= (WIDTH
-2*MARGIN
-1)+HSHIFT
; x
++ )
485 fputs("u\017", stdout
);
487 for ( y
= 4+VSHIFT
; y
< 4+VSHIFT
+MENU_ROWS
; y
++ )
488 draw_row(y
, sel
, top
, sbtop
, sbbot
);
490 printf("\033[%d;%dH\1#1\016m", y
, HSHIFT
+MARGIN
+1);
491 for ( x
= 2+HSHIFT
; x
<= (WIDTH
-2*MARGIN
-1)+HSHIFT
; x
++ )
493 fputs("j\017", stdout
);
495 if ( edit_line
&& allowedit
&& !menu_master_passwd
)
496 tabmsg
= messages
[MSG_TAB
].msg
;
498 tabmsg
= messages
[MSG_NOTAB
].msg
;
500 tabmsg_len
= strlen(tabmsg
);
502 printf("\1#8\033[%d;%dH%s",
503 TABMSG_ROW
, 1+HSHIFT
+((WIDTH
-tabmsg_len
)>>1), tabmsg
);
504 printf("\1#0\033[%d;1H", END_ROW
);
510 fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout
);
514 display_help(const char *text
)
521 printf("\1#0\033[%d;1H", HELPMSG_ROW
);
523 printf("\2#16\033[%d;1H", HELPMSG_ROW
);
526 for (p
= text
, row
= HELPMSG_ROW
; *p
&& row
<= HELPMSGEND_ROW
; p
++) {
534 printf("\033[K\033[%d;1H", ++row
);
541 fputs("\033[K", stdout
);
543 while (row
<= HELPMSGEND_ROW
) {
544 printf("\033[K\033[%d;1H", ++row
);
548 static void show_fkey(int key
)
554 case KEY_F1
: fkey
= 0; break;
555 case KEY_F2
: fkey
= 1; break;
556 case KEY_F3
: fkey
= 2; break;
557 case KEY_F4
: fkey
= 3; break;
558 case KEY_F5
: fkey
= 4; break;
559 case KEY_F6
: fkey
= 5; break;
560 case KEY_F7
: fkey
= 6; break;
561 case KEY_F8
: fkey
= 7; break;
562 case KEY_F9
: fkey
= 8; break;
563 case KEY_F10
: fkey
= 9; break;
564 case KEY_F11
: fkey
= 10; break;
565 case KEY_F12
: fkey
= 11; break;
566 default: fkey
= -1; break;
572 if (fkeyhelp
[fkey
].textname
)
573 key
= show_message_file(fkeyhelp
[fkey
].textname
,
574 fkeyhelp
[fkey
].background
);
581 edit_cmdline(char *input
, int top
)
583 static char cmdline
[MAX_CMDLINE_LEN
];
584 int key
, len
, prev_len
, cursor
;
585 int redraw
= 1; /* We enter with the menu already drawn */
587 strncpy(cmdline
, input
, MAX_CMDLINE_LEN
);
588 cmdline
[MAX_CMDLINE_LEN
-1] = '\0';
590 len
= cursor
= strlen(cmdline
);
595 /* Clear and redraw whole screen */
596 /* Enable ASCII on G0 and DEC VT on G1; do it in this order
597 to avoid confusing the Linux console */
599 draw_menu(-1, top
, 1);
604 /* Redraw the command line */
605 printf("\033[?25l\033[%d;1H\1#9> \2#10%s",
606 CMDLINE_ROW
, pad_line(cmdline
, 0, max(len
, prev_len
)));
607 printf("\2#10\033[%d;3H%s\033[?25h",
608 CMDLINE_ROW
, pad_line(cmdline
, 0, cursor
));
631 memmove(cmdline
+cursor
-1, cmdline
+cursor
, len
-cursor
+1);
640 if ( cursor
< len
) {
641 memmove(cmdline
+cursor
, cmdline
+cursor
+1, len
-cursor
);
657 int prevcursor
= cursor
;
659 while ( cursor
&& my_isspace(cmdline
[cursor
-1]) )
662 while ( cursor
&& !my_isspace(cmdline
[cursor
-1]) )
665 memmove(cmdline
+cursor
, cmdline
+prevcursor
, len
-prevcursor
+1);
666 len
-= (cursor
-prevcursor
);
681 if ( cursor
< len
) {
682 putchar(cmdline
[cursor
++]);
687 if ( cursor
< len
) {
688 cmdline
[len
= cursor
] = '\0';
703 if ( cursor
!= len
) {
726 if ( key
>= ' ' && key
<= 0xFF && len
< MAX_CMDLINE_LEN
-1 ) {
727 if ( cursor
== len
) {
729 cmdline
[++len
] = '\0';
734 memmove(cmdline
+cursor
+1, cmdline
+cursor
, len
-cursor
+1);
735 cmdline
[cursor
++] = key
;
748 uint8_t shift_bits
= *(uint8_t *)0x417;
750 return !!(shift_bits
& 0x5d); /* Caps/Scroll/Alt/Shift */
754 print_timeout_message(int tol
, int row
, const char *msg
)
758 const char *tp
= msg
;
762 while ((size_t)(tq
-buf
) < (sizeof buf
-16) && (tc
= *tp
)) {
765 nnc
= sprintf(tq
, "\2#15%d\2#14", tol
);
767 nc
+= nnc
-8; /* 8 formatting characters */
768 } else if (tc
== '{') {
769 /* Deal with {singular[,dual],plural} constructs */
776 memset(tx
, 0, sizeof tx
);
780 while (*tp
&& *tp
!= '}') {
781 if (*tp
== ',' && n
< 2) {
791 tp
++; /* Skip final bracket */
798 /* Now [0] is singular, [1] is dual, and [2] is plural,
799 even if the user only specified some of them. */
802 case 1: n
= 0; break;
803 case 2: n
= 1; break;
804 default: n
= 2; break;
807 for (tpp
= tx
[n
].s
; tpp
< tx
[n
].e
; tpp
++) {
808 if ((size_t)(tq
-buf
) < (sizeof buf
)) {
820 /* Let's hope 4 spaces on each side is enough... */
821 printf("\033[%d;%dH\2#14 %s ", row
, HSHIFT
+1+((WIDTH
-nc
-8)>>1), buf
);
828 int timeout_left
, this_timeout
;
832 if ( !setjmp(timeout_jump
) ) {
833 timeout_left
= timeout
;
835 while (!timeout
|| timeout_left
) {
836 int tol
= timeout_left
/CLK_TCK
;
838 print_timeout_message(tol
, HIDDEN_ROW
, messages
[MSG_AUTOBOOT
].msg
);
840 this_timeout
= min(timeout_left
, CLK_TCK
);
841 key
= mygetkey(this_timeout
);
844 return NULL
; /* Key pressed */
846 timeout_left
-= this_timeout
;
850 return menu_entries
[defentry
].cmdline
; /* Default entry */
858 volatile int entry
= defentry
, prev_entry
= -1;
859 int top
= 0, prev_top
= -1;
860 int clear
= 1, to_clear
;
861 const char *cmdline
= NULL
;
862 volatile clock_t key_timeout
, timeout_left
, this_timeout
;
864 /* Note: for both key_timeout and timeout == 0 means no limit */
865 timeout_left
= key_timeout
= timeout
;
867 /* If we're in shiftkey mode, exit immediately unless a shift key is pressed */
868 if ( shiftkey
&& !shift_is_held() ) {
869 return menu_entries
[defentry
].cmdline
;
872 /* Handle hiddenmenu */
874 cmdline
= do_hidden_menu();
878 /* Otherwise display the menu now; the timeout has already been
879 cancelled, since the user pressed a key. */
884 /* Handle both local and global timeout */
885 if ( setjmp(timeout_jump
) ) {
888 if ( top
< 0 || top
< entry
-MENU_ROWS
+1 )
889 top
= max(0, entry
-MENU_ROWS
+1);
890 else if ( top
> entry
|| top
> max(0,nentries
-MENU_ROWS
) )
891 top
= min(entry
, max(0,nentries
-MENU_ROWS
));
893 draw_menu(ontimeout
? -1 : entry
, top
, 1);
894 cmdline
= ontimeout
? ontimeout
: menu_entries
[entry
].cmdline
;
901 while ( entry
< nentries
&& menu_entries
[entry
].disabled
) entry
++;
904 if ( entry
>= nentries
) {
906 while ( entry
> 0 && menu_entries
[entry
].disabled
) entry
--;
909 if ( top
< 0 || top
< entry
-MENU_ROWS
+1 )
910 top
= max(0, entry
-MENU_ROWS
+1);
911 else if ( top
> entry
|| top
> max(0,nentries
-MENU_ROWS
) )
912 top
= min(entry
, max(0,nentries
-MENU_ROWS
));
914 /* Start with a clear screen */
916 /* Clear and redraw whole screen */
917 /* Enable ASCII on G0 and DEC VT on G1; do it in this order
918 to avoid confusing the Linux console */
921 prev_entry
= prev_top
= -1;
924 if ( top
!= prev_top
) {
925 draw_menu(entry
, top
, 1);
926 display_help(menu_entries
[entry
].helptext
);
927 } else if ( entry
!= prev_entry
) {
928 draw_row(prev_entry
-top
+4+VSHIFT
, entry
, top
, 0, 0);
929 draw_row(entry
-top
+4+VSHIFT
, entry
, top
, 0, 0);
930 display_help(menu_entries
[entry
].helptext
);
933 prev_entry
= entry
; prev_top
= top
;
935 /* Cursor movement cancels timeout */
936 if ( entry
!= defentry
)
940 int tol
= timeout_left
/CLK_TCK
;
941 print_timeout_message(tol
, TIMEOUT_ROW
, messages
[MSG_AUTOBOOT
].msg
);
947 this_timeout
= min(min(key_timeout
, timeout_left
), CLK_TCK
);
948 key
= mygetkey(this_timeout
);
950 if ( key
!= KEY_NONE
) {
951 timeout_left
= key_timeout
;
953 printf("\033[%d;1H\1#0\033[K", TIMEOUT_ROW
);
957 case KEY_NONE
: /* Timeout */
958 /* This is somewhat hacky, but this at least lets the user
959 know what's going on, and still deals with "phantom inputs"
960 e.g. on serial ports.
962 Warning: a timeout will boot the default entry without any
965 if ( timeout_left
<= this_timeout
)
966 longjmp(timeout_jump
, 1);
968 timeout_left
-= this_timeout
;
978 key_timeout
= 0; /* Cancels timeout */
979 if ( menu_entries
[entry
].passwd
) {
981 done
= ask_passwd(menu_entries
[entry
].passwd
);
985 cmdline
= menu_entries
[entry
].cmdline
;
990 while ( entry
> 0 && entry
-- && menu_entries
[entry
].disabled
) {
996 while ( menu_entries
[entry
].disabled
)
1003 while ( entry
< nentries
-1 && entry
++ && menu_entries
[entry
].disabled
) {
1004 if ( entry
>= top
+MENU_ROWS
)
1008 if ( entry
== nentries
-1 ) {
1009 while ( menu_entries
[entry
].disabled
)
1048 entry
= nentries
- 1;
1049 top
= max(0, nentries
-MENU_ROWS
);
1072 key_timeout
= 0; /* Cancels timeout */
1073 draw_row(entry
-top
+4+VSHIFT
, -1, top
, 0, 0);
1075 if ( menu_master_passwd
) {
1076 ok
= ask_passwd(NULL
);
1078 draw_menu(-1, top
, 0);
1080 /* Erase [Tab] message and help text*/
1081 printf("\033[%d;1H\1#0\033[K", TABMSG_ROW
);
1086 cmdline
= edit_cmdline(menu_entries
[entry
].cmdline
, top
);
1088 clear
= 1; /* In case we hit [Esc] and done is null */
1090 draw_row(entry
-top
+4+VSHIFT
, entry
, top
, 0, 0);
1094 case KEY_CTRL('C'): /* Ctrl-C */
1095 case KEY_ESC
: /* Esc */
1101 draw_row(entry
-top
+4+VSHIFT
, -1, top
, 0, 0);
1103 if ( menu_master_passwd
)
1104 done
= ask_passwd(NULL
);
1108 if ( key
> 0 && key
< 0xFF ) {
1109 key
&= ~0x20; /* Upper case */
1110 if ( menu_hotkeys
[key
] ) {
1112 entry
= menu_hotkeys
[key
] - menu_entries
;
1113 /* Should we commit at this point? */
1120 printf("\033[?25h"); /* Show cursor */
1122 /* Return the label name so localboot and ipappend work */
1128 execute(const char *cmdline
, enum kernel_type type
)
1131 const char *p
, **pp
;
1132 char *q
= __com32
.cs_bounce
;
1133 const char *kernel
, *args
;
1135 memset(&ireg
, 0, sizeof ireg
);
1139 while ( *p
&& !my_isspace(*p
) ) {
1145 while ( *p
&& my_isspace(*p
) )
1150 if (kernel
[0] == '.' && type
== KT_NONE
) {
1151 /* It might be a type specifier */
1152 enum kernel_type type
= KT_NONE
;
1153 for (pp
= kernel_types
; *pp
; pp
++, type
++) {
1154 if (!strcmp(kernel
+1, *pp
)) {
1155 execute(p
, type
); /* Strip the type specifier and retry */
1160 if (type
== KT_LOCALBOOT
) {
1161 ireg
.eax
.w
[0] = 0x0014; /* Local boot */
1162 ireg
.edx
.w
[0] = strtoul(kernel
, NULL
, 0);
1164 if (type
< KT_KERNEL
)
1167 ireg
.eax
.w
[0] = 0x0016; /* Run kernel image */
1168 ireg
.esi
.w
[0] = OFFS(kernel
);
1169 ireg
.ds
= SEG(kernel
);
1170 ireg
.ebx
.w
[0] = OFFS(args
);
1171 ireg
.es
= SEG(args
);
1172 ireg
.edx
.l
= type
-KT_KERNEL
;
1173 /* ireg.ecx.l = 0; */ /* We do ipappend "manually" */
1176 __intcall(0x22, &ireg
, NULL
);
1178 /* If this returns, something went bad; return to menu */
1181 int menu_main(int argc
, char *argv
[])
1183 const char *cmdline
;
1191 install_default_color_table();
1192 if (getscreensize(1, &rows
, &cols
)) {
1193 /* Unknown screen size? */
1199 parse_configs(argv
+1);
1201 /* If anyone has specified negative parameters, consider them
1202 relative to the bottom row of the screen. */
1203 for (i
= 0; mparm
[i
].name
; i
++)
1204 if (mparm
[i
].value
< 0)
1205 mparm
[i
].value
= max(mparm
[i
].value
+rows
, 0);
1207 draw_background(menu_background
);
1210 fputs("No LABEL entries found in configuration file!\n", stdout
);
1211 return 1; /* Error! */
1215 cmdline
= run_menu();
1217 printf("\033[?25h\033[%d;1H\033[0m", END_ROW
);
1221 execute(cmdline
, KT_NONE
);
1223 execute(onerror
, KT_NONE
);
1225 return 0; /* Exit */
1228 console_prepare(); /* If we're looping... */