You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1207 lines
27 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* ----------------------------------------------------------------------- *
*
* 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 <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <consoles.h>
#include <getkey.h>
#include <minmax.h>
#include <setjmp.h>
#include <limits.h>
#include <com32.h>
#include <syslinux/adv.h>
#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;
if ( done )
tail_cmdline[0] = NULL;
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... */
}
}
}