📄 menu.c
字号:
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 && (cmdline[cursor-1] <= ' ') ) cursor--; while ( cursor && (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; 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 voidclear_screen(void){ printf("\033e\033%%@\033)0\033(B%s\033[?25l\033[2J", menu_attrib->screen);}static const char *run_menu(void){ int key; int done = 0; volatile int entry = defentry, prev_entry = -1; int top = 0, prev_top = -1; int clear = 1, to_clear; const char *cmdline = NULL; volatile clock_t key_timeout, timeout_left, this_timeout; /* Note: for both key_timeout and timeout == 0 means no limit */ timeout_left = key_timeout = timeout; /* Handle both local and global timeout */ if ( setjmp(timeout_jump) ) { entry = defentry; if ( top < 0 || top < entry-MENU_ROWS+1 ) top = max(0, entry-MENU_ROWS+1); else if ( top > entry || top > max(0,nentries-MENU_ROWS) ) top = min(entry, max(0,nentries-MENU_ROWS)); draw_menu(ontimeout ? -1 : entry, top, 1); cmdline = ontimeout ? ontimeout : menu_entries[entry].cmdline; done = 1; } while ( !done ) { if ( entry < 0 ) entry = 0; else if ( entry >= nentries ) entry = nentries-1; if ( top < 0 || top < entry-MENU_ROWS+1 ) top = max(0, entry-MENU_ROWS+1); else if ( top > entry || top > max(0,nentries-MENU_ROWS) ) top = min(entry, max(0,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 */ clear_screen(); clear = 0; prev_entry = prev_top = -1; } if ( top != prev_top ) { draw_menu(entry, top, 1); } else if ( entry != prev_entry ) { draw_row(prev_entry-top+4, entry, top, 0, 0); draw_row(entry-top+4, entry, top, 0, 0); } prev_entry = entry; prev_top = top; /* Cursor movement cancels timeout */ if ( entry != defentry ) key_timeout = 0; if ( key_timeout ) { int tol = timeout_left/CLK_TCK; int nc = snprintf(NULL, 0, " Automatic boot in %d seconds ", tol); printf("\033[%d;%dH%s Automatic boot in %s%d%s seconds ", TIMEOUT_ROW, 1+((WIDTH-nc)>>1), menu_attrib->timeout_msg, menu_attrib->timeout, tol, menu_attrib->timeout_msg); to_clear = 1; } else { to_clear = 0; } this_timeout = min(min(key_timeout, timeout_left), CLK_TCK); key = mygetkey(this_timeout); if ( key != KEY_NONE ) { timeout_left = key_timeout; if ( to_clear ) printf("\033[%d;1H%s\033[K", TIMEOUT_ROW, menu_attrib->screen); } 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 ( menu_entries[entry].passwd ) { clear = 1; done = ask_passwd(menu_entries[entry].passwd); } else { done = 1; } cmdline = menu_entries[entry].cmdline; break; case KEY_UP: case KEY_CTRL('P'): if ( entry > 0 ) { entry--; if ( entry < top ) top -= MENU_ROWS; } break; case KEY_DOWN: case KEY_CTRL('N'): if ( entry < nentries-1 ) { entry++; if ( entry >= top+MENU_ROWS ) top += MENU_ROWS; } break; case KEY_PGUP: case KEY_LEFT: case KEY_CTRL('B'): case '<': entry -= MENU_ROWS; top -= MENU_ROWS; break; case KEY_PGDN: case KEY_RIGHT: case KEY_CTRL('F'): case '>': case ' ': entry += MENU_ROWS; top += MENU_ROWS; break; case '-': entry--; top--; break; case '+': entry++; top++; break; case KEY_CTRL('A'): case KEY_HOME: top = entry = 0; break; case KEY_CTRL('E'): case KEY_END: entry = nentries - 1; top = max(0, nentries-MENU_ROWS); break; case KEY_TAB: if ( allowedit ) { int ok = 1; key_timeout = 0; /* Cancels timeout */ draw_row(entry-top+4, -1, top, 0, 0); if ( menu_master_passwd ) { ok = ask_passwd(NULL); clear_screen(); draw_menu(-1, top, 0); } else { /* Erase [Tab] message */ printf("\033[%d;1H%s\033[K", TABMSG_ROW, menu_attrib->screen); } if ( ok ) { cmdline = edit_cmdline(menu_entries[entry].cmdline, top); done = !!cmdline; clear = 1; /* In case we hit [Esc] and done is null */ } else { draw_row(entry-top+4, entry, top, 0, 0); } } break; case KEY_CTRL('C'): /* Ctrl-C */ case KEY_ESC: /* Esc */ if ( allowedit ) { done = 1; clear = 1; key_timeout = 0; draw_row(entry-top+4, -1, top, 0, 0); if ( menu_master_passwd ) done = ask_passwd(NULL); } break; default: if ( key > 0 && key < 0xFF ) { key &= ~0x20; /* Upper case */ if ( menu_hotkeys[key] ) { key_timeout = 0; entry = menu_hotkeys[key] - menu_entries; /* Should we commit at this point? */ } } break; } } printf("\033[?25h"); /* Show cursor */ /* Return the label name so localboot and ipappend work */ return cmdline;}static voidexecute(const char *cmdline){#ifdef __COM32__ com32sys_t ireg; const char *p; char *q = __com32.cs_bounce; const char *kernel, *args; memset(&ireg, 0, sizeof ireg); kernel = q; p = cmdline; while ( *p && !isspace(*p) ) { *q++ = *p++; } *q++ = '\0'; args = q; while ( *p && isspace(*p) ) p++; strcpy(q, p); if ( !strcmp(kernel, ".localboot") ) { ireg.eax.w[0] = 0x0014; /* Local boot */ ireg.edx.w[0] = strtoul(args, NULL, 0); } else { ireg.eax.w[0] = 0x0016; /* Run kernel image */ ireg.esi.w[0] = OFFS(kernel); ireg.ds = SEG(kernel); ireg.ebx.w[0] = OFFS(args); ireg.es = SEG(args); /* ireg.ecx.l = 0; */ /* We do ipappend "manually" */ /* ireg.edx.l = 0; */ } __intcall(0x22, &ireg, NULL); /* If this returns, something went bad; return to menu */#else /* For testing... */ printf("\n\033[0m>>> %s\n", cmdline); exit(0);#endif}int main(int argc, char *argv[]){ const char *cmdline; (void)argc; console_ansi_raw(); parse_config(argv[1]); if ( !nentries ) { fputs("No LABEL entries found in configuration file!\n", stdout); return 1; /* Error! */ } for(;;) { cmdline = run_menu(); printf("\033[?25h\033[%d;1H\033[0m", END_ROW); if ( cmdline ) execute(cmdline); else return 0; /* Exit */ }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -