For SOH codes, always issue a leading zero reset
[syslinux.git] / com32 / modules / menumain.c
blob10da08ac9f4d6b5db555ed4866d523f943e1d303
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2006 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 * ----------------------------------------------------------------------- */
14 * menumain.c
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 */
21 #include <ctype.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <consoles.h>
26 #include <getkey.h>
27 #include <minmax.h>
28 #include <setjmp.h>
29 #include <limits.h>
30 #include <sha1.h>
31 #include <base64.h>
32 #include <colortbl.h>
33 #ifdef __COM32__
34 #include <com32.h>
35 #endif
37 #include "menu.h"
39 int (*draw_background)(const char *filename);
42 * The color/attribute indexes (\1#XX) are as follows
44 * 00 - screen Rest of the screen
45 * 01 - border Border area
46 * 02 - title Title bar
47 * 03 - unsel Unselected menu item
48 * 04 - hotkey Unselected hotkey
49 * 05 - sel Selection bar
50 * 06 - hotsel Selected hotkey
51 * 07 - scrollbar Scroll bar
52 * 08 - tabmsg Press [Tab] message
53 * 09 - cmdmark Command line marker
54 * 10 - cmdline Command line
55 * 11 - pwdborder Password box border
56 * 12 - pwdheader Password box header
57 * 13 - pwdentry Password box contents
58 * 14 - timeout_msg Timeout message
59 * 15 - timeout Timeout counter
62 static const struct color_table default_color_table[] = {
63 { "screen", "37;40", 0x80ffffff, 0x00000000 },
64 { "border", "30;44", 0x40000000, 0x00000000 },
65 { "title", "1;36;44", 0xc00090f0, 0x00000000 },
66 { "unsel", "37;44", 0x90ffffff, 0x00000000 },
67 { "hotkey", "1;37;44", 0xffffffff, 0x00000000 },
68 { "sel", "7;37;40", 0xcf101010, 0x20ff8000 },
69 { "hotsel", "7;37;40", 0xff353535, 0x20ff8000 },
70 { "scrollbar", "30;44", 0x40000000, 0x00000000 },
71 { "tabmsg", "31;40", 0x90ffff00, 0x00000000 },
72 { "cmdmark", "1;36;40", 0xc000ffff, 0x00000000 },
73 { "cmdline", "37;40", 0xc0ffffff, 0x00000000 },
74 { "pwdborder", "30;47", 0x80ffffff, 0x20ffffff },
75 { "pwdheader", "31;47", 0x80ff8080, 0x20ffffff },
76 { "pwdentry", "30;47", 0x80ffffff, 0x20ffffff },
77 { "timeout_msg", "37;40", 0x80ffffff, 0x00000000 },
78 { "timeout", "1;37;40", 0xc0ffffff, 0x00000000 },
81 #define NCOLORS (sizeof default_color_table/sizeof(struct color_table))
83 struct menu_parameter mparm[] = {
84 { "width", 80 },
85 { "margin", 10 },
86 { "passwordmargin", 3 },
87 { "rows", 12 },
88 { "tabmsgrow", 18 },
89 { "cmdlinerow", 18 },
90 { "endrow", 24 },
91 { "passwordrow", 11 },
92 { "timeoutrow", 20 },
93 { NULL, 0 }
96 #define WIDTH mparm[0].value
97 #define MARGIN mparm[1].value
98 #define PASSWD_MARGIN mparm[2].value
99 #define MENU_ROWS mparm[3].value
100 #define TABMSG_ROW mparm[4].value
101 #define CMDLINE_ROW mparm[5].value
102 #define END_ROW mparm[6].value
103 #define PASSWD_ROW mparm[7].value
104 #define TIMEOUT_ROW mparm[8].value
106 static void
107 install_default_color_table(void)
109 unsigned int i;
110 const struct color_table *dp;
111 struct color_table *cp;
112 static struct color_table color_table[NCOLORS];
114 dp = default_color_table;
115 cp = color_table;
117 for (i = 0; i < NCOLORS; i++) {
118 if (cp->ansi)
119 free((void *)cp->ansi);
121 cp->name = dp->name;
122 cp->ansi = strdup(dp->ansi);
123 cp->argb_fg = dp->argb_fg;
124 cp->argb_bg = dp->argb_bg;
126 cp++;
127 dp++;
130 console_color_table = color_table;
131 console_color_table_size = NCOLORS;
134 static char *
135 pad_line(const char *text, int align, int width)
137 static char buffer[MAX_CMDLINE_LEN];
138 int n, p;
140 if ( width >= (int) sizeof buffer )
141 return NULL; /* Can't do it */
143 n = strlen(text);
144 if ( n >= width )
145 n = width;
147 memset(buffer, ' ', width);
148 buffer[width] = 0;
149 p = ((width-n)*align)>>1;
150 memcpy(buffer+p, text, n);
152 return buffer;
155 /* Display an entry, with possible hotkey highlight. Assumes
156 that the current attribute is the non-hotkey one, and will
157 guarantee that as an exit condition as well. */
158 static void
159 display_entry(const struct menu_entry *entry, const char *attrib,
160 const char *hotattrib, int width)
162 const char *p = entry->displayname;
164 while ( width ) {
165 if ( *p ) {
166 if ( *p == '^' ) {
167 p++;
168 if ( *p && ((unsigned char)*p & ~0x20) == entry->hotkey ) {
169 fputs(hotattrib, stdout);
170 putchar(*p++);
171 fputs(attrib, stdout);
172 width--;
174 } else {
175 putchar(*p++);
176 width--;
178 } else {
179 putchar(' ');
180 width--;
185 static void
186 draw_row(int y, int sel, int top, int sbtop, int sbbot)
188 int i = (y-4)+top;
190 printf("\033[%d;%dH\1#01\016x\017%s ",
191 y, MARGIN+1, (i == sel) ? "\1#05" : "\1#03");
193 if ( i >= nentries ) {
194 fputs(pad_line("", 0, WIDTH-2*MARGIN-4), stdout);
195 } else {
196 display_entry(&menu_entries[i],
197 (i == sel) ? "\1#05" : "\1#03",
198 (i == sel) ? "\1#06" : "\1#04",
199 WIDTH-2*MARGIN-4);
202 if ( nentries <= MENU_ROWS ) {
203 printf(" \1#01\016x\017");
204 } else if ( sbtop > 0 ) {
205 if ( y >= sbtop && y <= sbbot )
206 printf(" \1#07\016a\017");
207 else
208 printf(" \1#01\016x\017");
209 } else {
210 putchar(' '); /* Don't modify the scrollbar */
214 static int
215 passwd_compare(const char *passwd, const char *entry)
217 const char *p;
218 SHA1_CTX ctx;
219 unsigned char sha1[20], pwdsha1[20];
221 if ( passwd[0] != '$' ) /* Plaintext passwd, yuck! */
222 return !strcmp(entry, passwd);
224 if ( strncmp(passwd, "$4$", 3) )
225 return 0; /* Only SHA-1 passwds supported */
227 SHA1Init(&ctx);
229 if ( (p = strchr(passwd+3, '$')) ) {
230 SHA1Update(&ctx, (void *)passwd+3, p-(passwd+3));
231 p++;
232 } else {
233 p = passwd+3; /* Assume no salt */
236 SHA1Update(&ctx, (void *)entry, strlen(entry));
237 SHA1Final(sha1, &ctx);
239 memset(pwdsha1, 0, 20);
240 unbase64(pwdsha1, 20, p);
242 return !memcmp(sha1, pwdsha1, 20);
245 static jmp_buf timeout_jump;
247 static int mygetkey(clock_t timeout)
249 clock_t t0, t;
250 clock_t tto, to;
251 int key;
253 if ( !totaltimeout )
254 return get_key(stdin, timeout);
256 for (;;) {
257 tto = min(totaltimeout, INT_MAX);
258 to = timeout ? min(tto, timeout) : tto;
260 t0 = times(NULL);
261 key = get_key(stdin, to);
262 t = times(NULL) - t0;
264 if ( totaltimeout <= t )
265 longjmp(timeout_jump, 1);
267 totaltimeout -= t;
269 if ( key != KEY_NONE )
270 return key;
272 if ( timeout ) {
273 if ( timeout <= t )
274 return KEY_NONE;
276 timeout -= t;
281 static int
282 ask_passwd(const char *menu_entry)
284 static const char title[] = "Password required";
285 char user_passwd[WIDTH], *p;
286 int done;
287 int key;
288 int x;
290 printf("\033[%d;%dH\1#11\016l", PASSWD_ROW, PASSWD_MARGIN+1);
291 for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ )
292 putchar('q');
294 printf("k\033[%d;%dHx", PASSWD_ROW+1, PASSWD_MARGIN+1);
295 for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ )
296 putchar(' ');
298 printf("x\033[%d;%dHm", PASSWD_ROW+2, PASSWD_MARGIN+1);
299 for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ )
300 putchar('q');
302 printf("j\017\033[%d;%dH\1#12 %s \033[%d;%dH\1#13",
303 PASSWD_ROW, (WIDTH-((int)sizeof(title)+1))/2,
304 title, PASSWD_ROW+1, PASSWD_MARGIN+3);
306 /* Actually allow user to type a password, then compare to the SHA1 */
307 done = 0;
308 p = user_passwd;
310 while ( !done ) {
311 key = mygetkey(0);
313 switch ( key ) {
314 case KEY_ENTER:
315 case KEY_CTRL('J'):
316 done = 1;
317 break;
319 case KEY_ESC:
320 case KEY_CTRL('C'):
321 p = user_passwd; /* No password entered */
322 done = 1;
323 break;
325 case KEY_BACKSPACE:
326 case KEY_DEL:
327 case KEY_DELETE:
328 if ( p > user_passwd ) {
329 printf("\b \b");
330 p--;
332 break;
334 case KEY_CTRL('U'):
335 while ( p > user_passwd ) {
336 printf("\b \b");
337 p--;
339 break;
341 default:
342 if ( key >= ' ' && key <= 0xFF &&
343 (p-user_passwd) < WIDTH-2*PASSWD_MARGIN-5 ) {
344 *p++ = key;
345 putchar('*');
347 break;
351 if ( p == user_passwd )
352 return 0; /* No password entered */
354 *p = '\0';
356 return (menu_master_passwd && passwd_compare(menu_master_passwd, user_passwd))
357 || (menu_entry && passwd_compare(menu_entry, user_passwd));
361 static void
362 draw_menu(int sel, int top, int edit_line)
364 int x, y;
365 int sbtop = 0, sbbot = 0;
367 if ( nentries > MENU_ROWS ) {
368 int sblen = MENU_ROWS*MENU_ROWS/nentries;
369 sbtop = (MENU_ROWS-sblen+1)*top/(nentries-MENU_ROWS+1);
370 sbbot = sbtop + sblen - 1;
372 sbtop += 4; sbbot += 4; /* Starting row of scrollbar */
375 printf("\033[1;%dH\1#01\016l", MARGIN+1);
376 for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ )
377 putchar('q');
379 printf("k\033[2;%dH\1#01x\017\1#02 %s \1#01\016x",
380 MARGIN+1,
381 pad_line(menu_title, 1, WIDTH-2*MARGIN-4));
383 printf("\033[3;%dH\1#01t", MARGIN+1);
384 for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ )
385 putchar('q');
386 fputs("u\017", stdout);
388 for ( y = 4 ; y < 4+MENU_ROWS ; y++ )
389 draw_row(y, sel, top, sbtop, sbbot);
391 printf("\033[%d;%dH\1#01\016m", y, MARGIN+1);
392 for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ )
393 putchar('q');
394 fputs("j\017", stdout);
396 if ( edit_line && allowedit && !menu_master_passwd )
397 printf("\1#08\033[%d;1H%s", TABMSG_ROW,
398 pad_line("Press [Tab] to edit options", 1, WIDTH));
400 printf("\1#00\033[%d;1H", END_ROW);
403 static void
404 clear_screen(void)
406 fputs("\033e\033%@\033)0\033(B\1#00\033[?25l\033[2J", stdout);
409 static const char *
410 edit_cmdline(char *input, int top)
412 static char cmdline[MAX_CMDLINE_LEN];
413 int key, len, prev_len, cursor;
414 int redraw = 1; /* We enter with the menu already drawn */
416 strncpy(cmdline, input, MAX_CMDLINE_LEN);
417 cmdline[MAX_CMDLINE_LEN-1] = '\0';
419 len = cursor = strlen(cmdline);
420 prev_len = 0;
422 for (;;) {
423 if ( redraw > 1 ) {
424 /* Clear and redraw whole screen */
425 /* Enable ASCII on G0 and DEC VT on G1; do it in this order
426 to avoid confusing the Linux console */
427 clear_screen();
428 draw_menu(-1, top, 1);
429 prev_len = 0;
432 if ( redraw > 0 ) {
433 /* Redraw the command line */
434 printf("\033[?25l\033[%d;1H\1#09> \1#10%s",
435 CMDLINE_ROW, pad_line(cmdline, 0, prev_len));
436 printf("\1#10\033[%d;3H%s\033[?25h",
437 CMDLINE_ROW, pad_line(cmdline, 0, cursor));
438 prev_len = len;
439 redraw = 0;
442 key = mygetkey(0);
444 switch( key ) {
445 case KEY_CTRL('L'):
446 redraw = 2;
447 break;
449 case KEY_ENTER:
450 case KEY_CTRL('J'):
451 return cmdline;
453 case KEY_ESC:
454 case KEY_CTRL('C'):
455 return NULL;
457 case KEY_BACKSPACE:
458 case KEY_DEL:
459 if ( cursor ) {
460 memmove(cmdline+cursor-1, cmdline+cursor, len-cursor+1);
461 len--;
462 cursor--;
463 redraw = 1;
465 break;
467 case KEY_CTRL('D'):
468 case KEY_DELETE:
469 if ( cursor < len ) {
470 memmove(cmdline+cursor, cmdline+cursor+1, len-cursor);
471 len--;
472 redraw = 1;
474 break;
476 case KEY_CTRL('U'):
477 if ( len ) {
478 len = cursor = 0;
479 cmdline[len] = '\0';
480 redraw = 1;
482 break;
484 case KEY_CTRL('W'):
485 if ( cursor ) {
486 int prevcursor = cursor;
488 while ( cursor && my_isspace(cmdline[cursor-1]) )
489 cursor--;
491 while ( cursor && !my_isspace(cmdline[cursor-1]) )
492 cursor--;
494 memmove(cmdline+cursor, cmdline+prevcursor, len-prevcursor+1);
495 len -= (cursor-prevcursor);
496 redraw = 1;
498 break;
500 case KEY_LEFT:
501 case KEY_CTRL('B'):
502 if ( cursor ) {
503 cursor--;
504 redraw = 1;
506 break;
508 case KEY_RIGHT:
509 case KEY_CTRL('F'):
510 if ( cursor < len ) {
511 putchar(cmdline[cursor++]);
513 break;
515 case KEY_CTRL('K'):
516 if ( cursor < len ) {
517 cmdline[len = cursor] = '\0';
518 redraw = 1;
520 break;
522 case KEY_HOME:
523 case KEY_CTRL('A'):
524 if ( cursor ) {
525 cursor = 0;
526 redraw = 1;
528 break;
530 case KEY_END:
531 case KEY_CTRL('E'):
532 if ( cursor != len ) {
533 cursor = len;
534 redraw = 1;
536 break;
538 default:
539 if ( key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN-1 ) {
540 if ( cursor == len ) {
541 cmdline[len] = key;
542 cmdline[++len] = '\0';
543 cursor++;
544 putchar(key);
545 prev_len++;
546 } else {
547 memmove(cmdline+cursor+1, cmdline+cursor, len-cursor+1);
548 cmdline[cursor++] = key;
549 len++;
550 redraw = 1;
553 break;
558 static inline int
559 shift_is_held(void)
561 uint8_t shift_bits = *(uint8_t *)0x417;
563 return !!(shift_bits & 0x5d); /* Caps/Scroll/Alt/Shift */
566 static const char *
567 run_menu(void)
569 int key;
570 int done = 0;
571 volatile int entry = defentry, prev_entry = -1;
572 int top = 0, prev_top = -1;
573 int clear = 1, to_clear;
574 const char *cmdline = NULL;
575 volatile clock_t key_timeout, timeout_left, this_timeout;
577 /* Note: for both key_timeout and timeout == 0 means no limit */
578 timeout_left = key_timeout = timeout;
580 /* If we're in shiftkey mode, exit immediately unless a shift key is pressed */
581 if ( shiftkey && !shift_is_held() ) {
582 return menu_entries[defentry].cmdline;
585 /* Handle both local and global timeout */
586 if ( setjmp(timeout_jump) ) {
587 entry = defentry;
589 if ( top < 0 || top < entry-MENU_ROWS+1 )
590 top = max(0, entry-MENU_ROWS+1);
591 else if ( top > entry || top > max(0,nentries-MENU_ROWS) )
592 top = min(entry, max(0,nentries-MENU_ROWS));
594 draw_menu(ontimeout ? -1 : entry, top, 1);
595 cmdline = ontimeout ? ontimeout : menu_entries[entry].cmdline;
596 done = 1;
599 while ( !done ) {
600 if ( entry < 0 )
601 entry = 0;
602 else if ( entry >= nentries )
603 entry = nentries-1;
605 if ( top < 0 || top < entry-MENU_ROWS+1 )
606 top = max(0, entry-MENU_ROWS+1);
607 else if ( top > entry || top > max(0,nentries-MENU_ROWS) )
608 top = min(entry, max(0,nentries-MENU_ROWS));
610 /* Start with a clear screen */
611 if ( clear ) {
612 /* Clear and redraw whole screen */
613 /* Enable ASCII on G0 and DEC VT on G1; do it in this order
614 to avoid confusing the Linux console */
615 clear_screen();
616 clear = 0;
617 prev_entry = prev_top = -1;
620 if ( top != prev_top ) {
621 draw_menu(entry, top, 1);
622 } else if ( entry != prev_entry ) {
623 draw_row(prev_entry-top+4, entry, top, 0, 0);
624 draw_row(entry-top+4, entry, top, 0, 0);
627 prev_entry = entry; prev_top = top;
629 /* Cursor movement cancels timeout */
630 if ( entry != defentry )
631 key_timeout = 0;
633 if ( key_timeout ) {
634 int tol = timeout_left/CLK_TCK;
635 int nc = snprintf(NULL, 0, " Automatic boot in %d seconds ", tol);
636 printf("\033[%d;%dH\1#14 Automatic boot in \1#15%d\1#14 seconds ",
637 TIMEOUT_ROW, 1+((WIDTH-nc)>>1), tol);
638 to_clear = 1;
639 } else {
640 to_clear = 0;
643 this_timeout = min(min(key_timeout, timeout_left), CLK_TCK);
644 key = mygetkey(this_timeout);
646 if ( key != KEY_NONE ) {
647 timeout_left = key_timeout;
648 if ( to_clear )
649 printf("\033[%d;1H\1#00\033[K", TIMEOUT_ROW);
652 switch ( key ) {
653 case KEY_NONE: /* Timeout */
654 /* This is somewhat hacky, but this at least lets the user
655 know what's going on, and still deals with "phantom inputs"
656 e.g. on serial ports.
658 Warning: a timeout will boot the default entry without any
659 password! */
660 if ( key_timeout ) {
661 if ( timeout_left <= this_timeout )
662 longjmp(timeout_jump, 1);
664 timeout_left -= this_timeout;
666 break;
668 case KEY_CTRL('L'):
669 clear = 1;
670 break;
672 case KEY_ENTER:
673 case KEY_CTRL('J'):
674 key_timeout = 0; /* Cancels timeout */
675 if ( menu_entries[entry].passwd ) {
676 clear = 1;
677 done = ask_passwd(menu_entries[entry].passwd);
678 } else {
679 done = 1;
681 cmdline = menu_entries[entry].cmdline;
682 break;
684 case KEY_UP:
685 case KEY_CTRL('P'):
686 if ( entry > 0 ) {
687 entry--;
688 if ( entry < top )
689 top -= MENU_ROWS;
691 break;
693 case KEY_DOWN:
694 case KEY_CTRL('N'):
695 if ( entry < nentries-1 ) {
696 entry++;
697 if ( entry >= top+MENU_ROWS )
698 top += MENU_ROWS;
700 break;
702 case KEY_PGUP:
703 case KEY_LEFT:
704 case KEY_CTRL('B'):
705 case '<':
706 entry -= MENU_ROWS;
707 top -= MENU_ROWS;
708 break;
710 case KEY_PGDN:
711 case KEY_RIGHT:
712 case KEY_CTRL('F'):
713 case '>':
714 case ' ':
715 entry += MENU_ROWS;
716 top += MENU_ROWS;
717 break;
719 case '-':
720 entry--;
721 top--;
722 break;
724 case '+':
725 entry++;
726 top++;
727 break;
729 case KEY_CTRL('A'):
730 case KEY_HOME:
731 top = entry = 0;
732 break;
734 case KEY_CTRL('E'):
735 case KEY_END:
736 entry = nentries - 1;
737 top = max(0, nentries-MENU_ROWS);
738 break;
740 case KEY_TAB:
741 if ( allowedit ) {
742 int ok = 1;
744 key_timeout = 0; /* Cancels timeout */
745 draw_row(entry-top+4, -1, top, 0, 0);
747 if ( menu_master_passwd ) {
748 ok = ask_passwd(NULL);
749 clear_screen();
750 draw_menu(-1, top, 0);
751 } else {
752 /* Erase [Tab] message */
753 printf("\033[%d;1H\1#00\033[K", TABMSG_ROW);
756 if ( ok ) {
757 cmdline = edit_cmdline(menu_entries[entry].cmdline, top);
758 done = !!cmdline;
759 clear = 1; /* In case we hit [Esc] and done is null */
760 } else {
761 draw_row(entry-top+4, entry, top, 0, 0);
764 break;
765 case KEY_CTRL('C'): /* Ctrl-C */
766 case KEY_ESC: /* Esc */
767 if ( allowedit ) {
768 done = 1;
769 clear = 1;
770 key_timeout = 0;
772 draw_row(entry-top+4, -1, top, 0, 0);
774 if ( menu_master_passwd )
775 done = ask_passwd(NULL);
777 break;
778 default:
779 if ( key > 0 && key < 0xFF ) {
780 key &= ~0x20; /* Upper case */
781 if ( menu_hotkeys[key] ) {
782 key_timeout = 0;
783 entry = menu_hotkeys[key] - menu_entries;
784 /* Should we commit at this point? */
787 break;
791 printf("\033[?25h"); /* Show cursor */
793 /* Return the label name so localboot and ipappend work */
794 return cmdline;
798 static void
799 execute(const char *cmdline)
801 #ifdef __COM32__
802 com32sys_t ireg;
803 const char *p;
804 char *q = __com32.cs_bounce;
805 const char *kernel, *args;
807 memset(&ireg, 0, sizeof ireg);
809 kernel = q;
810 p = cmdline;
811 while ( *p && !my_isspace(*p) ) {
812 *q++ = *p++;
814 *q++ = '\0';
816 args = q;
817 while ( *p && my_isspace(*p) )
818 p++;
820 strcpy(q, p);
822 if ( !strcmp(kernel, ".localboot") ) {
823 ireg.eax.w[0] = 0x0014; /* Local boot */
824 ireg.edx.w[0] = strtoul(args, NULL, 0);
825 } else {
826 ireg.eax.w[0] = 0x0016; /* Run kernel image */
827 ireg.esi.w[0] = OFFS(kernel);
828 ireg.ds = SEG(kernel);
829 ireg.ebx.w[0] = OFFS(args);
830 ireg.es = SEG(args);
831 /* ireg.ecx.l = 0; */ /* We do ipappend "manually" */
832 /* ireg.edx.l = 0; */
835 __intcall(0x22, &ireg, NULL);
837 /* If this returns, something went bad; return to menu */
838 #else
839 /* For testing... */
840 printf("\n\033[0m>>> %s\n", cmdline);
841 exit(0);
842 #endif
845 int menu_main(int argc, char *argv[])
847 const char *cmdline;
849 (void)argc;
851 install_default_color_table();
852 fputs("\1#00", stdout);
854 parse_config(argv[1]);
856 if (draw_background && menu_background)
857 draw_background(menu_background);
859 if ( !nentries ) {
860 fputs("No LABEL entries found in configuration file!\n", stdout);
861 return 1; /* Error! */
864 for(;;) {
865 cmdline = run_menu();
867 printf("\033[?25h\033[%d;1H\033[0m", END_ROW);
868 if ( cmdline ) {
869 execute(cmdline);
870 if ( onerror )
871 execute(onerror);
872 } else {
873 return 0; /* Exit */