diff options
author | Murali Krishnan Ganapathy <gmurali@cs.uchicago.edu> | 2006-01-18 21:59:58 -0600 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2006-01-19 08:53:37 -0800 |
commit | 338537160ab79aa5b88472ffa28d4c8cf6179706 (patch) | |
tree | afbf8d7e4b9b77c95c405637ebf508083e0e8dff /menu | |
parent | e9f0a6a9c46bb2b8806e69ec6b62a00fcb7ff4fa (diff) | |
download | syslinux-338537160ab79aa5b88472ffa28d4c8cf6179706.tar.gz |
Update to the complex menu systemsyslinux-3.20-pre6
Diffstat (limited to 'menu')
-rw-r--r-- | menu/CHANGES | 13 | ||||
-rw-r--r-- | menu/MENU_FORMAT | 277 | ||||
-rw-r--r-- | menu/Makefile | 16 | ||||
-rw-r--r-- | menu/README | 1 | ||||
-rw-r--r-- | menu/TODO | 5 | ||||
-rw-r--r-- | menu/adv_menu.tpl | 452 | ||||
-rw-r--r-- | menu/display.c | 37 | ||||
-rw-r--r-- | menu/libmenu/com32io.c | 18 | ||||
-rw-r--r-- | menu/libmenu/com32io.h | 17 | ||||
-rw-r--r-- | menu/libmenu/help.c | 162 | ||||
-rw-r--r-- | menu/libmenu/help.h | 10 | ||||
-rw-r--r-- | menu/libmenu/menu.c | 88 | ||||
-rw-r--r-- | menu/libmenu/menu.h | 18 | ||||
-rw-r--r-- | menu/libmenu/passwords.c | 6 | ||||
-rw-r--r-- | menu/libmenu/scancodes.h | 11 | ||||
-rw-r--r-- | menu/libmenu/syslnx.c | 47 | ||||
-rw-r--r-- | menu/libmenu/syslnx.h | 17 | ||||
-rw-r--r-- | menu/libmenu/tui.c | 7 | ||||
-rw-r--r-- | menu/libmenu/tui.h | 3 | ||||
-rw-r--r-- | menu/menugen.py | 308 | ||||
-rw-r--r-- | menu/test2.menu | 143 |
21 files changed, 1435 insertions, 221 deletions
diff --git a/menu/CHANGES b/menu/CHANGES index ede6a4fc..ed497ac7 100644 --- a/menu/CHANGES +++ b/menu/CHANGES @@ -3,9 +3,22 @@ Changes in v1.2 * Allowed menu's to have names. Submenu's can be referred to by names instead of their index in the menu system. This allows user to refer to submenus which are not yet part of the menusystem. +* help pages can be longer than one screen * menugen.py: Python script for converting .menu files to C source code + .menu files can be used to descibe most static uses of menu system, + including SubMenus, Checkboxes, RadioButtons, User Authentication and + Context sensitive help. You can also restrict use of certain items + to users with certain credentials. + See MENU_FORMAT for the format of .menu files +* display.c32: Takes the name of the text file to display and displays it + allowing user to scroll through the text. + + USAGE: display.c32 <filename> + + <filename> must be an absolute filename (including the /isolinux part) + Changes in v1.1 --------------- * Additional handler type: Keys handler diff --git a/menu/MENU_FORMAT b/menu/MENU_FORMAT index e34ebf4e..4a294085 100644 --- a/menu/MENU_FORMAT +++ b/menu/MENU_FORMAT @@ -1,68 +1,263 @@ -A .menu file can be used to describe basic menu structures which can be converted into -C code which can then be compiled into a .c32 file for use with SYSLINUX. The format -of a .menu file is similar to an ini file, but with important differences. +A .menu file can be used to describe basic menu structures which can be converted +into C code which can then be compiled into a .c32 file for use with SYSLINUX. +The format of a .menu file is similar to an ini file, but with important +differences. -COMMENTS and Blank lines ------------------------- -Lines starting with # and ; are treated as comments. -Blank lines are used to separate the attributes of one menu item -from another. Multiple blank lines are equivalent to a single one. -In other contexts Blank lines are not significant. +Lines starting with # and ; are treated as comments. Blank lines are used to +separate the attributes of one menu item from another. Multiple blank lines are +equivalent to a single one. In other contexts Blank lines are not significant. Menus ----- Each menu declaration starts with a line containing the name of menu in [ ]. -This name is used for internal purposes only and is not visible to the user of -the system. +This is the "nickname" of the menu and should be different for different menus. +This is not visible to the user of the menu system. The initial menu must +be called "main" The menu declaration is followed by lines which set the attributes of the menu. This is followed by a blank line and followed by declaration of menu items in that menu. -Currently supported menu attributes are -title: the title of this menu -row,col: position where menu should be displayed (defaults to system choosing optimal place) - - -Global Settings ---------------- All lines which occur before the first menu declaration is considered as -a global declaration. Currently supported global settings are - -title: the title of the whole menu system -top,left,bot,right: limits of the window in which menu system should use to display - menu. Defaults to 1,1,23,78 +a global declaration. -Menu item ---------- -Each menu item is declared by setting the following attributes +Abstract Format +--------------- -item: The string displayed to the user -info: Additional information displayed in the status bar -type: exitmenu,submenu or run indicating whether this item represents - an entry which exits this menu, goes to a sub menu or - executes something in SYSLINUX -data: In case of exitmenu, this has no meaning - In case of submenu, this is the name of the submenu - In case of run, this is string to be passed to SYSLINUX for execution +The overall format should look like this -------------------------------------------------------- - -GLOBAL SETTINGS +<GLOBAL SETTINGS> [menuname1] -MENUSETTINGS +<MENU SETTINGS> -ITEMATTR +<ITEM 1> ... +<ITEM N> + [menuname2] -MENUSETTINGS +<MENU SETTINGS> + +<ITEM A> + +<ITEM B> + +---------------------------------------------------------- + +GLOBAL SETTINGS +--------------- +The following global settings are now supported. Many of the keywords +accept what we call a "DOT COMMAND" as argument. Simply put they are +instructions to the menu system to perform certain actions. +The syntax and semantics of DOT COMMANDS are given later in the section +titled "DOT COMMANDS". + +videomode: (default 0xFF) [Use with care] + The textmode in which the whole menu system should operate. + Must be a number (use 0x notation for hexadecimal). + Lookup Ralph Brown Interrupt List and search for Video Mode + to find a number to put here. + + setting to 0xFF will mean, menu system will use the current + video mode. + +title: + The title of the whole menu system + +top, left, bot, right: (default 0,0,21,79) + The area of the screen used by the menu system. The remaining + part of the screen can be used by the user for anything. + +helpdir: (default /isolinux/help) + Location of the directory where help information is stored. The + help files must be called "hlpNNNNN.txt" where NNNNN is the helpid. + +pwdfile: (default /isolinux/passwd) + The name of the password file which contains user, password and permissions + See "passwd" file for details regarding format of this file + +editrow: (default 23) + the row on the screen where one can edit the command line. This must + be outside the menu area. Set this to a negative number to disable + editing the command line. In case of authenticated users, the current + user must have "editcmd" permissions to edit the command line + +pwdrow: (default 23) + The row on the screen used for user authentication. Must be outside + menu area (can be same as editrow). Set to negative to disable + user authentication + +skipif: (default 0) + The OR of the bits in the Shift-flags any of which can cause the menu system + to be skipped all together (0 means menu system always runs). It can also + be a combination of "Alt","Ctrl","Shift","Caps","Ins","Scroll". + When menu system starts it checks if any of the specified keys are On/pressed. + If true, the system exits immediately and executes the skipcmd. + + e.g. setting it to "shift-alt-caps" means menu will be skipped if alt OR shift + is pressed OR caps is on. setting to "0" means menu will always run. + +skipcmd: (default .exit) + valid terminal commands: .exit .ignore or any syslinux command + command to execute if menu system is skipped. This must be a non-trivial + syslinux command if skipcondn is not "0". ".exit" means menu system + quits back to the boot prompt. + +startfile: (default "") + if non-empty the system will display the contents of this file before launching + the menusystem. This happens only if the menusystem is not skipped. Can be used + to display licensing, usage or welcome messages. A file with given name + is expected to be found in the helpdir directory. + +exitcmd: (default .exit) + valid terminal commands: .exit .repeat or any syslinux command + The default command to execute when user quits the menu system. + +exitcmdroot: (default =exitcmd) + Same as exitcmd except applies when current user has "root" privileges. If not + specified, it is assumed to be the same as exitcmd + +timeout: (default 3000) + The amount of time (in multiple of 0.1 seconds) to wait for user keypress. If no + key pressed for specified duration then the timeoutcmd is executed. + +totaltimeout: (default 0) + The total amount of time (in multiples of 0.1 seconds) the system will wait for + user to make a decision. If no decision has been made in the specified duration + totaltimeoutcmd will be executed + + NOTE: This does not include the time spent browsing the help system or + the time taken for the user to enter his/her authentication credentials. + +timeoutcmd: (default .beep) + valid terminal commands: .wait .enter .escape or any syslinux command + command to execute when we timeout waiting for user input. The commands + .enter and .escape tell the menu system to pretend the user typed ENTER or + ESCAPE on the keyboard, while .wait tells the menusystem to wait for one + more time period + +totaltimeoutcmd: (default .wait) + choices are the same as for timeoutcmd + +MENU SETTINGS +------------- + +title: (must be specified) + Title of this menu + +row,col: [Usage not recomended] + position in screen where this menu should be placed. By default the + system will choose an appropriate location. + +ITEM ATTRIBUTES +--------------- + +item: + The string displayed to the user. Characters enclosed in < > are highlighted. + +shortcut: (default -1) valid values A-Za-z0-9 or -1 [Usage not recommended] + Sets the shortcut key for this item. If set to -1, the system scans for the first + highlighted letter in the given range and sets that as the shortcut key. + +info: (default same as data) + Additional textual information displayed in the status bar + +type: + the type of entry this item represents. This is one of the following: + + run: choosing this will run something in SYSLINUX + use data to specify the actual command to execute + exitmenu: exit to parent menu + submenu: choosing will open up submenu + use data to specify the "nickname" of the menu + which should come here + sep: Position a separator here + inactive: menu item is disabled + checkbox: this is a checkbox + use state to set initial state + invisible: User does not see this item + radioitem: One choice in a radiomenu + radiomenu: Allow user to choose one of many choices + (initial choice is always NULL) + login: Selecting this will allow user to login to system + +data: + for run items, the syslinux command to execute + for submenus and radiomenus, nickname of menu + for checkboxes, string to be added to kernel command line (if set) + for radioitems, string to be added to kernel command line (if chosen) + +ipappend: + ipappend flag to pass to PXELINUX (harmless for other variants of SYSLINUX) + See syslinux documentation for meaning of the FLAGS + +helpid: (default 65535 which is not a valid id) + associates a context for the help system. + +state: (default 0) + Initial state of a checkbox (for other items this has no meaning) + +perms: (default "") + string containing the name of the permission which user must + have to activate this item. For eg. if this item is a submenu + then user needs the permission in order to open the submenu + +argsmenu: (default "") + Name of the menu to be scanned for setting additional arguments to + pass to command line when this item is chosen for execution. Submenus + of specified menu are also scanned. Only checkboxes and radiomenu's + are scanned. Items of other type in this menu is silently ignored. + + +DOT COMMANDS +------------ +Dot commands are basically instructions to the menu system to do certain things. + +A "single command" is one of the following + +[NT] A syslinux command (any DOT command not starting with a "." is assumed to be this) +[NT] .beep [n] +[NT] .help <file> +[NT] .nop +[T] .exit or .quit (equivalent) +[T] .repeat or .wait or .ignore (all three are equivalent) + +A dot command is a sequence of "single commands" separated by a "%". When a dot command +is executed the system executes all the given "single commands" in the specified order. +All the commands marked "[T]" are terminal commands, i.e. when the system encounters +such a command it stops processing the dot command and returns the terminal command +which caused the termination to the caller (who usually interprets the command +appropriately). + +All commands marked with [NT] are non-terminal commands, i.e. once these commands are +processed the system continues to process the remaining "single commands" specified in +the "DOT COMMAND". + +Note: The case of a syslinux command is tricky. When executed, the command should never return +(if the specified kernel exists) so the fact that we consider it a [NT] should be taken with +a pinch of salt. However, if the syslinux command does return (in case of no kernel), then +remaining "single commands" are processed. In particular "ker1 arg1 % ker2 arg2 % ker3 args" +has the effect of executing the first kernel which exists -ITEMATTR +.nop: + Does nothing. +.beep: + .beep [n] produces a beep n times. n must be between 0 and 9. If not specified n=1. + (hence .beep 0 is equivalent to .nop) +.help: + .help <file> + Displays the help file <file> which is assumed to be in the "help" directory. Its name + does not have to be in the form "hlpNNNNN.txt" (as required by the context sensitive help). + Executing this command will mean the appropriate help screen is displayed till the user hits + ESCAPE -ITEMATTR +The meaning of the Terminal commands can vary with the context in which it is used. For example, +a ".enter" or ".escape" does not have any meaning in the "onerrorcmd" context but it has a meaning +in the "ontimeout" context. In case the user gives a Terminal command which does not make sense, it +is upto the code (in this case adv_menu.tpl) to do what it pleases. diff --git a/menu/Makefile b/menu/Makefile index 102b7afe..8728dccc 100644 --- a/menu/Makefile +++ b/menu/Makefile @@ -47,8 +47,8 @@ MENUS = $(CMENUS) $(IMENUS) .SUFFIXES: .S .c .o .elf .c32 .menu .PRECIOUS: %.c -%.c: %.menu - python menugen.py $< $@ +%.c: %.menu adv_menu.tpl + python menugen.py --input=$< --output=$@ --template=adv_menu.tpl .PRECIOUS: %.o %.o: %.S @@ -73,12 +73,18 @@ libmenu/libmenu.a: $(LIBMENU) $(RANLIB) $@ tidy: - rm -f *.o *.lo *.a *.lst *.elf libmenu/*.o libmenu/*.a + rm -f *.o *.lo *.a *.lst *.elf -clean: tidy +libclean: + rm -f libmenu/*.o libmenu/*.a + +clean: tidy menuclean rm -f *.lss *.c32 *.com -spotless: clean +menuclean: + rm -f $(patsubst %.menu,%.c,$(wildcard *.menu)) + +spotless: clean libclean menuclean rm -f *~ \#* menus: $(MENUS) diff --git a/menu/README b/menu/README index aa979ed5..b6cc2524 100644 --- a/menu/README +++ b/menu/README @@ -12,7 +12,6 @@ for your own menu configuration file; If your menu system is only going to have entries corresponding to things which can be executed directly, then you can create a file in ".menu" format instead of the C code. -NOTE: ".menu" files can only describe the very basic type of menus See MENU_FORMAT for the syntax of .menu files The resulting code is a 32-bit COMBOOT code, and hence can be executed @@ -1,8 +1,3 @@ * Write COMBOOT code to read .menu files and parse them directly - take the name of menu file to parse from commandline -* menugen.py is still useful as user can see what the C code will - be and modify that as required. -* Help support - - Beef up help.c so that the text file can be larger than one page, and - user can scroll down page to view extra text. diff --git a/menu/adv_menu.tpl b/menu/adv_menu.tpl new file mode 100644 index 00000000..f2bf79c2 --- /dev/null +++ b/menu/adv_menu.tpl @@ -0,0 +1,452 @@ +All the lines in this file not in between --something BEGINS-- and --something ENDS-- +is ignored completely and will not make it into the generated C file + +This file has sections of C code each section delimited by --secname BEGINS-- +and --secname ENDS--. In the generated C code certain section may be used multiple +times. Currently the different section which must be defined are + +header, system, item, login and footer + +Any additional sections you define will be processed but will probably not make it +to the C code if you do not modify menugen.py to use it. + +header and footer go through unmolested. The remaining are % substituted using +python rules. Basically it means %(var)s gets replaced by the value of the variable +"var" which is a processed form of what is read from the .menu file + +NOTE: There is absolutely no C code in the python script, so you are free to +modify this template to suit your needs + +--header BEGINS-- +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2006 Murali Krishnan Ganapathy - 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. + * + * ----------------------------------------------------------------------- */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#include "menu.h" +#include "help.h" +#include "passwords.h" +#include "com32io.h" +#include <string.h> +#include <stdlib.h> + +#define MAX_CMD_LINE_LENGTH 514 + +typedef struct s_xtra { + long ipappend; // Stores the ipappend flag to send (useful for PXELINUX only) + char *argsmenu; // Stores the name of menu which contains options for the given RUN item + char *perms; // stores the permissions required to activate the item +} t_xtra; + +typedef t_xtra *pt_xtra; // Pointer to extra datastructure + +// Types of dot commands for which caller takes responsibility of handling +// In some case some commands may not make sense, it is up to the caller +// to handle cases which do not make sense +typedef enum {QUIT_CMD, REPEAT_CMD, ENTER_CMD, ESCAPE_CMD} t_dotcmd; + + +/*----------------- Global Variables */ + +// default user +#define GUEST_USER "guest" + +// for local commands. return value of execdotcmd +#define QUIT_CMD 0 +#define RPT_CMD 1 + +char username[12]; // Name of user currently using the system + +int PWD_ROW; // Line number where user authentication happens +int EDIT_ROW; // row where User Tab + +char loginstr[] = "<L>ogin "; +char logoutstr[30]; + +int vmode; // The video mode we want to be in +char timeoutcmd[MAX_CMD_LINE_LENGTH]; // Command to execute on timeout +char totaltimeoutcmd[MAX_CMD_LINE_LENGTH]; // Command to execute on totaltimeout + +char QUITSTR[] = ".quit"; // same as exit +char IGNORESTR[]=".ignore"; // same as repeat, wait + +/*---------------- End globals */ + +// returns pointer to first non-space char +// and advances end of str by removing trailing spaces +char * strip(char *str) +{ + char *p,*s,*e; + if (!str) return NULL; + p = str; + s = NULL; + e = NULL; + while (*p) { + if (*p != ' ') { + // mark start of string or record the last visited non-space char + if (!s) s=p; else e=p; + } + p++; + } + *(++e)='\0'; // kill string earlier + return s; +} + +// executes a list of % separated commands +// non-dot commands are assumed to be syslinux commands +// All syslinux commands are appended with the contents of kerargs +// If it fails (kernel not found) then the next one is tried in the +// list +// returns QUIT_CMD or RPT_CMD +t_dotcmd execdotcmd(const char *cmd, char *defcmd, const char *kerargs) +{ + char cmdline[MAX_CMD_LINE_LENGTH]; + char dotcmd[MAX_CMD_LINE_LENGTH]; + char *curr,*next,*p,*args; + char ctr; + + strcpy(dotcmd,cmd); + next = dotcmd; + cmdline[0] = '\0'; + while (*next) { // if something to do + curr = next; + p = strchr(next,'%'); + if (p) { + *p--='\0'; next=p+2; + while (*p == ' ') p--; + *(++p)='\0'; // remove trailing spaces + } else { + if (*defcmd) { // execute defcmd next + next=defcmd; + defcmd=NULL; // exec def cmd only once + } else next=NULL; + } + // now we just need to execute the command "curr" + curr = strip(curr); + if (curr[0] != '.') { // just run the kernel + strcpy(cmdline,curr); + if (kerargs) strcat(cmdline,kerargs); + runsyslinuximage(cmdline,0); // No IPAppend + } else { // We have a DOT command + // split command into command and args (may be empty) + args = curr; + while ( (*args != ' ') && (*args != '\0') ) args++; + if (*args) { // found a space + *args++ = '\0'; + while (*args == ' ') args++; // skip over spaces + } + if ( (strcmp(curr,".exit")==0) || + (strcmp(curr,".quit")==0) + ) + return QUIT_CMD; + if ( (strcmp(curr,".repeat")==0) || + (strcmp(curr,".ignore")==0) || + (strcmp(curr,".wait")==0) + ) + return RPT_CMD; + if (strcmp(curr,".beep")==0) { + if ((args) && ('0' <= args[0]) && (args[0] <= '9')) + ctr = args[0]-'0'; + else ctr=1; + for (;ctr>0; ctr--) beep(); + } + if (strcmp(curr,".help")==0) runhelp(args); + } + } + return RPT_CMD; // by default we do not quit +} + + +TIMEOUTCODE timeout(const char *cmd) +{ + t_dotcmd c; + c = execdotcmd(cmd,".wait",NULL); + switch(c) { + case ENTER_CMD: + return CODE_ENTER; + case ESCAPE_CMD: + return CODE_ESCAPE; + default: + return CODE_WAIT; + } +} + +TIMEOUTCODE ontimeout() +{ + return timeout(timeoutcmd); +} + +TIMEOUTCODE ontotaltimeout() +{ + return timeout(totaltimeoutcmd); +} + +void keys_handler(t_menusystem *ms, t_menuitem *mi,unsigned int scancode) +{ + char nc; + + if ( ((scancode >> 8) == F1) && (mi->helpid != 0xFFFF) ) { // If scancode of F1 and non-trivial helpid + runhelpsystem(mi->helpid); + } + + // If user hit TAB, and item is an "executable" item + // and user has privileges to edit it, edit it in place. + if (((scancode & 0xFF) == 0x09) && (mi->action == OPT_RUN) && + (EDIT_ROW < getnumrows()) && (EDIT_ROW > 0) && + (isallowed(username,"editcmd") || isallowed(username,"root"))) { + nc = getnumcols(); + // User typed TAB and has permissions to edit command line + gotoxy(EDIT_ROW,1,ms->menupage); + csprint("Command line:",0x07); + editstring(mi->data,ACTIONLEN); + gotoxy(EDIT_ROW,1,ms->menupage); + cprint(' ',0x07,nc-1,ms->menupage); + } +} + +t_handler_return login_handler(t_menusystem *ms, t_menuitem *mi) +{ + (void)mi; // Unused + char pwd[40]; + char login[40]; + char nc; + t_handler_return rv; + + rv = ACTION_INVALID; + if (PWD_ROW < 0) return rv; // No need to authenticate + + if (mi->item == loginstr) { /* User wants to login */ + nc = getnumcols(); + gotoxy(PWD_ROW,1,ms->menupage); + csprint("Enter Username: ",0x07); + getstring(login, sizeof username); + gotoxy(PWD_ROW,1,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + csprint("Enter Password: ",0x07); + getpwd(pwd, sizeof pwd); + gotoxy(PWD_ROW,1,ms->menupage); + cprint(' ',0x07,nc,ms->menupage); + + if (authenticate_user(login,pwd)) + { + strcpy(username,login); + strcpy(logoutstr,"<L>ogout "); + strcat(logoutstr,username); + mi->item = logoutstr; // Change item to read "Logout" + rv.refresh = 1; // refresh the screen (as item contents changed) + } + else strcpy(username,GUEST_USER); + } + else // User needs to logout + { + strcpy(username,GUEST_USER); + strcpy(logoutstr,""); + mi->item = loginstr; + } + + return rv; +} + +t_handler_return check_perms(t_menusystem *ms, t_menuitem *mi) +{ + char *perms; + pt_xtra x; + + (void) ms; // To keep compiler happy + + x = (pt_xtra) mi->extra_data; + perms = ( x ? x->perms : NULL); + if (!perms) return ACTION_VALID; + + if (isallowed(username,"root") || isallowed(username,perms)) // If allowed + return ACTION_VALID; + else return ACTION_INVALID; +} + +// Compute the full command line to add and if non-trivial +// prepend the string prepend to final command line +// Assume cmdline points to buffer long enough to hold answer +void gencommand(pt_menuitem mi, char *cmdline) +{ + pt_xtra x; + cmdline[0] = '\0'; + strcat(cmdline,mi->data); + x = (pt_xtra) mi->extra_data; + if ( (x) && (x->argsmenu)) gen_append_line(x->argsmenu,cmdline); +} + + +// run the given command together with additional options which may need passing +void runcommand(pt_menuitem mi) +{ + char *line; + pt_xtra x; + long ipappend; + + line = (char *)malloc(sizeof(char)*MAX_CMD_LINE_LENGTH); + gencommand(mi,line); + x = (pt_xtra) mi->extra_data; + ipappend = (x ? x->ipappend : 0); + + runsyslinuximage(line,x->ipappend); + free(line); +} + +// set the extra info for the specified menu item. +void set_xtra(pt_menuitem mi, const char *argsmenu, const char *perms, unsigned int helpid, long ipappend) +{ + pt_xtra xtra; + int bad_argsmenu, bad_perms, bad_ipappend; + + mi->extra_data = NULL; // initalize + mi->helpid = helpid; // set help id + + if (mi->action != OPT_RUN) return; + + bad_argsmenu = bad_perms = bad_ipappend = 0; + if ( (argsmenu==NULL) || (strlen(argsmenu)==0)) bad_argsmenu = 1; + if ( (perms==NULL) || (strlen(perms)==0)) bad_perms = 1; + if ( ipappend==0) bad_ipappend = 1; + + if (bad_argsmenu && bad_perms && bad_ipappend) return; + + xtra = (pt_xtra) malloc(sizeof(t_xtra)); + mi->extra_data = (void *) xtra; + xtra->argsmenu = xtra->perms = NULL; + xtra->ipappend = ipappend; + if (!bad_argsmenu) { + xtra->argsmenu = (char *) malloc(sizeof(char)*(strlen(argsmenu)+1)); + strcpy(xtra->argsmenu,argsmenu); + } + if (!bad_perms) { + xtra->perms = (char *) malloc(sizeof(char)*(strlen(perms)+1)); + strcpy(xtra->perms,perms); + mi->handler = &check_perms; + } +} + +int main(void) +{ + pt_menuitem curr; + char quit; + char exitcmd[MAX_CMD_LINE_LENGTH]; + char exitcmdroot[MAX_CMD_LINE_LENGTH]; + char onerrcmd[MAX_CMD_LINE_LENGTH]; + char startfile[MAX_CMD_LINE_LENGTH]; + char *ecmd; // effective exit command or onerrorcmd + char skipbits; + char skipcmd[MAX_CMD_LINE_LENGTH]; + int timeout; // time in multiples of 0.1 seconds + int totaltimeout; // time in multiples of 0.1 seconds + t_dotcmd dotrv; // to store the return value of execdotcmd + int temp; + + strcpy(username,GUEST_USER); +--header ENDS-- +--system BEGINS-- +/* ---- Initializing menu system parameters --- */ + vmode = %(videomode)s; + skipbits = %(skipcondn)s; + PWD_ROW = %(pwdrow)s; + EDIT_ROW = %(editrow)s; + strcpy(onerrcmd,"%(onerrorcmd)s"); + strcpy(exitcmd,"%(exitcmd)s"); + strcpy(exitcmdroot,"%(exitcmdroot)s"); + // If not specified exitcmdroot = exitcmd + if (exitcmdroot[0] == '\0') strcpy(exitcmdroot,exitcmd); + // Timeout stuff + timeout = %(timeout)s; + strcpy(timeoutcmd,"%(timeoutcmd)s"); + totaltimeout = %(totaltimeout)s; + strcpy(totaltimeoutcmd,"%(totaltimeoutcmd)s"); + strcpy(startfile,"%(startfile)s"); + + init_help("%(helpdir)s"); + init_passwords("%(pwdfile)s"); + init_menusystem("%(title)s"); + set_window_size(%(top)s,%(left)s,%(bot)s,%(right)s); + + // Register the ontimeout handler, with a time out of 10 seconds + reg_ontimeout(ontimeout,timeout*10,0); + reg_ontotaltimeout(ontotaltimeout,totaltimeout*10); + + // Register menusystem handlers + reg_handler(HDLR_KEYS,&keys_handler); +/* ---- End of initialization --- */ +--system ENDS-- +--item BEGINS-- + + curr = add_item("%(item)s","%(info)s",%(type)s,"%(data)s",%(state)d); + set_xtra(curr,"%(argsmenu)s","%(perms)s",%(helpid)d,%(ipappend)d); // Set associated extra info + set_shortcut(%(shortcut)s); +--item ENDS-- +--login BEGINS-- + + curr = add_item(loginstr,"Login/Logout of authentication system",OPT_RUN,NULL,0); + curr->helpid = %(helpid)d; + curr->handler = &login_handler; +--login ENDS-- +--menu BEGINS-- + +/* ------- MENU %(name)s ----- */ + add_named_menu("%(name)s","%(title)s",-1); +--menu ENDS-- +--footer BEGINS-- +/* ------- END OF MENU declarations ----- */ + +// Check if we should skip the menu altogether + quit = 0; // Dont skip the menu + if (getshiftflags() & skipbits) { // we must skip the menu altogther and execute skipcmd + dotrv = execdotcmd(skipcmd,".beep%.exit",NULL); // Worst case we beep and exit + if (dotrv == QUIT_CMD) quit = 1; + } + +// Switch vide mode if required + if (vmode != 0xFF) setvideomode(vmode); + +// Do we have a startfile to display? + if (startfile[0] != '\0') runhelp(startfile); + +// The main loop + while (quit == 0) { // As long as quit is zero repeat + curr = showmenus(find_menu_num("main")); // Initial menu is the one called "main" + + if (curr) { + if (curr->action == OPT_RUN) { + ecmd = (char *)malloc(sizeof(char)*MAX_CMD_LINE_LENGTH); + gencommand(curr,ecmd); + temp = (curr->extra_data ? ((pt_xtra)curr->extra_data)->ipappend : 0); + runsyslinuximage(ecmd,temp); + // kernel not found so execute the appropriate dot command + dotrv = execdotcmd(onerrcmd,".quit",ecmd); // pass bad cmdline as arg + if (dotrv== QUIT_CMD) quit = 1; + free(ecmd); ecmd = NULL; + } + else csprint("Error in programming!",0x07); + } else { + // find effective exit command + ecmd = ( isallowed(username,"root") ? exitcmdroot : exitcmd); + dotrv = execdotcmd(ecmd,".repeat",NULL); + quit = (dotrv == QUIT_CMD ? 1 : 0); // should we exit now + } + } + +// Deallocate space used and quit + close_passwords(); + close_help(); + close_menusystem(); + return 0; +} + +--footer ENDS-- diff --git a/menu/display.c b/menu/display.c new file mode 100644 index 00000000..a9bf70e1 --- /dev/null +++ b/menu/display.c @@ -0,0 +1,37 @@ +/* -*- c -*- ------------------------------------------------------------- * + * + * Copyright 2004-2006 Murali Krishnan Ganapathy - 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. + * + * ----------------------------------------------------------------------- */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#include "help.h" +#include "com32io.h" +#include "menu.h" +#include "tui.h" +#include <stdlib.h> +#include <com32.h> +#include <stdio.h> + + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + csprint("Usage: display.c32 <textfile>\n",0x07); + exit(1); + } + + init_help(NULL); // No base dir, so all filenames must be absolute + runhelp(argv[1]); + close_help(); + return 0; +} diff --git a/menu/libmenu/com32io.c b/menu/libmenu/com32io.c index 92a67a0b..33f0c3e6 100644 --- a/menu/libmenu/com32io.c +++ b/menu/libmenu/com32io.c @@ -65,7 +65,7 @@ unsigned char sleep(unsigned int msec) REG_AH(inreg) = 0x86; REG_CX(inreg) = (micro >> 16); - REG_DX(inreg) = (micro % 0x10000); + REG_DX(inreg) = (micro & 0xFFFF); __intcall(0x15,&inreg,&outreg); return REG_AH(outreg); } @@ -78,22 +78,22 @@ void beep() __intcall(0x10,&inreg,&outreg); } -void scrollup() +void scrollupwindow(char top, char left, char bot, char right, char attr,char numlines) { - unsigned int dx = (getnumrows()<< 8) + getnumcols(); REG_AH(inreg) = 0x06; - REG_AL(inreg) = 0x01; - REG_BH(inreg) = 0x07; // Attribute to write blanks lines - REG_DX(inreg) = dx; // BOT RIGHT corner to window - REG_CX(inreg) = 0; // TOP LEFT of window + REG_AL(inreg) = numlines; + REG_BH(inreg) = attr; // Attribute to write blanks lines + REG_DX(inreg) = (bot << 8) + right; // BOT RIGHT corner of window + REG_CX(inreg) = (top << 8) + left; // TOP LEFT of window + __intcall(0x10,&inreg,&outreg); } char inputc(char * scancode) { + syslinux_idle(); /* So syslinux can perform periodic activity */ REG_AH(inreg) = 0x10; __intcall(0x16,&inreg,&outreg); - if (scancode) - *scancode = REG_AH(outreg); + if (scancode) *scancode = REG_AH(outreg); return REG_AL(outreg); } diff --git a/menu/libmenu/com32io.h b/menu/libmenu/com32io.h index 899260dd..26bec0fc 100644 --- a/menu/libmenu/com32io.h +++ b/menu/libmenu/com32io.h @@ -79,10 +79,25 @@ static inline char getnumcols(void) return readbiosb(0x44a); // Actually numcols } -void scrollup(); //Scroll up display screen by one line +static inline char getshiftflags(void) +{ + return readbiosb(0x417); +} + +void scrollupwindow(char top, char left, char bot,char right,char attr,char numlines); //Scroll up given window + +static inline void scrollup(void) //Scroll up display screen by one line +{ + scrollupwindow(0,0,getnumrows(),getnumcols(),0x07,1); +} void setvideomode(char mode); // Set the video mode. +static inline char getvideomode(void) // Get the current video mode +{ + return readbiosb(0x449); +} + unsigned char sleep(unsigned int msec); // Sleep for specified time void beep(); // A Bell diff --git a/menu/libmenu/help.c b/menu/libmenu/help.c index d591156e..0727a380 100644 --- a/menu/libmenu/help.c +++ b/menu/libmenu/help.c @@ -13,65 +13,181 @@ #include "help.h" #include <stdio.h> #include "string.h" +#include "com32io.h" +#include <loadfile.h> // to read entire file into memory char helpbasedir[HELPDIRLEN]; // name of help directory limited to HELPDIRLEN +// Find the occurence of the count'th \n in buffer (or NULL) if not found +char * findline(char*buffer,int count) +{ + int ctr; + char *p= buffer-1; + + if (count < 1) return buffer; + for (ctr=0; ctr < count; ctr++) { + p = strchr(p+1,'\n'); + if (p==NULL) return NULL; + } + return p; +} + +// return the number of lines in buffer +int countlines(char*buffer) +{ + int ans; + const char *p; + + p = buffer-1; + ans = 1; + while(p) {p = strchr(p+1,'\n'); ans++; } + return ans; +} + + +// Print numlines of text starting from buf +void printtext(char*buf, int from) +{ + char *p,*f; + char right,bot,nlines; + + // clear window to print + right = getnumcols() - HELP_RIGHT_MARGIN; + bot = getnumrows() - HELP_BOTTOM_MARGIN; + nlines = bot-HELP_BODY_ROW+1; + scrollupwindow(HELP_BODY_ROW,HELP_LEFT_MARGIN,bot,right,0x07,nlines); + + f = findline(buf,from); + if (!f) return; // nothing to print + if (*f=='\n') f++; // start of from+1st line + p = findline(f,nlines); + if (p && (*p=='\n')) *p = '\0'; // change to NUL + gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE); + cswprint(f,0x07,HELP_LEFT_MARGIN); + if (p) *p = '\n'; // set it back +} + void showhelp(const char *filename) { - char nc,nr; - FILE *f; - char line[512]; // Max length of a line + char nc,nr,ph; + char *title,*text; + union { char *buffer; void *vbuf; } buf; // This is to avoild type-punning issues + + char line[512]; + size_t size; + char scan; + int rv,numlines,curr_line; nc = getnumcols(); nr = getnumrows(); + ph = nr - HELP_BOTTOM_MARGIN - HELP_BODY_ROW - 1; cls(); drawbox(0,0,nr,nc-1,HELPPAGE,0x07,HELPBOX); drawhorizline(2,0,nc-1,HELPPAGE,0x07,HELPBOX,0); // dumb==0 if (filename == NULL) { // print file contents gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE); - cswprint("Help system not initialized",0x07,HELP_LEFT_MARGIN); + cswprint("Filename not given",0x07,HELP_LEFT_MARGIN); + while (1) { + inputc(&scan); + if (scan == ESCAPE) break; + } + cls(); return; } - f = fopen(filename,"r"); - if (!f) { // No such file - sprintf(line, "File %s not found",filename); + rv = loadfile(filename,(void **)&buf.vbuf, &size); // load entire file into memory + if (rv < 0) { // Error reading file or no such file + sprintf(line, "Error reading file or file not found\n file=%s",filename); gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE); cswprint(line,0x07,HELP_LEFT_MARGIN); + while (1) { + inputc(&scan); + if (scan == ESCAPE) break; + } + cls(); return; } + title = buf.buffer; + text = findline(title,1); // end of first line + *text++='\0'; // end the title string and increment text + // Now we have a file just print it. - fgets(line,sizeof line,f); // Get first line (TITLE) - gotoxy(1,(nc-strlen(line))/2,HELPPAGE); - csprint(line,0x07); + gotoxy(1,(nc-strlen(title))/2,HELPPAGE); + csprint(title,0x07); + numlines = countlines(text); + curr_line = 0; + scan = ESCAPE+1; // anything except ESCAPE + + while(scan != ESCAPE) { + printtext(text,curr_line); + gotoxy(HELP_BODY_ROW-1,nc-HELP_RIGHT_MARGIN,HELPPAGE); + if (curr_line > 0) + putch(HELP_MORE_ABOVE,0x07,HELPPAGE); + else putch(' ',0x07,HELPPAGE); + gotoxy(nr-HELP_BOTTOM_MARGIN+1,nc-HELP_RIGHT_MARGIN,HELPPAGE); + if (curr_line < numlines - ph) + putch(HELP_MORE_BELOW,0x07,HELPPAGE); + else putch(' ',0x07,HELPPAGE); + + inputc(&scan); // wait for user keypress - gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE); - while ( fgets(line, sizeof line, f) ) cswprint(line,0x07,HELP_LEFT_MARGIN); - fclose(f); + switch(scan) { + case HOMEKEY: + curr_line = 0; + break; + case ENDKEY: + curr_line = numlines; + break; + case UPARROW: + curr_line--; + break; + case DNARROW: + curr_line++; + break; + case PAGEUP: + curr_line -= ph; + break; + case PAGEDN: + curr_line += ph; + break; + default: + break; + } + if (curr_line > numlines - ph) curr_line = numlines-ph; + if (curr_line < 0) curr_line = 0; + } + cls(); + return; } -void runhelpsystem(unsigned int helpid) +void runhelp(const char *filename) { char dp; - char scan; - char filename[HELPDIRLEN+16]; + char fullname[HELPDIRLEN+16]; dp = getdisppage(); if (dp != HELPPAGE) setdisppage(HELPPAGE); + cursoroff(); if (helpbasedir[0] != 0) { - sprintf(filename,"%s/hlp%05d.txt",helpbasedir,helpid); - showhelp(filename); - } - else showhelp (NULL); - while (1) { - inputc(&scan); - if (scan == ESCAPE) break; + strcpy(fullname,helpbasedir); + strcat(fullname,"/"); + strcat(fullname,filename); + showhelp(fullname); } + else showhelp (filename); // Assume filename is absolute if (dp != HELPPAGE) setdisppage(dp); } +void runhelpsystem(unsigned int helpid) +{ + char filename[15]; + + sprintf(filename,"hlp%5d.txt",helpid); + runhelp(filename); +} + void init_help(const char *helpdir) { if (helpdir != NULL) diff --git a/menu/libmenu/help.h b/menu/libmenu/help.h index 45ef9d66..77db9909 100644 --- a/menu/libmenu/help.h +++ b/menu/libmenu/help.h @@ -22,8 +22,15 @@ #define HELP_TITLE_HEIGHT 1 #define HELP_BODY_ROW (HELP_TITLE_HEIGHT+3) #define HELP_LEFT_MARGIN 2 +#define HELP_RIGHT_MARGIN 2 // Assume all lines dont cross this +#define HELP_BOTTOM_MARGIN 2 // Number of lines not use from bottom of screen + #define HELPBOX BOX_SINSIN #define HELPDIRLEN 64 +#define HELPPAGE 2 + +#define HELP_MORE_ABOVE 24 // to print when more is available above +#define HELP_MORE_BELOW 25 // same as above but for below // Display one screen of help information void showhelp(const char *filename); @@ -31,6 +38,9 @@ void showhelp(const char *filename); // Start the help system using id helpid void runhelpsystem(unsigned int helpid); +// Start help system with specified file +void runhelp(const char *filename); + // Directory where help files are located void init_help(const char *helpdir); // Free internal datastructures diff --git a/menu/libmenu/menu.c b/menu/libmenu/menu.c index 75a8d724..31831d2f 100644 --- a/menu/libmenu/menu.c +++ b/menu/libmenu/menu.c @@ -11,6 +11,7 @@ * ----------------------------------------------------------------------- */ #include "menu.h" +#include "com32io.h" #include <stdlib.h> // Local Variables @@ -42,18 +43,29 @@ char getch(char *scan) { unsigned long i; TIMEOUTCODE c; + t_timeout_handler th; // Wait until keypress if no handler specified - if (ms->ontimeout==NULL) return inputc(scan); + if ((ms->ontimeout==NULL) && (ms->ontotaltimeout==NULL)) return inputc(scan); + th = ms->ontimeout; while (1) // Forever do { for (i=0; i < ms->tm_numsteps; i++) { if (checkkbdbuf()) return inputc(scan); sleep(ms->tm_stepsize); + if ( (ms->tm_total_timeout == 0) || (ms->ontotaltimeout==NULL)) + continue; // Dont bother with calculations if no handler + ms->tm_sofar_timeout += ms->tm_stepsize; + if (ms->tm_sofar_timeout >= ms->tm_total_timeout) { + th = ms->ontotaltimeout; + ms->tm_sofar_timeout = 0; + break; // Get out of the for loop + } } - c = ms->ontimeout(); + if (!th) continue; // no handler dont call + c = th(); switch(c) { case CODE_ENTER: // Pretend user hit enter @@ -684,7 +696,8 @@ void fix_submenus() { mi = m->items[j]; // if submenu with non-trivial data string - if ( (mi->action == OPT_SUBMENU) && (mi->data) ) + // again using hack that itemdata is a union data type + if ( mi->data && ((mi->action == OPT_SUBMENU) || (mi->action == OPT_RADIOMENU)) ) mi->itemdata.submenunum = find_menu_num (mi->data); } } @@ -776,6 +789,9 @@ pt_menusystem init_menusystem(const char *title) ms->handler = NULL; ms->keys_handler = NULL; ms->ontimeout=NULL; // No timeout handler + ms->tm_total_timeout = 0; + ms->tm_sofar_timeout = 0; + ms->ontotaltimeout = NULL; // Setup ACTION_{,IN}VALID ACTION_VALID.valid=1; @@ -911,6 +927,21 @@ void unreg_ontimeout() ms->ontimeout = NULL; } +void reg_ontotaltimeout (t_timeout_handler handler, unsigned long numcentiseconds) +{ + if (numcentiseconds != 0) { + ms->ontotaltimeout = handler; + ms->tm_total_timeout = numcentiseconds*10; // to convert to milliseconds + ms->tm_sofar_timeout = 0; + } +} + +void unreg_ontotaltimeout() +{ + ms->ontotaltimeout = NULL; +} + + int next_visible(pt_menu menu, int index) { int ans; @@ -1216,3 +1247,54 @@ void close_menusystem(void) { } +// append_line_helper(pt_menu menu,char *line) +void append_line_helper(int menunum, char *line) +{ + pt_menu menu; + pt_menuitem mi,ri; + char *app; + int ctr; + char dp; + + + dp = getdisppage(); + menu = ms->menus[menunum]; + for (ctr = 0; ctr < (int) menu->numitems; ctr++) + { + mi = menu->items[ctr]; + app = NULL; //What to append + switch (mi->action) { + case OPT_CHECKBOX: + if (mi->itemdata.checked) app = mi->data; + break; + case OPT_RADIOMENU: + if (mi->data) { // Some selection has been made + ri = (pt_menuitem) (mi->data); + app = ri->data; + } + break; + case OPT_SUBMENU: + append_line_helper(mi->itemdata.submenunum,line); + break; + default: + break; + } + if (app) { + strcat(line," "); + strcat(line,app); + } + } +} + + +// Generate string based on state of checkboxes and radioitem in given menu +// Assume line points to large enough buffer +void gen_append_line(const char *menu_name,char *line) +{ + int menunum; + + menunum = find_menu_num(menu_name); + if (menunum < 0) return; // No such menu + append_line_helper(menunum,line); +} + diff --git a/menu/libmenu/menu.h b/menu/libmenu/menu.h index a6fae5d2..ba03c299 100644 --- a/menu/libmenu/menu.h +++ b/menu/libmenu/menu.h @@ -93,7 +93,6 @@ #define MENUROW 3 // Row where menu is displayed (relative to window) #define MENUCOL 4 // Col where menu is displayed (relative to window) #define MENUPAGE 1 // show in display page 1 -#define HELPPAGE 2 // Use this page for any additional information #define STATLINE 24 // Line number where status line starts (relative to window) // Used for printing debugging messages @@ -157,13 +156,14 @@ typedef struct s_menuitem { // for radio menu's this is a pointer to the item selected or NULL (initially) // for submenu's this string could be name of menu void * extra_data; // Any other data user can point to + unsigned int helpid; // Used for Context sensitive help t_item_handler handler; // Pointer to function of type menufn t_action action; t_itemdata itemdata; // Data depends on action value - unsigned int helpid; // context sensitive help system ID uchar shortcut; // one of [A-Za-z0-9] shortcut for this menu item uchar index; // Index within the menu array uchar parindex; // Index of the menu in which this item appears. + } t_menuitem; typedef t_menuitem *pt_menuitem; // Pointer to type menuitem @@ -190,6 +190,11 @@ typedef struct s_menusystem { unsigned long tm_numsteps; // Time to wait for key press=numsteps * stepsize milliseconds unsigned int tm_stepsize; // Timeout step size (in milliseconds) + // Total timeout max time spent idle before we call handler + unsigned long tm_total_timeout; // (in milli seconds) + unsigned long tm_sofar_timeout; // All accumulated timeout + // total timeout handler + t_timeout_handler ontotaltimeout; // Total timeout handler int maxmenuheight; uchar nummenus; @@ -248,6 +253,9 @@ void reg_ontimeout(t_timeout_handler, unsigned int numsteps, unsigned int stepsi // So stepsize=0 means numsteps is measured in centiseconds. void unreg_ontimeout(); +void reg_ontotaltimeout(t_timeout_handler, unsigned long numcentiseconds); +void unreg_ontotaltimeout(); + // Find the number of the menu given the name // Returns -1 if not found uchar find_menu_num(const char *name); @@ -275,7 +283,9 @@ static inline void set_shortcut(uchar shortcut) // Add a separator to the "current" menu pt_menuitem add_sep(); -// Main function for the user's config file -int menumain(char *cmdline); +// Generate string based on state of checkboxes and radioitem in given menu +// and append string to existing contents of "line" +// line must have enough space allocated +void gen_append_line(const char *menu_name,char *line); #endif diff --git a/menu/libmenu/passwords.c b/menu/libmenu/passwords.c index d7ada291..f3855b47 100644 --- a/menu/libmenu/passwords.c +++ b/menu/libmenu/passwords.c @@ -26,9 +26,7 @@ int numusers; // Actual number of users char authenticate_user(const char * username, const char* pwd) { char salt[12]; - int i, password_ok; - - password_ok=0; + int i; for (i=0; i< numusers; i++) { if (userdb[i] == NULL) continue; @@ -48,6 +46,8 @@ char isallowed(const char *username, const char *perm) char *dperm; char *tmp; + // If no users, then everybody is allowed to do everything + if (numusers == 0) return 1; if (strcmp(username,GUEST_USER) == 0) return 0; dperm = (char *) malloc(strlen(perm)+3); strcpy(dperm+1,perm); diff --git a/menu/libmenu/scancodes.h b/menu/libmenu/scancodes.h index 83318849..6048c7e3 100644 --- a/menu/libmenu/scancodes.h +++ b/menu/libmenu/scancodes.h @@ -72,4 +72,15 @@ #define ALTF11 0x8B #define ALTF12 0x8C +/* Bits representing ShiftFlags, See Int16/Function 2 or Mem[0x417] to get this info */ + +#define INSERT_ON (1<<7) +#define CAPSLOCK_ON (1<<6) +#define NUMLOCK_ON (1<<5) +#define SCRLLOCK_ON (1<<4) +#define ALT_PRESSED (1<<3) +#define CTRL_PRESSED (1<<2) +// actually 1<<1 is Left Shift, 1<<0 is right shift +#define SHIFT_PRESSED (1<<1 | 1 <<0) + #endif diff --git a/menu/libmenu/syslnx.c b/menu/libmenu/syslnx.c index 66a11aef..76961194 100644 --- a/menu/libmenu/syslnx.c +++ b/menu/libmenu/syslnx.c @@ -32,7 +32,7 @@ void runsyslinuxcmd(const char *cmd) strcpy(__com32.cs_bounce, cmd); REG_AX(inreg) = 0x0003; // Run command REG_BX(inreg) = OFFS(__com32.cs_bounce); - inreg.es = SEG(__com32.cs_bounce); + REG_ES(inreg) = SEG(__com32.cs_bounce); __intcall(0x22, &inreg, &outreg); } @@ -42,3 +42,48 @@ void gototxtmode(void) __intcall(0x22,&inreg,&outreg); } +void syslinux_idle(void) +{ + REG_AX(inreg) = 0x0013; + __intcall(0x22,&inreg,&outreg); +} + +unsigned int getversion(char *deriv,unsigned int *numfun) +{ + REG_AX(inreg) = 0x0001; + __intcall(0x22,&inreg,&outreg); + if (deriv) *deriv= REG_DL(outreg); + if (numfun) *numfun = REG_AX(outreg); + return REG_CX(outreg); +} + +void runsyslinuximage(const char*cmd, long ipappend) +{ + unsigned int numfun = 0; + char *ptr,*cmdline; + + getversion(NULL,&numfun); + // Function 16h not supported Fall back to runcommand + if (numfun < 0x16) runsyslinuxcmd(cmd); + // Try the Run Kernel Image function + // Split command line into + strcpy(__com32.cs_bounce,cmd); + ptr = __com32.cs_bounce; + // serach for first space or end of string + while ( (*ptr) && (*ptr != ' ')) ptr++; + if (!*ptr) cmdline = ptr; // no command line + else { + *ptr++='\0'; // terminate kernal name + cmdline = ptr+1; + while (*cmdline != ' ') cmdline++; // find first non-space + } + // Now call the interrupt + REG_BX(inreg) = OFFS(cmdline); + REG_ES(inreg) = SEG(cmdline); + REG_SI(inreg) = OFFS(__com32.cs_bounce); + REG_DS(inreg) = SEG(__com32.cs_bounce); + REG_EDX(inreg) = 0; + + __intcall(0x22,&inreg,&outreg); // If successful does not return +} + diff --git a/menu/libmenu/syslnx.h b/menu/libmenu/syslnx.h index 7d0281b3..cd159aec 100644 --- a/menu/libmenu/syslnx.h +++ b/menu/libmenu/syslnx.h @@ -38,10 +38,27 @@ #define REG_DX(x) ((x).edx.w[0]) #define REG_EDX(x) ((x).edx.l) +#define REG_DS(x) ((x).ds) +#define REG_ES(x) ((x).es) +#define REG_FS(x) ((x).fs) +#define REG_GS(x) ((x).gs) + +#define REG_SI(x) ((x).esi.w[0]) +#define REG_ESI(x) ((x).esi.l) + +#define REG_DI(x) ((x).edi.w[0]) +#define REG_EDI(x) ((x).edi.l) + char issyslinux(void); /* Check if syslinux is running */ void runsyslinuxcmd(const char *cmd); /* Run specified command */ void gototxtmode(void); /* Change mode to text mode */ +void syslinux_idle(void); /* Call syslinux idle loop */ + +/* Run command line with ipappend, returns if kernel image not found + If syslinux version too old, then defaults to runsyslinuxcmd */ +void runsyslinuximage(const char*cmd, long ipappend); + #endif diff --git a/menu/libmenu/tui.c b/menu/libmenu/tui.c index ad19f46e..617b7312 100644 --- a/menu/libmenu/tui.c +++ b/menu/libmenu/tui.c @@ -1,6 +1,6 @@ /* -*- c -*- ------------------------------------------------------------- * * - * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved + * Copyright 2004-2006 Murali Krishnan Ganapathy - 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 @@ -10,12 +10,9 @@ * * ----------------------------------------------------------------------- */ +#include "tui.h" #include <string.h> #include <com32.h> -#include "tui.h" -#include "syslnx.h" -#include "com32io.h" -#include "scancodes.h" #include <stdlib.h> com32sys_t inreg,outreg; // Global register sets for use diff --git a/menu/libmenu/tui.h b/menu/libmenu/tui.h index 07020ad5..affdc2e4 100644 --- a/menu/libmenu/tui.h +++ b/menu/libmenu/tui.h @@ -14,7 +14,10 @@ #define __TUI_H__ #include <com32.h> +#include "syslnx.h" #include "com32io.h" +#include "scancodes.h" + #ifndef NULL #define NULL ((void *)0) diff --git a/menu/menugen.py b/menu/menugen.py index a868d2a3..78ea3160 100644 --- a/menu/menugen.py +++ b/menu/menugen.py @@ -1,88 +1,89 @@ #!/usr/bin/env python -import sys, string - -TEMPLATE_HEADER=""" -/* -*- c -*- ------------------------------------------------------------- * - * - * Copyright 2004-2005 Murali Krishnan Ganapathy - 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. - * - * ----------------------------------------------------------------------- */ - -#ifndef NULL -#define NULL ((void *) 0) -#endif - -#include "menu.h" -#include "com32io.h" -#include <string.h> - -int main(void) -{ - t_menuitem * curr; - - // Change the video mode here - // setvideomode(0) - - // Set the title and window size - -""" - - -TEMPLATE_FOOTER=""" - curr = showmenus(find_menu_num("main")); // Initial menu is the one called "main" - - if (curr) - { - if (curr->action == OPT_RUN) - { - if (issyslinux()) runsyslinuxcmd(curr->data); - else csprint(curr->data,0x07); - return 1; - } - csprint("Error in programming!",0x07); - } - return 0; -} -""" +import sys, re, getopt class Menusystem: - def __init__(self): + + types = {"run" : "OPT_RUN", + "inactive" : "OPT_INACTIVE", + "checkbox" : "OPT_CHECKBOX", + "radiomenu": "OPT_RADIOMENU", + "sep" : "OPT_SEP", + "invisible": "OPT_INVISIBLE", + "radioitem": "OPT_RADIOITEM", + "exitmenu" : "OPT_EXITMENU", + "login" : "login", # special type + "submenu" : "OPT_SUBMENU"} + + entry_init = { "item" : "", + "info" : "", + "data" : "", + "ipappend" : 0, # flag to send in case of PXELINUX + "helpid" : 65535, # 0xFFFF + "shortcut":"-1", + "state" : 0, # initial state of checkboxes + "argsmenu": "", # name of menu containing arguments + "perms" : "", # permission required to execute this entry + "_updated" : None, # has this dictionary been updated + "type" : "run" } + + menu_init = { "title" : "", + "row" : "0xFF", # let system decide position + "col" : "0xFF", + "_updated" : None, + "name" : "" } + + system_init ={ "videomode" : "0xFF", + "title" : "Menu System", + "top" : "1", + "left" : "1" , + "bot" : "21", + "right":"79", + "helpdir" : "/isolinux/help", + "pwdfile" : "", + "pwdrow" : "23", + "editrow" : "23", + "skipcondn" : "0", + "skipcmd" : ".exit", + "startfile": "", + "onerrorcmd":".repeat", + "exitcmd" : ".exit", + "exitcmdroot" : "", + "timeout" : "600", + "timeoutcmd":".beep", + "totaltimeout" : "0", + "totaltimeoutcmd" : ".wait" + } + + shift_flags = { "alt" : "ALT_PRESSED", + "ctrl" : "CTRL_PRESSED", + "shift": "SHIFT_PRESSED", + "caps" : "CAPSLOCK_ON", + "num" : "NUMLOCK_ON", + "ins" : "INSERT_ON" + } + + reqd_templates = ["item","login","menu","system"] + + def __init__(self,template): + self.state = "system" + self.code_template_filename = template self.menus = [] - self.types = {"run" : "OPT_RUN","exitmenu":"OPT_EXITMENU","submenu":"OPT_SUBMENU"} self.init_entry() self.init_menu() self.init_system() - self.vtypes = string.join(self.types.keys()," OR ") - self.vattrs = string.join(filter(lambda x: x[0] != "_", self.entry.keys())," OR ") - self.mattrs = string.join(filter(lambda x: x[0] != "_", self.menu.keys())," OR ") - self.itemtemplate = ' add_item("%(item)s","%(info)s",%(type)s,"%(data)s",0);\n' - self.menutemplate = '\n add_named_menu("%(name)s","%(title)s",-1);\n' - self.systemplate = '\n init_menusystem(%(title)s);\n set_window_size(%(top)s,%(left)s,%(bot)s,%(right)s);\n' + self.vtypes = " OR ".join(self.types.keys()) + self.vattrs = " OR ".join(filter(lambda x: x[0] != "_", self.entry.keys())) + self.mattrs = " OR ".join(filter(lambda x: x[0] != "_", self.menu.keys())) def init_entry(self): - self.entry = { "item" : "", - "info" : "", - "data" : "", - "_updated" : None, # has this dictionary been updated - "type" : "run" } + self.entry = self.entry_init.copy() def init_menu(self): - self.menu = {"title" : "", - "row" : "0xFF", # let system decide position - "col" : "0xFF", - "_updated" : None, - "name" : "" } + self.menu = self.menu_init.copy() def init_system(self): - self.system = { "title" : "", - "top" : "1", "left" : "1" , "bot" : "23", "right":"79" } + self.system = self.system_init.copy() def add_menu(self,name): self.add_item() @@ -105,105 +106,153 @@ class Menusystem: self.menus[-1][1].append(self.entry) self.init_entry() - # remove quotes if reqd - def rm_quote(self,str): - str = str .strip() - if (str[0] == str[-1]) and (str[0] in ['"',"'"]): # remove quotes - str = str[1:-1] - return str - def set_item(self,name,value): if not self.entry.has_key(name): msg = ["Unknown attribute %s in line %d" % (name,self.lineno)] msg.append("REASON: Attribute must be one of %s" % self.vattrs) - return string.join(msg,"\n") + return "\n".join(msg) if name=="type" and not self.types.has_key(value): msg = [ "Unrecognized type %s in line %d" % (value,self.lineno)] msg.append("REASON: Valid types are %s" % self.vtypes) - return string.join(msg,"\n") - self.entry[name] = self.rm_quote(value) + return "\n".join(msg) + if name=="shortcut": + if (value <> "-1") and not re.match("^[A-Za-z0-9]$",value): + msg = [ "Invalid shortcut char '%s' in line %d" % (value,self.lineno) ] + msg.append("REASON: Valid values are [A-Za-z0-9]") + return "\n".join(msg) + elif value <> "-1": value = "'%s'" % value + elif name in ["state","helpid","ipappend"]: + try: + value = int(value) + except: + return "Value of %s in line %d must be an integer" % (name,self.lineno) + self.entry[name] = value self.entry["_updated"] = 1 return "" def set_menu(self,name,value): - # no current menu yet. We are probably in global section - if not self.menus: return "Error" if not self.menu.has_key(name): - return "Error" - self.menu[name] = self.rm_quote(value) + return "Error: Unknown keyword %s" % name + self.menu[name] = value self.menu["_updated"] = 1 return "" def set_system(self,name,value): if not self.system.has_key(name): - return "Error" - self.system[name] = self.rm_quote(value) + return "Error: Unknown keyword %s" % name + if name == "skipcondn": + try: # is skipcondn a number? + a = int(value) + except: # it is a "-" delimited sequence + value = value.lower() + parts = [ self.shift_flags.get(x.strip(),None) for x in value.split("-") ] + self.system["skipcondn"] = " | ".join(filter(None, parts)) + else: + self.system[name] = value def set(self,name,value): - msg = self.set_item(name,value) - # if valid item attrbute done - if not msg: return + # remove quotes if given + if (value[0] == value[-1]) and (value[0] in ['"',"'"]): # remove quotes + value = value[1:-1] + if self.state == "system": + err = self.set_system(name,value) + if not err: return + if self.state == "menu": + err = self.set_menu(name,value) + # change state to entry it menu returns error + if err: + err = None + self.state = "item" + if self.state == "item": + err = self.set_item(name,value) - # check if attr is of menu - err = self.set_menu(name,value) - if not err: return - - # check if global attribute - err = self.set_system(name,value) if not err: return # all errors so return item's error message - print msg + print err sys.exit(1) def print_entry(self,entry,fd): entry["type"] = self.types[entry["type"]] - fd.write(self.itemtemplate % entry) + if entry["type"] == "login": #special type + fd.write(self.templates["login"] % entry) + else: + fd.write(self.templates["item"] % entry) def print_menu(self,menu,fd): if menu["name"] == "main": self.foundmain = 1 - fd.write(self.menutemplate % menu) + fd.write(self.templates["menu"] % menu) if (menu["row"] != "0xFF") or (menu["col"] != "0xFF"): fd.write(' set_menu_pos(%(row)s,%(col)s);\n' % menu) - # parts of C code which set attrs for entire menu system - def print_system(self,fd): - if self.system["title"]: - self.system["title"] = '"%s"' % self.system["title"] - else: self.system["title"] = "NULL" - fd.write(self.systemplate % self.system) def output(self,filename): - fd = open(filename,"w") + curr_template = None + contents = [] + self.templates = {} + regbeg = re.compile(r"^--(?P<name>[a-z]+) BEGINS?--\n$") + regend = re.compile(r"^--[a-z]+ ENDS?--\n$") + ifd = open(self.code_template_filename,"r") + for line in ifd.readlines(): + b = regbeg.match(line) + e = regend.match(line) + if e: # end of template + if curr_template: + self.templates[curr_template] = "".join(contents) + curr_template = None + continue + if b: + curr_template = b.group("name") + contents = [] + continue + if not curr_template: continue # lines between templates are ignored + contents.append(line) + ifd.close() + + missing = None + for x in self.reqd_templates: + if not self.templates.has_key(x): missing = x + if missing: + print "Template %s required but not defined in %s" % (missing,self.code_template_filename) + + if filename == "-": + fd = sys.stdout + else: fd = open(filename,"w") self.foundmain = None - fd.write(TEMPLATE_HEADER) - self.print_system(fd) + fd.write(self.templates["header"]) + fd.write(self.templates["system"] % self.system) for (menu,items) in self.menus: self.print_menu(menu,fd) for entry in items: self.print_entry(entry,fd) - fd.write(TEMPLATE_FOOTER) + fd.write(self.templates["footer"]) fd.close() if not self.foundmain: print "main menu not found" + print self.menus sys.exit(1) def input(self,filename): - fd = open(filename,"r") + if filename == "-": + fd = sys.stdin + else: fd = open(filename,"r") self.lineno = 0 + self.state = "system" for line in fd.readlines(): self.lineno = self.lineno + 1 if line and line[-1] in ["\r","\n"]: line = line[:-1] if line and line[-1] in ["\r","\n"]: line = line[:-1] + line = line.strip() if line and line[0] in ["#",";"]: continue try: # blank line -> starting a new entry - if not line: - self.add_item() + if not line: + if self.state == "item": self.add_item() continue # starting a new section? if line[0] == "[" and line[-1] == "]": + self.state = "menu" self.add_menu(line[1:-1]) continue @@ -222,18 +271,37 @@ class Menusystem: fd.close() self.add_item() - def usage(): - print sys.argv[0]," inputfile outputfile" - print "inputfile is the ini-like file declaring menu structure" - print "outputfile is the C source which can be compiled" + print sys.argv[0]," [options]" + print "--input=<file> is the name of the .menu file declaring the menu structure" + print "--output=<file> is the name of generated C source" + print "--template=<file> is the name of template to be used" + print + print "input and output default to - (stdin and stdout respectively)" + print "template defaults to adv_menu.tpl" sys.exit(1) def main(): - if len(sys.argv) <> 3: usage() - inst = Menusystem() - inst.input(sys.argv[1]) - inst.output(sys.argv[2]) + tfile = "adv_menu.tpl" + ifile = "-" + ofile = "-" + opts,args = getopt.getopt(sys.argv[1:], "hi:o:t:",["input=","output=","template=","help"]) + if args: + print "Unknown options %s" % args + usage() + for o,a in opts: + if o in ["-i","--input"]: + ifile = a + elif o in ["-o", "--output"]: + ofile = a + elif o in ["-t","--template"]: + tfile = a + elif o in ["-h","--help"]: + usage() + + inst = Menusystem(tfile) + inst.input(ifile) + inst.output(ofile) if __name__ == "__main__": main() diff --git a/menu/test2.menu b/menu/test2.menu new file mode 100644 index 00000000..02e63b39 --- /dev/null +++ b/menu/test2.menu @@ -0,0 +1,143 @@ + +title=" COMBOOT Menu System " + +# location of help directory +helpdir="/isolinux/help" +pwdfile="/isolinux/password" + +# skip the menu if shift is pressed or Caps is on +# if the menu is skipped run "skipcmd" +# in our case we run the OS on the first harddisk +skipcondn=shift-caps +skipcmd="chain.c32 hd 0" + +# person with root privileges can exit menu +# others just repeat +exitcmd=".exit" +onerrorcmd=".beep 2 % % .help hlp00025.txt % .exit" + +startfile="hlp00026.txt" + +timeoutcmd=".wait" +totaltimeoutcmd="chain.c32 hd 0" + +[netmenu] +title=" Init Network " + +item="<N>one" +info="Dont start network" +type=radioitem +data="network=no" + +item="<d>hcp" +info="Use DHCP" +type=radioitem +data="network=dhcp" + +[testing] +title=" Testing " + +item="<M>emory Test" +info="Perform extensive memory testing" +data="memtest" +helpid=25 +ipappend=3 + +item="<I>nvisible" +info="You dont see this" +type=invisible + +item="<E>xit menu" +info="Go one level up" +type=exitmenu + +[rescue] +title=" Rescue Options " + +item="<L>inux Rescue" +info="Run linresc" +data="linresc" + +item="<D>os Rescue" +info="dosresc" +data="dosresc" + +item="<W>indows Rescue" +info="winresc" +data="winresc" + +item="<E>xit this menu" +info="Go one level up" +type=exitmenu + +[prep] +title=" Prep options " + +item="<b>aseurl by IP?" +info="Specify gui baseurl by IP address" +type=checkbox +data="baseurl=http://192.168.0.1" + +item="<m>ountcd?" +info="Mount the cdrom drive?" +type=checkbox +data="mountcd" + +item="Network Initialization" +info="How to initialise network device?" +type=radiomenu +data="netmenu" + +type=sep + +item="Reinstall <w>indows" +info="Re-install the windows side of a dual boot setup" +type=checkbox +data="repair=win" + +item="Reinstall <l>inux" +info="Re-install the linux side of a dual boot setup" +type=checkbox +data="repair=lin" + +type=sep + +item="<R>un prep now" +info="Execute prep with the above options" +data="prep" +argsmenu="prep" + +item="<E>xit this menu" +info="Go up one level" +type=exitmenu + +[main] + +title=" Main Menu " + +type=login + +item="<P>repare" +info="prep" +data="prep" + +item="<P>rep options..." +info="Options for prep" +type=submenu +data="prep" + +item="<R>escue options..." +info="Troubleshoot a system" +type=submenu +data="rescue" +helpid=26 + +item="<T>esting..." +info="Options to test hardware" +type=submenu +data="testing" + +item="<E>xit to prompt" +info="Exit the menu system" +type=exitmenu + |