diff options
-rw-r--r-- | com32/libutil/include/minmax.h | 44 | ||||
-rw-r--r-- | com32/modules/menu.c | 240 |
2 files changed, 284 insertions, 0 deletions
diff --git a/com32/libutil/include/minmax.h b/com32/libutil/include/minmax.h new file mode 100644 index 00000000..319db164 --- /dev/null +++ b/com32/libutil/include/minmax.h @@ -0,0 +1,44 @@ +#ident "$Id$" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#ifndef _MINMAX_H +#define _MINMAX_H + +/* + * minmax.h: Type-independent safe min/max macros + */ + +#define min(x,y) ({ __typeof(x) xx = (x); \ + __typeof(y) yy = (y); \ + xx < yy ? xx : yy; }) +#define max(x,y) ({ __typeof(x) xx = (x); \ + __typeof(y) yy = (y); \ + xx > yy ? xx : yy; }) + +#endif /* _MINMAX_H */ + diff --git a/com32/modules/menu.c b/com32/modules/menu.c new file mode 100644 index 00000000..357952c9 --- /dev/null +++ b/com32/modules/menu.c @@ -0,0 +1,240 @@ +#ident "$Id$" +/* ----------------------------------------------------------------------- * + * + * Copyright 2004 H. Peter Anvin - All Rights Reserved + * + * 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., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * menu.c + * + * Simple menu system which displays a list and allows the user to select + * a command line and/or edit it. + */ + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <consoles.h> +#include <getkey.h> +#include <minmax.h> +#ifdef __COM32__ +#include <com32.h> +#endif + +struct menu_entry { + const char *displayname; + const char *cmdline; +}; + +struct menu_entry menu_entries[] = + { + { "Test", "vmlinux root=/dev/zero" }, + { "this", "chain.c32 hd0 2" }, + { "entry 3", "runentry val=3" }, + { "entry 4", "runentry val=3" }, + { "entry 5", "runentry val=3" }, + { "entry 6", "runentry val=3" }, + { "entry 7", "runentry val=3" }, + { "entry 8", "runentry val=3" }, + { "entry 9", "runentry val=3" }, + { "entry 10", "runentry val=10" }, + { "entry 11", "runentry val=11" }, + { "entry 12", "runentry val=12" }, + { "entry 13", "runentry val=13" }, + { "entry 14", "runentry val=14" }, + { "entry 15", "runentry val=15" }, + { "entry 16", "runentry val=16" }, + { "entry 17", "runentry val=17" }, + { "entry 18", "runentry val=18" }, + { "entry 19", "runentry val=19" }, + { "entry 20", "runentry val=20" }, + }; + +int nentries = sizeof menu_entries / sizeof(struct menu_entry); +int defentry = 0; +int allowedit = 1; /* Allow edits of the command line */ + +char *menu_title = "This is the menu title"; + +struct menu_attrib { + const char *border; /* Border area */ + const char *title; /* Title bar */ + const char *unsel; /* Unselected menu item */ + const char *sel; /* Selected */ + const char *tabmsg; /* Press [Tab] message */ + const char *cmdmark; /* Command line marker */ + const char *cmdline; /* Command line */ + const char *screen; /* Rest of the screen */ +}; + +const struct menu_attrib default_attrib = { + .border = "\033[0;30;44m", + .title = "\033[1;36;44m", + .unsel = "\033[0;37;44m", + .sel = "\033[0;30;47m", + .tabmsg = "\033[0;31;40m", + .cmdmark = "\033[1;36;40m", + .cmdline = "\033[0;37;40m", + .screen = "\033[0;37;40m", +}; + +const struct menu_attrib *menu_attrib = &default_attrib; + +#define WIDTH 80 +#define MARGIN 10 +#define MENU_ROWS 12 +#define TABMSG_ROW 18 +#define CMDLINE_ROW 20 +#define END_ROW 24 + +char *pad_line(const char *text, int align, int width) +{ + static char buffer[256]; + 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; +} + +void draw_menu(int sel, int top) +{ + int x, y; + + printf("\033[1;%dH%s\311", MARGIN+1, menu_attrib->border); + for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ ) + putchar('\315'); + putchar('\273'); + + printf("\033[2;%dH\272%s %s %s\272", + MARGIN+1, + menu_attrib->title, + pad_line(menu_title, 1, WIDTH-2*MARGIN-4), + menu_attrib->border); + + printf("\033[3;%dH\307", MARGIN+1); + for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ ) + putchar('\304'); + putchar('\266'); + + for ( y = 4 ; y < 4+MENU_ROWS ; y++ ) { + int i = (y-4)+top; + const char *txt = (i >= nentries) ? "" : menu_entries[i].displayname; + + printf("\033[%d;%dH\272%s %s %s\272", + y, MARGIN+1, + (i == sel) ? menu_attrib->sel : menu_attrib->unsel, + pad_line(txt, 0, WIDTH-2*MARGIN-4), + menu_attrib->border); + } + + printf("\033[%d;%dH\310", y, MARGIN+1); + for ( x = 2 ; x <= WIDTH-2*MARGIN-1 ; x++ ) + putchar('\315'); + putchar('\274'); + + if ( allowedit ) + printf("%s\033[%d;1H%s", menu_attrib->tabmsg, TABMSG_ROW, + pad_line("Press [Tab] to edit options", 1, WIDTH)); + + printf("\033[%d;1H%s> %s%s\033[%d;1H", + CMDLINE_ROW, menu_attrib->cmdmark, + menu_attrib->cmdline, + pad_line(menu_entries[sel].cmdline, 0, 255), + END_ROW); +} + +const char *run_menu(void) +{ + int key; + int done = 0; + int entry = defentry; + int top = 0; + + /* Start with a clear screen */ + printf("%s\033[2J", menu_attrib->screen); + + while ( !done ) { + if ( top < entry-MENU_ROWS+1 ) + top = max(entry-MENU_ROWS+1, 0); + else if ( top > entry ) + top = min(entry, nentries-MENU_ROWS+1); + + draw_menu(entry, top); + + gkey: + key = get_key(stdin); + switch ( key ) { + case '\r': + done = 1; + break; + case KEY_UP: + if ( entry > 0 ) + entry--; + break; + case KEY_DOWN: + if ( entry < nentries-1 ) + entry++; + break; + case '\003': /* Ctrl-C */ + case '\033': /* Esc */ + exit(1); /* FIX THIS... do something sane here */ + default: + printf("[%04x]", key); + goto gkey; + } + } + + printf("\033[%d;1H\033[0m", END_ROW); + return menu_entries[defentry].cmdline; +} + + +void __attribute__((noreturn)) execute(const char *cmdline) +{ +#ifdef __COM32__ + static com32sys_t ireg; + + strcpy(__com32.cs_bounce, cmdline); + ireg.eax.w[0] = 0x0003; /* Run command */ + ireg.ebx.w[0] = OFFS(__com32.cs_bounce); + ireg.es = SEG(__com32.cs_bounce); + __intcall(0x22, &ireg, NULL); + exit(255); /* Shouldn't return */ +#else + /* For testing... */ + printf("\n>>> %s\n", cmdline); + exit(0); +#endif +} + +int main(void) +{ + const char *cmdline; + + console_ansi_raw(); + + fputs("\033%@\033(U", stdout); /* Enable CP 437 graphics on a real console */ + + cmdline = run_menu(); + execute(cmdline); +} + + |