/* ----------------------------------------------------------------------- * * * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved * Copyright 2009 Intel Corporation; author: H. Peter Anvin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston MA 02110-1301, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- * * * 02.06.2009 Calculate Pack http://www.calculate-linux.org * В исходный код main.c вненсены следующие изменения: * - вывод TABMSG происходит без учета HSHIFT * - клавиши F1 отображают текстовое сообщение только если файл .txt * или .msg * - по клавиши ESC в меню проиходит возврат в главное меню * - модуль аккумулирует неиспользуемые параметры, которые впоследствии * передает дальше * - для указания пункта по умолчанию используется параметры командной * строки * * ----------------------------------------------------------------------- */ /* * menumain.c * * Simple menu system which displays a list and allows the user to select * a command line and/or edit it. */ #include #include #include #include #include #include #include #include #include #include #include #include "calcmenu.h" /* The symbol "cm" always refers to the current menu across this file... */ static struct menu *cm; const struct menu_parameter mparm[NPARAMS] = { [P_WIDTH] = { "width", 0 }, [P_MARGIN] = { "margin", 10 }, [P_PASSWD_MARGIN] = { "passwordmargin", 3 }, [P_MENU_ROWS] = { "rows", 12 }, [P_TABMSG_ROW] = { "tabmsgrow", 18 }, [P_CMDLINE_ROW] = { "cmdlinerow", 18 }, [P_END_ROW] = { "endrow", -1 }, [P_PASSWD_ROW] = { "passwordrow", 11 }, [P_TIMEOUT_ROW] = { "timeoutrow", 20 }, [P_HELPMSG_ROW] = { "helpmsgrow", 22 }, [P_HELPMSGEND_ROW] = { "helpmsgendrow", -1 }, [P_HSHIFT] = { "hshift", 0 }, [P_VSHIFT] = { "vshift", 0 }, [P_HIDDEN_ROW] = { "hiddenrow", -2 }, }; /* These macros assume "cm" is a pointer to the current menu */ #define WIDTH (cm->mparm[P_WIDTH]) #define MARGIN (cm->mparm[P_MARGIN]) #define PASSWD_MARGIN (cm->mparm[P_PASSWD_MARGIN]) #define MENU_ROWS (cm->mparm[P_MENU_ROWS]) #define TABMSG_ROW (cm->mparm[P_TABMSG_ROW]+VSHIFT) #define CMDLINE_ROW (cm->mparm[P_CMDLINE_ROW]+VSHIFT) #define END_ROW (cm->mparm[P_END_ROW]) #define PASSWD_ROW (cm->mparm[P_PASSWD_ROW]+VSHIFT) #define TIMEOUT_ROW (cm->mparm[P_TIMEOUT_ROW]+VSHIFT) #define HELPMSG_ROW (cm->mparm[P_HELPMSG_ROW]+VSHIFT) #define HELPMSGEND_ROW (cm->mparm[P_HELPMSGEND_ROW]) #define HSHIFT (cm->mparm[P_HSHIFT]) #define VSHIFT (cm->mparm[P_VSHIFT]) #define HIDDEN_ROW (cm->mparm[P_HIDDEN_ROW]) /* transfering buffer by default */ char default_tail_cmdline[MAX_CMDLINE_LEN]; /* transfering buffer */ char tail_cmdline[MAX_CMDLINE_LEN]; /* number of parameter in defaultparam */ int default_menu; /* parameter for default label menu */ char defaultparam[50]; /* buffer for concatinating cmdline and tail_cmdline */ char newcmdline[MAX_CMDLINE_LEN]; /* primary config name */ char startconfig[256]; static char * pad_line(const char *text, int align, int width) { static char buffer[MAX_CMDLINE_LEN]; int n, p; if ( width >= (int) sizeof buffer ) return NULL; /* Can't do it */ n = strlen(text); if ( n >= width ) n = width; memset(buffer, ' ', width); buffer[width] = 0; p = ((width-n)*align)>>1; memcpy(buffer+p, text, n); return buffer; } /* Display an entry, with possible hotkey highlight. Assumes that the current attribute is the non-hotkey one, and will guarantee that as an exit condition as well. */ static void display_entry(const struct menu_entry *entry, const char *attrib, const char *hotattrib, int width) { const char *p = entry->displayname; char marker; if (!p) p = ""; switch (entry->action) { case MA_SUBMENU: marker = '>'; break; case MA_EXIT: marker = '<'; break; default: marker = 0; break; } if (marker) width -= 2; while ( width ) { if ( *p ) { if ( *p == '^' ) { p++; if ( *p && ((unsigned char)*p & ~0x20) == entry->hotkey ) { fputs(hotattrib, stdout); putchar(*p++); fputs(attrib, stdout); width--; } } else { putchar(*p++); width--; } } else { putchar(' '); width--; } } if (marker) { putchar(' '); putchar(marker); } } static void draw_row(int y, int sel, int top, int sbtop, int sbbot) { int i = (y-4-VSHIFT)+top; int dis = (i < cm->nentries) && is_disabled(cm->menu_entries[i]); printf("\033[%d;%dH\1#1\016x\017%s ", y, MARGIN+1+HSHIFT, (i == sel) ? "\1#5" : dis ? "\2#17" : "\1#3"); if ( i >= cm->nentries ) { fputs(pad_line("", 0, WIDTH-2*MARGIN-4), stdout); } else { display_entry(cm->menu_entries[i], (i == sel) ? "\1#5" : dis ? "\2#17" : "\1#3", (i == sel) ? "\1#6" : dis ? "\2#17" : "\1#4", WIDTH-2*MARGIN-4); } if ( cm->nentries <= MENU_ROWS ) { printf(" \1#1\016x\017"); } else if ( sbtop > 0 ) { if ( y >= sbtop && y <= sbbot ) printf(" \1#7\016a\017"); else printf(" \1#1\016x\017"); } else { putchar(' '); /* Don't modify the scrollbar */ } } static jmp_buf timeout_jump; int mygetkey(clock_t timeout) { clock_t t0, t; clock_t tto, to; int key; if ( !totaltimeout ) return get_key(stdin, timeout); for (;;) { tto = min(totaltimeout, INT_MAX); to = timeout ? min(tto, timeout) : tto; t0 = times(NULL); key = get_key(stdin, to); t = times(NULL) - t0; if ( totaltimeout <= t ) longjmp(timeout_jump, 1); totaltimeout -= t; if ( key != KEY_NONE ) return key; if ( timeout ) { if ( timeout <= t ) return KEY_NONE; timeout -= t; } } } static int ask_passwd(const char *menu_entry) { char user_passwd[WIDTH], *p; int done; int key; int x; int rv; printf("\033[%d;%dH\2#11\016l", PASSWD_ROW, PASSWD_MARGIN+1); for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ ) putchar('q'); printf("k\033[%d;%dHx", PASSWD_ROW+1, PASSWD_MARGIN+1); for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ ) putchar(' '); printf("x\033[%d;%dHm", PASSWD_ROW+2, PASSWD_MARGIN+1); for ( x = 2 ; x <= WIDTH-2*PASSWD_MARGIN-1 ; x++ ) putchar('q'); printf("j\017\033[%d;%dH\2#12 %s \033[%d;%dH\2#13", PASSWD_ROW, (WIDTH-(strlen(cm->messages[MSG_PASSPROMPT])+2))/2, cm->messages[MSG_PASSPROMPT], PASSWD_ROW+1, PASSWD_MARGIN+3); drain_keyboard(); /* Actually allow user to type a password, then compare to the SHA1 */ done = 0; p = user_passwd; while ( !done ) { key = mygetkey(0); switch ( key ) { case KEY_ENTER: case KEY_CTRL('J'): done = 1; break; case KEY_ESC: case KEY_CTRL('C'): p = user_passwd; /* No password entered */ done = 1; break; case KEY_BACKSPACE: case KEY_DEL: case KEY_DELETE: if ( p > user_passwd ) { printf("\b \b"); p--; } break; case KEY_CTRL('U'): while ( p > user_passwd ) { printf("\b \b"); p--; } break; default: if ( key >= ' ' && key <= 0xFF && (p-user_passwd) < WIDTH-2*PASSWD_MARGIN-5 ) { *p++ = key; putchar('*'); } break; } } if ( p == user_passwd ) return 0; /* No password entered */ *p = '\0'; rv = (cm->menu_master_passwd && passwd_compare(cm->menu_master_passwd, user_passwd)) || (menu_entry && passwd_compare(menu_entry, user_passwd)); /* Clean up */ memset(user_passwd, 0, WIDTH); drain_keyboard(); return rv; } static void draw_menu(int sel, int top, int edit_line) { int x, y; int sbtop = 0, sbbot = 0; const char *tabmsg; int tabmsg_len; if ( cm->nentries > MENU_ROWS ) { int sblen = max(MENU_ROWS*MENU_ROWS/cm->nentries, 1); sbtop = (MENU_ROWS-sblen+1)*top/(cm->nentries-MENU_ROWS+1); sbbot = sbtop+sblen-1; sbtop += 4; sbbot += 4; /* Starting row of scrollbar */ } printf("\033[%d;%dH\1#1\016l", VSHIFT+1, HSHIFT+MARGIN+1); for ( x = 2+HSHIFT ; x <= (WIDTH-2*MARGIN-1)+HSHIFT ; x++ ) putchar('q'); printf("k\033[%d;%dH\1#1x\017\1#2 %s \1#1\016x", VSHIFT+2, HSHIFT+MARGIN+1, pad_line(cm->title, 1, WIDTH-2*MARGIN-4)); printf("\033[%d;%dH\1#1t", VSHIFT+3, HSHIFT+MARGIN+1); for ( x = 2+HSHIFT ; x <= (WIDTH-2*MARGIN-1)+HSHIFT ; x++ ) putchar('q'); fputs("u\017", stdout); for ( y = 4+VSHIFT ; y < 4+VSHIFT+MENU_ROWS ; y++ ) draw_row(y, sel, top, sbtop, sbbot); printf("\033[%d;%dH\1#1\016m", y, HSHIFT+MARGIN+1); for ( x = 2+HSHIFT ; x <= (WIDTH-2*MARGIN-1)+HSHIFT ; x++ ) putchar('q'); fputs("j\017", stdout); if ( edit_line && cm->allowedit && !cm->menu_master_passwd ) tabmsg = cm->messages[MSG_TAB]; else tabmsg = cm->messages[MSG_NOTAB]; tabmsg_len = strlen(tabmsg); printf("\1#8\033[%d;%dH%s", TABMSG_ROW, (79-tabmsg_len)>>1, tabmsg); printf("\1#0\033[%d;1H", END_ROW); } static void clear_screen(void) { fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout); } static void display_help(const char *text) { int row; const char *p; if (!text) { text = ""; printf("\1#0\033[%d;1H", HELPMSG_ROW); } else { printf("\2#16\033[%d;1H", HELPMSG_ROW); } for (p = text, row = HELPMSG_ROW; *p && row <= HELPMSGEND_ROW; p++) { switch (*p) { case '\r': case '\f': case '\v': case '\033': break; case '\n': printf("\033[K\033[%d;1H", ++row); break; default: putchar(*p); } } fputs("\033[K", stdout); while (row <= HELPMSGEND_ROW) { printf("\033[K\033[%d;1H", ++row); } } static int show_fkey(int key) { int fkey; while (1) { switch (key) { case KEY_F1: fkey = 0; break; case KEY_F2: fkey = 1; break; case KEY_F3: fkey = 2; break; case KEY_F4: fkey = 3; break; case KEY_F5: fkey = 4; break; case KEY_F6: fkey = 5; break; case KEY_F7: fkey = 6; break; case KEY_F8: fkey = 7; break; case KEY_F9: fkey = 8; break; case KEY_F10: fkey = 9; break; case KEY_F11: fkey = 10; break; case KEY_F12: fkey = 11; break; default: fkey = -1; break; } if (fkey == -1) return -2; if( cm->fkeyhelp[fkey].textname ) { int slent = strlen(cm->fkeyhelp[fkey].textname); if (slent<4 || (strcmp(cm->fkeyhelp[fkey].textname+slent-4,".txt") && strcmp(cm->fkeyhelp[fkey].textname+slent-4,".msg"))) { return fkey; } } if (cm->fkeyhelp[fkey].textname) { key = show_message_file(cm->fkeyhelp[fkey].textname, cm->fkeyhelp[fkey].background); return -1; } else return -2; } } const char * edit_cmdline(const char *input, int top) { static char cmdline[MAX_CMDLINE_LEN]; int key, len, prev_len, cursor; int redraw = 1; /* We enter with the menu already drawn */ strncpy(cmdline, input, MAX_CMDLINE_LEN); cmdline[MAX_CMDLINE_LEN-1] = '\0'; len = cursor = strlen(cmdline); prev_len = 0; for (;;) { if ( redraw > 1 ) { /* Clear and redraw whole screen */ /* Enable ASCII on G0 and DEC VT on G1; do it in this order to avoid confusing the Linux console */ clear_screen(); draw_menu(-1, top, 1); prev_len = 0; } if ( redraw > 0 ) { /* Redraw the command line */ printf("\033[?25l\033[%d;1H\1#9> \2#10%s", CMDLINE_ROW, pad_line(cmdline, 0, max(len, prev_len))); printf("\2#10\033[%d;3H%s\033[?25h", CMDLINE_ROW, pad_line(cmdline, 0, cursor)); prev_len = len; redraw = 0; } key = mygetkey(0); switch( key ) { case KEY_CTRL('L'): redraw = 2; break; case KEY_ENTER: case KEY_CTRL('J'): return cmdline; case KEY_ESC: case KEY_CTRL('C'): return NULL; case KEY_BACKSPACE: case KEY_DEL: if ( cursor ) { memmove(cmdline+cursor-1, cmdline+cursor, len-cursor+1); len--; cursor--; redraw = 1; } break; case KEY_CTRL('D'): case KEY_DELETE: if ( cursor < len ) { memmove(cmdline+cursor, cmdline+cursor+1, len-cursor); len--; redraw = 1; } break; case KEY_CTRL('U'): if ( len ) { len = cursor = 0; cmdline[len] = '\0'; redraw = 1; } break; case KEY_CTRL('W'): if ( cursor ) { int prevcursor = cursor; while ( cursor && my_isspace(cmdline[cursor-1]) ) cursor--; while ( cursor && !my_isspace(cmdline[cursor-1]) ) cursor--; memmove(cmdline+cursor, cmdline+prevcursor, len-prevcursor+1); len -= (cursor-prevcursor); redraw = 1; } break; case KEY_LEFT: case KEY_CTRL('B'): if ( cursor ) { cursor--; redraw = 1; } break; case KEY_RIGHT: case KEY_CTRL('F'): if ( cursor < len ) { putchar(cmdline[cursor++]); } break; case KEY_CTRL('K'): if ( cursor < len ) { cmdline[len = cursor] = '\0'; redraw = 1; } break; case KEY_HOME: case KEY_CTRL('A'): if ( cursor ) { cursor = 0; redraw = 1; } break; case KEY_END: case KEY_CTRL('E'): if ( cursor != len ) { cursor = len; redraw = 1; } break; case KEY_F1: case KEY_F2: case KEY_F3: case KEY_F4: case KEY_F5: case KEY_F6: case KEY_F7: case KEY_F8: case KEY_F9: case KEY_F10: case KEY_F11: case KEY_F12: show_fkey(key); redraw = 1; break; default: if ( key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN-1 ) { if ( cursor == len ) { cmdline[len] = key; cmdline[++len] = '\0'; cursor++; putchar(key); prev_len++; } else { memmove(cmdline+cursor+1, cmdline+cursor, len-cursor+1); cmdline[cursor++] = key; len++; redraw = 1; } } break; } } } static inline int shift_is_held(void) { uint8_t shift_bits = *(uint8_t *)0x417; return !!(shift_bits & 0x5d); /* Caps/Scroll/Alt/Shift */ } static void print_timeout_message(int tol, int row, const char *msg) { char buf[256]; int nc = 0, nnc; const char *tp = msg; char tc; char *tq = buf; while ((size_t)(tq-buf) < (sizeof buf-16) && (tc = *tp)) { tp++; if (tc == '#') { nnc = sprintf(tq, "\2#15%d\2#14", tol); tq += nnc; nc += nnc-8; /* 8 formatting characters */ } else if (tc == '{') { /* Deal with {singular[,dual],plural} constructs */ struct { const char *s, *e; } tx[3]; const char *tpp; int n = 0; memset(tx, 0, sizeof tx); tx[0].s = tp; while (*tp && *tp != '}') { if (*tp == ',' && n < 2) { tx[n].e = tp; n++; tx[n].s = tp+1; } tp++; } tx[n].e = tp; if (*tp) tp++; /* Skip final bracket */ if (!tx[1].s) tx[1] = tx[0]; if (!tx[2].s) tx[2] = tx[1]; /* Now [0] is singular, [1] is dual, and [2] is plural, even if the user only specified some of them. */ switch (tol) { case 1: n = 0; break; case 2: n = 1; break; default: n = 2; break; } for (tpp = tx[n].s; tpp < tx[n].e; tpp++) { if ((size_t)(tq-buf) < (sizeof buf)) { *tq++ = *tpp; nc++; } } } else { *tq++ = tc; nc++; } } *tq = '\0'; /* Let's hope 4 spaces on each side is enough... */ printf("\033[%d;%dH\2#14 %s ", row, HSHIFT+1+((WIDTH-nc-8)>>1), buf); } /* Set the background screen, etc. */ static void prepare_screen_for_menu(void) { console_color_table = cm->color_table; console_color_table_size = menu_color_table_size; set_background(cm->menu_background); } static const char * do_hidden_menu(void) { int key; int timeout_left, this_timeout; clear_screen(); if ( !setjmp(timeout_jump) ) { timeout_left = cm->timeout; while (!cm->timeout || timeout_left) { int tol = timeout_left/CLK_TCK; print_timeout_message(tol, HIDDEN_ROW, cm->messages[MSG_AUTOBOOT]); this_timeout = min(timeout_left, CLK_TCK); key = mygetkey(this_timeout); if (key != KEY_NONE) return NULL; /* Key pressed */ timeout_left -= this_timeout; } } return cm->menu_entries[cm->defentry]->cmdline; /* Default entry */ } static const char * run_menu(void) { int key; int done = 0; volatile int entry = cm->curentry; int prev_entry = -1; volatile int top = cm->curtop; int prev_top = -1; int clear = 1, to_clear; const char *cmdline = NULL; volatile clock_t key_timeout, timeout_left, this_timeout; const struct menu_entry *me; /* Note: for both key_timeout and timeout == 0 means no limit */ timeout_left = key_timeout = cm->timeout; /* If we're in shiftkey mode, exit immediately unless a shift key is pressed */ if ( shiftkey && !shift_is_held() ) { return cm->menu_entries[cm->defentry]->cmdline; } else { shiftkey = 0; } /* Do this before hiddenmenu handling, so we show the background */ prepare_screen_for_menu(); /* Handle hiddenmenu */ if ( hiddenmenu ) { cmdline = do_hidden_menu(); if (cmdline) return cmdline; /* Otherwise display the menu now; the timeout has already been cancelled, since the user pressed a key. */ hiddenmenu = 0; key_timeout = 0; } /* Handle both local and global timeout */ if ( setjmp(timeout_jump) ) { entry = cm->defentry; if ( top < 0 || top < entry-MENU_ROWS+1 ) top = max(0, entry-MENU_ROWS+1); else if ( top > entry || top > max(0, cm->nentries-MENU_ROWS) ) top = min(entry, max(0, cm->nentries-MENU_ROWS)); draw_menu(cm->ontimeout ? -1 : entry, top, 1); cmdline = cm->ontimeout ? cm->ontimeout : cm->menu_entries[entry]->cmdline; done = 1; } char *p = strstr(tail_cmdline,defaultparam); if(p) { /* if it is param - not inner part str */ if( p == tail_cmdline || *(p-1) == ' ' ) { p += strlen(defaultparam)+1; char *params1[256]; char str1[512]; strcpy(str1,p); /* Truncates the end of the string containing the rest of the parameters */ if(strchr(str1,' ')) *strchr(str1,' ')=0; /* spliting str1 to params */ int n = splitstr(str1,',',params1,255); if( default_menu < n ) { for(int i=0;i< cm->nentries;i++) { if(!strcmp(cm->menu_entries[i]->label,params1[default_menu])) { entry = i; break; } } } } } while ( !done ) { if (entry <= 0) { entry = 0; while (entry < cm->nentries && is_disabled(cm->menu_entries[entry])) entry++; } if (entry >= cm->nentries) { entry = cm->nentries-1; while (entry > 0 && is_disabled(cm->menu_entries[entry])) entry--; } me = cm->menu_entries[entry]; if ( top < 0 || top < entry-MENU_ROWS+1 ) top = max(0, entry-MENU_ROWS+1); else if ( top > entry || top > max(0, cm->nentries-MENU_ROWS) ) top = min(entry, max(0, cm->nentries-MENU_ROWS)); /* Start with a clear screen */ if ( clear ) { /* Clear and redraw whole screen */ /* Enable ASCII on G0 and DEC VT on G1; do it in this order to avoid confusing the Linux console */ if (clear >= 2) prepare_screen_for_menu(); printf("\033[?25l"); /* Hide cursor */ clear_screen(); /* Disable flashing screen */ clear = 0; prev_entry = prev_top = -1; } if ( top != prev_top ) { draw_menu(entry, top, 1); display_help(me->helptext); } else if ( entry != prev_entry ) { draw_row(prev_entry-top+4+VSHIFT, entry, top, 0, 0); draw_row(entry-top+4+VSHIFT, entry, top, 0, 0); display_help(me->helptext); } prev_entry = entry; prev_top = top; cm->curentry = entry; cm->curtop = top; /* Cursor movement cancels timeout */ if ( entry != cm->defentry ) key_timeout = 0; if ( key_timeout ) { int tol = timeout_left/CLK_TCK; print_timeout_message(tol, TIMEOUT_ROW, cm->messages[MSG_AUTOBOOT]); to_clear = 1; } else { to_clear = 0; } this_timeout = min(min(key_timeout, timeout_left), (clock_t)CLK_TCK); key = mygetkey(this_timeout); if ( key != KEY_NONE ) { timeout_left = key_timeout; if ( to_clear ) printf("\033[%d;1H\1#0\033[K", TIMEOUT_ROW); } switch ( key ) { case KEY_NONE: /* Timeout */ /* This is somewhat hacky, but this at least lets the user know what's going on, and still deals with "phantom inputs" e.g. on serial ports. Warning: a timeout will boot the default entry without any password! */ if ( key_timeout ) { if ( timeout_left <= this_timeout ) longjmp(timeout_jump, 1); timeout_left -= this_timeout; } break; case KEY_CTRL('L'): clear = 1; break; case KEY_ENTER: case KEY_CTRL('J'): key_timeout = 0; /* Cancels timeout */ if ( me->passwd ) { clear = 1; done = ask_passwd(me->passwd); } else { done = 1; } cmdline = NULL; if (done) { switch (me->action) { case MA_CMD: cmdline = me->cmdline; break; case MA_SUBMENU: case MA_GOTO: case MA_EXIT: done = 0; clear = 2; cm = me->submenu; entry = cm->curentry; top = cm->curtop; break; case MA_QUIT: /* Quit menu system */ done = 1; clear = 1; draw_row(entry-top+4+VSHIFT, -1, top, 0, 0); break; default: done = 0; break; } } if (done && !me->passwd) { /* Only save a new default if we don't have a password... */ if (me->save && me->label) { syslinux_setadv(ADV_MENUSAVE, strlen(me->label), me->label); syslinux_adv_write(); } } break; case KEY_UP: case KEY_CTRL('P'): while (entry > 0) { entry--; if (entry < top) top -= MENU_ROWS; if (!is_disabled(cm->menu_entries[entry])) break; } break; case KEY_DOWN: case KEY_CTRL('N'): while (entry < cm->nentries-1) { entry++; if (entry >= top+MENU_ROWS) top += MENU_ROWS; if (!is_disabled(cm->menu_entries[entry])) break; } break; case KEY_PGUP: case KEY_LEFT: case KEY_CTRL('B'): case '<': entry -= MENU_ROWS; top -= MENU_ROWS; while (entry > 0 && is_disabled(cm->menu_entries[entry])) { entry--; if (entry < top) top -= MENU_ROWS; } break; case KEY_PGDN: case KEY_RIGHT: case KEY_CTRL('F'): case '>': case ' ': entry += MENU_ROWS; top += MENU_ROWS; while (entry < cm->nentries-1 && is_disabled(cm->menu_entries[entry])) { entry++; if (entry >= top+MENU_ROWS) top += MENU_ROWS; } break; case '-': while (entry > 0) { entry--; top--; if (!is_disabled(cm->menu_entries[entry])) break; } break; case '+': while (entry < cm->nentries-1) { entry++; top++; if (!is_disabled(cm->menu_entries[entry])) break; } break; case KEY_CTRL('A'): case KEY_HOME: top = entry = 0; break; case KEY_CTRL('E'): case KEY_END: entry = cm->nentries - 1; top = max(0, cm->nentries-MENU_ROWS); break; case KEY_F1: case KEY_F2: case KEY_F3: case KEY_F4: case KEY_F5: case KEY_F6: case KEY_F7: case KEY_F8: case KEY_F9: case KEY_F10: case KEY_F11: case KEY_F12: { int res = show_fkey(key); /* Adds ability to initizalize other menu on func keys */ if( res >= 0 ) { strncpy(newcmdline,cm->fkeyhelp[res].textname,512); strncat(newcmdline," ",512); strncat(newcmdline,cm->fkeyhelp[res].background,512); return newcmdline; } if(res == -1 ) { clear = 1; } } break; case KEY_TAB: if ( cm->allowedit && me->action == MA_CMD ) { int ok = 1; key_timeout = 0; /* Cancels timeout */ draw_row(entry-top+4+VSHIFT, -1, top, 0, 0); if ( cm->menu_master_passwd ) { ok = ask_passwd(NULL); clear_screen(); draw_menu(-1, top, 0); } else { /* Erase [Tab] message and help text*/ printf("\033[%d;1H\1#0\033[K", TABMSG_ROW); display_help(NULL); } if ( ok ) { strncpy(newcmdline, me->cmdline, MAX_CMDLINE_LEN-1); strncat(newcmdline, tail_cmdline, MAX_CMDLINE_LEN-1); cmdline = edit_cmdline(newcmdline, top); done = !!cmdline; clear = 1; /* In case we hit [Esc] and done is null */ } else { draw_row(entry-top+4+VSHIFT, entry, top, 0, 0); } } break; case KEY_CTRL('C'): /* Ctrl-C */ case KEY_ESC: /* Esc */ if ( cm->parent ) { cm = cm->parent; clear = 2; entry = cm->curentry; top = cm->curtop; } else { strcpy(newcmdline,"calcmenu.c32 "); strncat(newcmdline,startconfig,255); return newcmdline; } break; default: if ( key > 0 && key < 0xFF ) { key &= ~0x20; /* Upper case */ if ( cm->menu_hotkeys[key] ) { key_timeout = 0; entry = cm->menu_hotkeys[key]->entry; /* Should we commit at this point? */ } } break; } } printf("\033[?25h"); /* Show cursor */ /* Return the label name so localboot and ipappend work */ return cmdline; } int menu_main(int argc, char *argv[]) { const char *cmdline; struct menu *m; int rows, cols; int i; *defaultparam = '\0'; *startconfig = '\0'; (void)argc; console_prepare(); if (getscreensize(1, &rows, &cols)) { /* Unknown screen size? */ rows = 24; cols = 80; } default_menu = -1; parse_configs(argv+1); for(;;) { /* Some postprocessing for all menus */ for (m = menu_list; m; m = m->next) { if (!m->mparm[P_WIDTH]) m->mparm[P_WIDTH] = cols; /* If anyone has specified negative parameters, consider them relative to the bottom row of the screen. */ for (i = 0; i < NPARAMS; i++) if (m->mparm[i] < 0) m->mparm[i] = max(m->mparm[i]+rows, 0); } if ( !cm->nentries ) { fputs("Initial menu has no LABEL entries!\n", stdout); return 1; /* Error! */ } cm = start_menu; for(;;) { cmdline = run_menu(); strncpy(newcmdline,cmdline,MAX_CMDLINE_LEN-1); if( strlen(newcmdline) < MAX_CMDLINE_LEN-1) strncat(newcmdline,tail_cmdline,MAX_CMDLINE_LEN-1-strlen(newcmdline)); cmdline = newcmdline; printf("\033[?25h\033[%d;1H\033[0m", END_ROW); console_cleanup(); if ( strstr(cmdline,"calcmenu.c32") ) { char *params[100]; char *p = cmdline; *p = ' '; for( int i=0;*p && i<99;p++) { if( *p == ' ') { *p = '\0'; } else if( !*(p-1)) { params[i] = p; params[++i] = NULL; } } /* Erase previous content of tail */ *tail_cmdline = '\0'; /* Erase previous of default param for menu */ *defaultparam = '\0'; default_menu = 0; parse_configs(params+1); // обновить меню break; } if ( cmdline ) { execute(cmdline, KT_NONE); if ( cm->onerror ) execute(cm->onerror, KT_NONE); } else { return 0; /* Exit */ } console_prepare(); /* If we're looping... */ } } }