|
|
|
|
/* ----------------------------------------------------------------------- *
|
|
|
|
|
*
|
|
|
|
|
* 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 */
|
|
|
|
|
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... */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|