aboutsummaryrefslogtreecommitdiffstats
path: root/com32/cmenu
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2009-03-02 10:51:25 -0800
committerH. Peter Anvin <hpa@linux.intel.com>2009-03-02 10:51:25 -0800
commit37bfb1cb8b4c1d670e0d407b83c5270f7c457389 (patch)
tree81096599d4315dc2debb8c3faa189371d1d15566 /com32/cmenu
parent2b570465a0df2070aca723559a9f309d92530e6a (diff)
downloadsyslinux.git-37bfb1cb8b4c1d670e0d407b83c5270f7c457389.tar.gz
syslinux.git-37bfb1cb8b4c1d670e0d407b83c5270f7c457389.tar.xz
syslinux.git-37bfb1cb8b4c1d670e0d407b83c5270f7c457389.zip
Move complex menu to com32/cmenu; clean up the Makefiles
Move the complex menu system into the com32 directory so it can be sequenced properly with respect to hdt (it needs to be built after com32/lib but before com32/hdt). While we're at it, clean up the Makefiles somewhat.
Diffstat (limited to 'com32/cmenu')
-rw-r--r--com32/cmenu/CHANGES32
-rw-r--r--com32/cmenu/HISTORY20
-rw-r--r--com32/cmenu/MANUAL348
-rw-r--r--com32/cmenu/MENU_FORMAT262
-rw-r--r--com32/cmenu/Makefile78
-rw-r--r--com32/cmenu/README95
-rw-r--r--com32/cmenu/TODO2
-rw-r--r--com32/cmenu/adv_menu.tpl452
-rw-r--r--com32/cmenu/complex.c423
-rw-r--r--com32/cmenu/display.c37
-rw-r--r--com32/cmenu/libmenu/com32io.c146
-rw-r--r--com32/cmenu/libmenu/com32io.h112
-rw-r--r--com32/cmenu/libmenu/des.c1101
-rw-r--r--com32/cmenu/libmenu/des.h8
-rw-r--r--com32/cmenu/libmenu/help.c200
-rw-r--r--com32/cmenu/libmenu/help.h49
-rw-r--r--com32/cmenu/libmenu/menu.c1300
-rw-r--r--com32/cmenu/libmenu/menu.h291
-rw-r--r--com32/cmenu/libmenu/passwords.c140
-rw-r--r--com32/cmenu/libmenu/passwords.h27
-rw-r--r--com32/cmenu/libmenu/scancodes.h86
-rw-r--r--com32/cmenu/libmenu/syslnx.c88
-rw-r--r--com32/cmenu/libmenu/syslnx.h64
-rw-r--r--com32/cmenu/libmenu/tui.c357
-rw-r--r--com32/cmenu/libmenu/tui.h88
-rw-r--r--com32/cmenu/menugen.py307
-rw-r--r--com32/cmenu/password18
-rw-r--r--com32/cmenu/simple.c79
-rw-r--r--com32/cmenu/test.menu60
-rw-r--r--com32/cmenu/test2.menu142
30 files changed, 6412 insertions, 0 deletions
diff --git a/com32/cmenu/CHANGES b/com32/cmenu/CHANGES
new file mode 100644
index 00000000..cce21838
--- /dev/null
+++ b/com32/cmenu/CHANGES
@@ -0,0 +1,32 @@
+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
+* Menuitem handlers now have a return value of type t_handler_return.
+ For all simple cases, you just return ACTION_VALID or ACTION_INVALID
+ (For some types of menu items, handlers are ignored, and for
+ others the return value is ignored)
+* add_menu takes an extra argument (to better control memory footprint)
+ You can just set it to -1 to choose the default value
+* Now the menu system support long menu's using scroll bars.
+* Support for passwords and context sensitive help is added.
diff --git a/com32/cmenu/HISTORY b/com32/cmenu/HISTORY
new file mode 100644
index 00000000..8e9beb3f
--- /dev/null
+++ b/com32/cmenu/HISTORY
@@ -0,0 +1,20 @@
+
+GCC & 32-bit code
+-----------------
+Due to the limitations of the COM file format,
+(64KB limit on memory footprint) the code has been changed
+so that the code compiles to a 32-bit COMBOOT program.
+Since the code makes use of BIOS calls, this code cannot be
+compiled into a format which can execute under Linux. As a
+side effect, there is no nice way to debug this code. In order
+to debug this code, you will have to run the code under syslinux.
+
+GCC & 16-bit code
+-----------------
+The code was ported to GCC by Peter Anvin.
+
+OpenWatcom & 16-bit code
+------------------------
+Originally this code was written for the Openwatcom compiler
+and generated .COM files, which could execute under DOS as well as
+SYSLINUX.
diff --git a/com32/cmenu/MANUAL b/com32/cmenu/MANUAL
new file mode 100644
index 00000000..4e70149c
--- /dev/null
+++ b/com32/cmenu/MANUAL
@@ -0,0 +1,348 @@
+ Overview of writing code using the menu system
+ ----------------------------------------------
+
+This file contains implementation and developer documentation.
+For simple cases, you should start by using simple.c as a template.
+complex.c illustrates most of the features available in the menu system.
+
+Menu Features currently supported are:
+* menu items,
+* submenus,
+* disabled items,
+* checkboxes,
+* invisible items (useful for dynamic menus), and
+* Radio menus,
+* Context sensitive help
+* Authenticated users
+
+The keys used are:
+
+* Arrow Keys, PgUp, PgDn, Home, End Keys
+* Space to switch state of a checkbox
+* Enter to choose the item
+* Escape to exit from it
+* Shortcut keys
+
+1. Overview
+-----------
+
+The code usually consists of many stages.
+
+ * Configuring the menusytem
+ * Installing global handlers [optional]
+ * Populating the menusystem
+ * Executing the menusystem
+ * Processing the result
+
+1.1 Configuring the menusystem
+------------------------------
+This includes setting the window the menu system should use,
+the choice of colors, the title of the menu etc. In most functions
+calls, a value of -1 indicates that the default value be used.
+For details about what the arguments are look at function
+declarations in menu.h
+
+<code>
+ // Choose the default title and setup default values for all attributes....
+ init_menusystem(NULL);
+ set_window_size(1,1,23,78); // Leave one row/col border all around
+
+ // Choose the default values for all attributes and char's
+ // -1 means choose defaults (Actually the next 4 lines are not needed)
+ set_normal_attr (-1,-1,-1,-1);
+ set_status_info (-1,-1);
+ set_title_info (-1,-1);
+ set_misc_info(-1,-1,-1,-1);
+</code>
+
+1.2 Populating the menusystem
+-----------------------------
+This involves adding a menu to the system, and the options which
+should appear in the menu. An example is given below.
+
+<code>
+ MAINMENU = add_menu(" Menu Title ",-1);
+ CHECKED = 1;
+ add_item("option1","Status 1",OPT_RUN,"kernel1 arg1=val1",0);
+ add_item("selfloop","Status 2",OPT_SUBMENU,NULL,MAINMENU);
+ add_item("othermenu","Status 3",OPT_SUBMENU,"menuname",0);
+ add_sep();
+ add_item("checkbox,"Checkbox Info",OPT_CHECKBOX,NULL,CHECKED);
+ add_item("Exit ","Status String",OPT_EXITMENU,NULL,0);
+</code>
+
+The call to add_menu has two arguments, the first being the title of
+the menu and the second an upper bound on the number of items in the menu.
+Putting a -1, will use the default (see MENUSIZE in menu.h). If you try
+to add more items than specified, the extra items will not appear in
+the menu. The accuracy of this number affects the memory required
+to run the system.
+
+If you do not want to keep track of the return values, you can also use
+the following variant of add_menu
+
+<code>
+add_named_menu("main"," Menu Title ",-1)
+</code>
+
+This creates a new menu as before and gives it a name "main". When using named
+menus, you get an alternate way for adding submenu's. See below for details.
+
+The call to add_item has five arguments.
+The first argument is the text which appears in the menu itself.
+The second argument is the text displayed in the status line.
+The third argument indicates the type of this menuitem. It is one of
+the following
+
+ * OPT_RUN : executable content
+ * OPT_EXITMENU : exits menu to parent
+ * OPT_SUBMENU : if selected, displays a submenu
+ * OPT_CHECKBOX : associates a boolean with this item which can be toggled
+ * OPT_RADIOMENU: associates this with a radio menu.
+ After execution, the data field of this item will point
+ to the option selected.
+ * OPT_SEP : A menu seperator (visually divide menu into parts)
+ * OPT_RADIOITEM: this item is one of the options in a RADIOMENU
+ * OPT_INACTIVE : A disabled item (user cannot select this)
+ * OPT_INVISIBLE: This item will not be displayed.
+
+The fourth argument is the value of the data field always a string.
+Usually this string is just copied and nothing is done with it. Two
+cases, where it is used.
+
+In case of a radiomenu the input string is ignored and the "data" field
+points to the menuitem chosen (Dont forget to typecast this pointer to
+(t_menuitem *) when reading this info).
+
+In case of a submenu, this string if non-trivial is interpreted as the
+name of the submenu which should be linked there. This interpretation
+happens when the menu is first run and not when the menu system is being
+created. This allows the user to create the menusystem in an arbitrary
+order.
+
+
+The fifth argument is a number whose meaning depends on the type of the
+item. For a CHECKBOX it should be 0/1 setting the initial state of the
+checkbox. For a SUBMENU it should be the index of the menu which should
+be displayed if this option is chosen. Incase the data field is non-trivial,
+this number is ignored and computed later. For a RADIOMENU it should be the
+index of the menu which contains all the options (All items in that menu
+not of type RADIOITEM are ignored). For all other types, this
+argument has no meaning at all.
+
+A call to add_sep is a convenient shorthand for calling add_item
+with the type set to OPT_SEP.
+
+1.3 Executing the menusystem
+----------------------------
+This is the simplest of all. Just call showmenus, with the index
+of the main menu as its argument. It returns a pointer to the menu
+item which was selected by the user.
+
+<code>
+ choice = showmenus(MAIN); // Initial menu is the one with index MAIN
+ // or choice = showmenus(find_menu_num("main")); // Initial menu is the one named "main"
+</code>
+
+1.4 Processing the result
+-------------------------
+This pointer will either be NULL (user hit Escape) or always point
+to a menuitem which can be "executed", i.e. it will be of type OPT_RUN.
+Usually at this point, all we need to do is to ask syslinux to run
+the command associated with this menuitem. The following code executes
+the command stored in choice->data (there is no other use for the data
+field, except for radiomenu's)
+
+<code>
+ if (choice)
+ {
+ if (choice->action == OPT_RUN)
+ {
+ if (syslinux) runcommand(choice->data);
+ else csprint(choice->data,0x07);
+ return 1;
+ }
+ csprint("Error in programming!",0x07);
+ }
+</code>
+
+2. Advanced features
+--------------------
+Everycall to add_item actually returns a pointer to the menuitem
+created. This can be useful when using any of the advanced features.
+
+2.1 extra_data
+--------------
+For example, every menuitem has an "extra_data" field (a pointer)
+which the user can use to point any data he/she pleases. The menusystem
+itself does not use this field in anyway.
+
+2.2 helpid
+----------
+Every item also has a field called "helpid". It is meant to hold some
+kind of identifier which can be referenced and used to generate
+a context sensitive help system. This can be set after a call to
+add_item as follows
+<code>
+ add_item("selfloop","Status 2",OPT_SUBMENU,NULL,MAINMENU);
+ set_item_options('A',4516);
+</code>
+
+The first is the shortcut key for this entry. You can put -1 to ensure
+that the shortcut key is not reset. The second is some unsigned integer.
+If this value is 0xFFFF, then the helpid is not changed.
+
+2.3 Installing global handlers
+------------------------------
+It is possible to register handlers for the menu system. These are
+user functions which are called by the menusystem in certain
+situations. Usually the handlers get a pointer to the menusystem
+datastructure as well as a pointer to the current item selected.
+Some handlers may get additional information. Some handlers are
+required to return values while others are not required to do so.
+
+Currently the menusystem support three types of global handlers
+* timeout handler
+* screen handler
+* keys handler
+
+2.3.1 timeout handler
+---------------------
+This is installed using a call to "reg_ontimeout(fn,numsteps,stepsize)"
+function. fn is a pointer to a function which takes no arguments and
+returns one of CODE_WAIT, CODE_ENTER, CODE_ESCAPE. This function is
+called when numsteps*stepsize Centiseconds have gone by without any
+user input. If the function returns CODE_WAIT then the menusystem
+waits for user input (for another numsteps*stepsize Centiseconds). If
+CODE_ENTER or CODE_ESCAPE is returned, then the system pretends that
+the user hit ENTER or ESCAPE on the keyboard and acts accordingly.
+
+2.3.2 Screen handler
+--------------------
+This is installed using a call to "reg_handler(HDLR_SCREEN,fn)". fn is
+a pointer to a function which takes a pointer to the menusystem
+datastructure and the current item selected and returns nothing.
+This is called everytime a menu is drawn (i.e. everytime user changes
+the current selection). This is meant for displaying any additional
+information which reflects the current state of the system.
+
+2.3.3 Keys handler
+------------------
+This is installed using a call to "reg_handler(HDLR_KEYS,fn)". fn is
+a pointer to a function which takes a pointer to the menusystem
+datastructure, the current item and the scan code of a key and returns
+nothing. This function is called when the user presses a key which
+the menusystem does not know to dealwith. In any case, when this call
+returns the screen should not have changed in any way. Usually,
+one can change the active page and display any output needed and
+reset the active page when you return from this call.
+
+complex.c implements a key_handler, which implements a simple
+context sensitive help system, by displaying the contents of a
+file whose name is based on the helpid of the active item.
+
+Also, complex.c's handler allows certain users to make changes
+to edit the commands associated with a menu item.
+
+2.4 Installing item level handlers
+----------------------------------
+In addition to global handlers, one can also install handlers for each
+individual item. A handler for an individual item is a function which
+takes a pointer to the menusystem datastructure and a pointer to the
+current item and return a structure of type t_handler_return. Currently
+it has two bit fields "valid" and "refresh".
+
+This handler is called when the user hits "enter" on a RUN item, or
+changes the status of a CHECKBOX, or called *after* a radio menu choice
+has been set. In all other cases, installing a handler has no effect.
+
+The handler can change any of the internal datastructures it pleases.
+For e.g. in a radiomenu handler, one can change the text displayed
+on the menuitem depending on which choice was selected (see complex.c
+for an example). The return values are ignored for RADIOMENU's.
+
+In case of RUN items: the return values are used as follows. If the
+return value of "valid" was false, then this user choice is ignored.
+This is useful if the handler has useful side effects. For e.g.
+complex.c has a Login item, whose handler always return INVALID. It
+sets a global variable to the name of the user logged in, and enables
+some menu items, and makes some invisible items visible.
+
+* If the handler does not change the visibility status of any items,
+ the handler should set "refresh" to 0.
+* If the handler changes the visibility status of items in the current
+ menu set "refresh" to 1.
+* If you are changing the visibility status of items in menu's currently
+ not displayed, then you can set "refresh" to 0.
+* Changing the visibility status of items in another menu
+ which is currently displayed, is not supported. If you do it,
+ the screen contents may not reflect the change until you get to the
+ menu which was changed. When you do get to that menu, you may notice
+ pieces of the old menu still on the screen.
+
+In case of CHECKBOXES: the return value of "valid" is ignored. Because,
+the handler can change the value of checkbox if the user selected value
+is not appropriate. only the value of "refresh" is honored. In this case
+all the caveats in the previous paragraph apply.
+
+menu.h defines two instances of t_handler_return
+ACTION_VALID and ACTION_INVALID for common use. These set the valid flag
+to 1 and 0 respectively and the refresh flag to 0.
+
+3. Things to look out for
+-------------------------
+When you define the menu system, always declare it in the opposite
+order, i.e. all lower level menu's should be defined before the higher
+level menus. This is because in order to define the MAINMENU, you need
+to know the index assigned to all its submenus.
+
+4. Additional Modules
+---------------------
+You can make use of the following additional modules, in writing your
+handlers.
+
+* Passwords
+* Help
+
+4.1 Passwords
+-------------
+This module was written by Th. Gebhardt. This is basically a modification
+of the DES crypt function obtained by removing the dependence of the
+original crypt function on C libraries. The following functions are
+defined
+
+ init_passwords(PWDFILE)
+ // Read in the password database from the file
+ authenticate_user(user,pwd)
+ // Checks if user,pwd is valid
+ isallowed(user,perm)
+ // Checks if the user has a specified permission
+ close_passwords()
+ // Unloads password database from memory
+
+ See the sample password file for more details about the file format
+ and the implementation of permissions.
+
+See complex.c for a example of how to use this.
+
+4.2 Help
+--------
+This can be used to set up a context sensitive help system. The following
+functions are defined
+
+ init_help(HELPBASEDIR)
+ // Initialises the help system. All help files will be loaded
+ // from the directory specified.
+ runhelpsystem(context)
+ // Displays the contents of HELPBASEDIR/hlp<context>.txt
+
+In order to have a functioning help system, you just need to create
+the hlp<NNNNN>.txt files and initialize the help system by specifying
+the base directory.
+
+The first line of this file assumed to be the title of the help screen.
+You can use ^N and ^O to change attributes absolutely and relatively,
+i.e. [^O]46 (i.e. Ctrl-O followed by chars 4 and 6) will set the
+attribute to 46, while [^N]08 will XOR the current attribute with
+specified number, thus in this case the first [^N]08 will turn on
+highlighting and the second one will turn it off.
diff --git a/com32/cmenu/MENU_FORMAT b/com32/cmenu/MENU_FORMAT
new file mode 100644
index 00000000..24cb02f8
--- /dev/null
+++ b/com32/cmenu/MENU_FORMAT
@@ -0,0 +1,262 @@
+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.
+
+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 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.
+
+All lines which occur before the first menu declaration is considered as
+a global declaration.
+
+Abstract Format
+---------------
+
+The overall format should look like this
+
+--------------------------------------------------------
+<GLOBAL SETTINGS>
+
+[menuname1]
+
+<MENU SETTINGS>
+
+<ITEM 1>
+
+...
+
+<ITEM N>
+
+[menuname2]
+
+<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
+
+.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
+
+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/com32/cmenu/Makefile b/com32/cmenu/Makefile
new file mode 100644
index 00000000..e8627a9f
--- /dev/null
+++ b/com32/cmenu/Makefile
@@ -0,0 +1,78 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2009 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.
+##
+## -----------------------------------------------------------------------
+
+##
+## Makefile for the complex menu system
+##
+
+# This must be defined before MCONFIG is included
+LIBS = libmenu/libmenu.a
+
+topdir = ../..
+include ../MCONFIG
+
+CFLAGS += -I./libmenu
+
+LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \
+ libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o
+
+CMENUS = $(patsubst %.c,%.c32,$(wildcard *.c))
+IMENUS = $(patsubst %.menu,%.c32,$(wildcard *.menu))
+
+MENUS = $(CMENUS) $(IMENUS)
+
+.SUFFIXES: .S .c .o .elf .c32 .menu
+
+.PRECIOUS: %.c
+%.c: %.menu adv_menu.tpl
+ python menugen.py --input=$< --output=$@ --template=adv_menu.tpl
+
+.PRECIOUS: %.o
+%.o: %.S
+ $(CC) $(SFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.o
+%.o: %.c %.h
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.elf
+%.elf: %.o libmenu/libmenu.a $(LIBS)
+ $(LD) $(LDFLAGS) -o $@ $^
+
+%.c32: %.elf
+ $(OBJCOPY) -O binary $< $@
+
+all: menus
+
+libmenu/libmenu.a: $(LIBMENU)
+ -rm -f $@
+ $(AR) cq $@ $^
+ $(RANLIB) $@
+
+tidy dist:
+ rm -f *.o *.lo *.a *.lst *.elf
+
+libclean:
+ rm -f libmenu/*.o libmenu/*.a
+
+clean: tidy menuclean libclean
+ rm -f *.lss *.c32 *.com
+
+menuclean:
+ rm -f $(patsubst %.menu,%.c,$(wildcard *.menu))
+
+spotless: clean libclean menuclean
+ rm -f *~ \#*
+
+menus: $(MENUS)
+
+install: # Don't install samples
diff --git a/com32/cmenu/README b/com32/cmenu/README
new file mode 100644
index 00000000..d585d2fa
--- /dev/null
+++ b/com32/cmenu/README
@@ -0,0 +1,95 @@
+ Text User Interface using comboot
+ ---------------------------------
+
+This is a menu system written by Murali Krishnan Ganapathy and ported
+from OpenWatcom to gcc by HPA. It is currently being maintained by the
+original author.
+
+To configure the menus, you need to set up a menu configuration file
+to have the menu items you desire, then build the menu system using
+make. You can use either simple.c or complex.c as a starting point
+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.
+
+See MENU_FORMAT for the syntax of .menu files
+
+The resulting code is a 32-bit COMBOOT code, and hence can be executed
+only under syslinux. You can use tools like bochs to help debug your
+code.
+
+Menu Features currently supported are:
+* menu items,
+* submenus,
+* disabled items,
+* checkboxes,
+* invisible items (useful for dynamic menus), and
+* Radio menus,
+* Context sensitive help
+* Authenticated users
+* Editing commands associated with items
+
+The keys used are:
+
+* Arrow Keys, PgUp, PgDn, Home, End Keys
+* Space to switch state of a checkbox
+* Enter to choose the item
+* Escape to exit from it
+* Shortcut keys
+
+Features
+--------
+This is a general purpose menu system implemented using only BIOS calls,
+so it can be executed in a COMBOOT environment as well. It is highly
+customizable. Some features include:
+
+* Status line
+ Display any help information associated with each menu item.
+* Window
+ Specify a window within which the menu system draws all its menu's.
+ It is upto the user to ensure that the menu's fit within the window.
+* Positioning submenus
+ By default, each submenu is positioned just below the corresponding
+ entry of the parent menu. However, the user may position each menu
+ at a specific location of his choice. This is useful, when the menu's
+ have lots of options.
+* Registering handlers for each menu item
+ This is mainly used for checkboxes and radiomenu's, where a selection may
+ result in disabling other menu items/checkboxes
+* Global Screen Handler
+ This is called every time the menu is redrawn. The user can display
+ additional information (usually outside the window where the menu is
+ being displayed). See the complex.c for an example, where the global
+ handler is used to display the choices made so far.
+* Global Keys Handler
+ This is called every time the user presses a key which the menu
+ system does not understand. This can be used to display context
+ sensitive help. See complex.c for how to use this hook to implement
+ a context sensitive help system as well as "On the fly" editing
+ of commands associated with menus.
+* Shortcut Keys
+ With each item one can register a shortcut key from [A-Za-z0-9].
+ Pressing a key within that range, will take you to the next item
+ with that shortcut key (so you can have multiple items with the
+ same shortcut key). The default shortcut key for each item, is
+ the lower case version of the first char of the item in the range
+ [A-Za-z0-9].
+* Escape Keys
+ Each item entry can have a substring enclosed in < and >. This part
+ is highlighted. Can be used to highlight the shortcut keys. By default
+ if an item has a <, then the first char inside < and > in the range
+ [A-Za-z0-9] is converted to lower case and set as the shortcut key.
+* Ontimeout handler
+ The user can register an ontimeout handler, which gets called if
+ no key has been pressed for a user specific amount of time (default 5 min).
+ For an example see the complex.c file.
+
+Credits
+-------
+* The Watcom developers and Peter Anvin for figuring out an OS
+ independent startup code.
+* Thomas for porting the crypt function and removing all C library
+ dependencies
+* Peter Anvin for porting the code to GCC
+
+- Murali (gmurali+guicd@cs.uchicago.edu)
diff --git a/com32/cmenu/TODO b/com32/cmenu/TODO
new file mode 100644
index 00000000..d2ee82c4
--- /dev/null
+++ b/com32/cmenu/TODO
@@ -0,0 +1,2 @@
+* Write COMBOOT code to read .menu files and parse them directly
+ - take the name of menu file to parse from commandline
diff --git a/com32/cmenu/adv_menu.tpl b/com32/cmenu/adv_menu.tpl
new file mode 100644
index 00000000..6ce4acf8
--- /dev/null
+++ b/com32/cmenu/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/com32/cmenu/complex.c b/com32/cmenu/complex.c
new file mode 100644
index 00000000..94627c4f
--- /dev/null
+++ b/com32/cmenu/complex.c
@@ -0,0 +1,423 @@
+/* -*- 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 "help.h"
+#include "passwords.h"
+#include "des.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Global variables */
+char infoline[160];
+char buffer[80];
+
+// Different network options
+static char nonet[] = "<n>etwork [none]";
+static char dhcpnet[]="<n>etwork [dhcp]";
+static char statnet[]="<n>etwork [static]";
+
+static char loginstr[] = "<L>ogin ";
+static char logoutstr[]= "<L>ogout ";
+
+struct {
+ unsigned int baseurl : 1; // Do we need to specify by url
+ unsigned int mountcd : 1; // Should we mount the cd
+ unsigned int winrep : 1; // Want to repair windows?
+ unsigned int linrep : 1; // Want to repair linux?
+} flags;
+
+// Some menu options
+t_menuitem *baseurl,*mountcd,*network,*runprep,*winrep,*linrep;
+t_menuitem * stat,*dhcp,*none,*prepopt,*secret;
+
+// all the menus we are going to declare
+unsigned char TESTING,RESCUE,MAIN,PREPMENU,NETMENU,LONGMENU,SECRETMENU;
+
+char username[12]; // Name of user currently using the system
+
+/* End globals */
+
+TIMEOUTCODE ontimeout()
+{
+ beep();
+ return CODE_WAIT;
+}
+
+
+#define INFLINE 22
+#define PWDLINE 3
+#define PWDPROMPT 21
+#define PWDCOLUMN 60
+#define PWDATTR 0x74
+#define EDITPROMPT 21
+
+void keys_handler(t_menusystem *ms, t_menuitem *mi,unsigned int scancode)
+{
+ char nc;
+
+ if ((scancode >> 8) == F1) { // If scancode of F1
+ 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) &&
+ (isallowed(username,"editcmd") || isallowed(username,"root"))) {
+ nc = getnumcols();
+ // User typed TAB and has permissions to edit command line
+ gotoxy(EDITPROMPT,1,ms->menupage);
+ csprint("Command line:",0x07);
+ editstring(mi->data,ACTIONLEN);
+ gotoxy(EDITPROMPT,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;
+
+ if (mi->item == loginstr) { /* User wants to login */
+ nc = getnumcols();
+ gotoxy(PWDPROMPT,1,ms->menupage);
+ csprint("Enter Username: ",0x07);
+ getstring(login, sizeof username);
+ gotoxy(PWDPROMPT,1,ms->menupage);
+ cprint(' ',0x07,nc,ms->menupage);
+ csprint("Enter Password: ",0x07);
+ getpwd(pwd, sizeof pwd);
+ gotoxy(PWDPROMPT,1,ms->menupage);
+ cprint(' ',0x07,nc,ms->menupage);
+
+ if (authenticate_user(login,pwd))
+ {
+ strcpy(username,login);
+ mi->item = logoutstr; // Change item to read "Logout"
+ }
+ else strcpy(username,GUEST_USER);
+ }
+ else // User needs to logout
+ {
+ strcpy(username,GUEST_USER);
+ mi->item = loginstr;
+ }
+
+ if (strcmp(username,GUEST_USER)==0)
+ {
+ prepopt->action = OPT_INACTIVE;
+ secret->action = OPT_INVISIBLE;
+ }
+ else
+ {
+ prepopt->action = OPT_SUBMENU;
+ prepopt->itemdata.radiomenunum = PREPMENU;
+ secret->action = OPT_SUBMENU;
+ secret->itemdata.submenunum = SECRETMENU;
+ }
+ rv.valid = 0;
+ rv.refresh = 1;
+ return rv;
+}
+
+void msys_handler(t_menusystem *ms, t_menuitem *mi)
+{
+ char nc;
+ void *v;
+ nc = getnumcols(); // Get number of columns
+
+ gotoxy(PWDLINE,PWDCOLUMN,ms->menupage);
+ csprint("User: ",PWDATTR);
+ cprint(ms->fillchar,ms->fillattr,sizeof username,ms->menupage);
+ gotoxy(PWDLINE,PWDCOLUMN +6,ms->menupage);
+ csprint(username,PWDATTR);
+
+ if (mi->parindex != PREPMENU) // If we are not in the PREP MENU
+ {
+ gotoxy(INFLINE,0,ms->menupage);
+ cprint(' ',0x07,nc,ms->menupage);
+ gotoxy(INFLINE+1,0,ms->menupage);
+ cprint(' ',0x07,nc,ms->menupage);
+ return;
+ }
+ strcpy (infoline," ");
+ if (flags.baseurl) strcat(infoline,"baseurl=http://192.168.11.12/gui ");
+ if (flags.mountcd) strcat(infoline,"mountcd=yes ");
+ v = (void *)network->data;
+ if (v!=NULL) // Some network option specified
+ {
+ strcat(infoline,"network=");
+ strcat(infoline,(char *)(((t_menuitem *)v)->data));
+ }
+ if (flags.winrep) strcat(infoline,"repair=win ");
+ if (flags.linrep) strcat(infoline,"repair=lin ");
+
+ gotoxy(INFLINE,0,ms->menupage);
+ cprint(' ',0x07,nc,ms->menupage);
+ gotoxy(INFLINE+1,0,ms->menupage);
+ cprint(' ',0x07,nc,ms->menupage);
+ gotoxy(INFLINE,0,ms->menupage);
+ csprint("Kernel Arguments:",0x07);
+ gotoxy(INFLINE,17,ms->menupage);
+ csprint(infoline,0x07);
+}
+
+t_handler_return network_handler(t_menusystem *ms, t_menuitem *mi)
+{
+ // mi=network since this is handler only for that.
+ (void)ms; // Unused
+
+ if (mi->data == (void *)none) mi->item = nonet;
+ if (mi->data == (void *)stat) mi->item = statnet;
+ if (mi->data == (void *)dhcp) mi->item = dhcpnet;
+ return ACTION_INVALID; // VALID or INVALID does not matter
+}
+
+t_handler_return checkbox_handler(t_menusystem *ms, t_menuitem *mi)
+{
+ (void)ms; /* Unused */
+
+ if (mi->action != OPT_CHECKBOX) return ACTION_INVALID;
+
+ if (strcmp(mi->data,"baseurl") == 0) flags.baseurl = (mi->itemdata.checked ? 1 : 0);
+ if (strcmp(mi->data,"winrepair") == 0) {
+ if (mi->itemdata.checked)
+ {
+ flags.winrep = 1;
+ linrep->action = OPT_INACTIVE;
+ }
+ else
+ {
+ flags.winrep = 0;
+ linrep->action = OPT_CHECKBOX;
+ }
+ }
+ if (strcmp(mi->data,"linrepair") == 0) {
+ if (mi->itemdata.checked)
+ {
+ flags.linrep = 1;
+ winrep->action = OPT_INACTIVE;
+ }
+ else
+ {
+ flags.winrep = 0;
+ winrep->action = OPT_CHECKBOX;
+ }
+ }
+ if (strcmp(mi->data,"mountcd") == 0) flags.mountcd = (mi->itemdata.checked ? 1 : 0);
+ return ACTION_VALID;
+}
+
+/*
+ Clears keyboard buffer and then
+ wait for stepsize*numsteps milliseconds for user to press any key
+ checks for keypress every stepsize milliseconds.
+ Returns: 1 if user pressed a key (not read from the buffer),
+ 0 if time elapsed
+*/
+int checkkeypress(int stepsize, int numsteps)
+{
+ int i;
+ clearkbdbuf();
+ for (i=0; i < numsteps; i++)
+ {
+ if (checkkbdbuf()) return 1;
+ sleep(stepsize);
+ }
+ return 0;
+}
+
+int main()
+{
+ t_menuitem * curr;
+ char cmd[160];
+ char ip[30];
+
+ // Set default username as guest
+ strcpy(username,GUEST_USER);
+
+ // Switch video mode here
+ // setvideomode(0x18); // or whatever mode you want
+
+ // Choose the default title and setup default values for all attributes....
+ init_passwords("/isolinux/password");
+ init_help("/isolinux/help");
+ init_menusystem(NULL);
+ set_window_size(1,1,20,78); // Leave some space around
+
+ // Choose the default values for all attributes and char's
+ // -1 means choose defaults (Actually the next 4 lines are not needed)
+ //set_normal_attr (-1,-1,-1,-1);
+ //set_status_info (-1,-1); // Display status on the last line
+ //set_title_info (-1,-1);
+ //set_misc_info(-1,-1,-1,-1);
+
+ // Register the menusystem handler
+ reg_handler(HDLR_SCREEN,&msys_handler);
+ reg_handler(HDLR_KEYS,&keys_handler);
+ // Register the ontimeout handler, with a time out of 10 seconds
+ reg_ontimeout(ontimeout,1000,0);
+
+ NETMENU = add_menu(" Init Network ",-1);
+ none = add_item("<N>one","Dont start network",OPT_RADIOITEM,"no ",0);
+ dhcp = add_item("<d>hcp","Use DHCP",OPT_RADIOITEM,"dhcp ",0);
+ stat = add_item("<s>tatic","Use static IP I will specify later",OPT_RADIOITEM,"static ",0);
+
+ TESTING = add_menu(" Testing ",-1);
+ set_menu_pos(5,55);
+ add_item("<M>emory Test","Perform extensive memory testing",OPT_RUN, "memtest",0);
+ add_item("<I>nvisible","You dont see this",OPT_INVISIBLE,"junk",0);
+ add_item("<E>xit this menu","Go one level up",OPT_EXITMENU,"exit",0);
+
+ RESCUE = add_menu(" Rescue Options ",-1);
+ add_item("<L>inux Rescue","linresc",OPT_RUN,"linresc",0);
+ add_item("<D>os Rescue","dosresc",OPT_RUN,"dosresc",0);
+ add_item("<W>indows Rescue","winresc",OPT_RUN,"winresc",0);
+ add_item("<E>xit this menu","Go one level up",OPT_EXITMENU,"exit",0);
+
+ PREPMENU = add_menu(" Prep options ",-1);
+ baseurl = add_item("<b>aseurl by IP?","Specify gui baseurl by IP address",OPT_CHECKBOX,"baseurl",0);
+ mountcd = add_item("<m>ountcd?","Mount the cdrom drive?",OPT_CHECKBOX,"mountcd",0);
+ network = add_item(dhcpnet,"How to initialise network device?",OPT_RADIOMENU,NULL,NETMENU);
+ add_sep();
+ winrep = add_item("Reinstall <w>indows","Re-install the windows side of a dual boot setup",OPT_CHECKBOX,"winrepair",0);
+ linrep = add_item("Reinstall <l>inux","Re-install the linux side of a dual boot setup",OPT_CHECKBOX,"linrepair",0);
+ add_sep();
+ runprep = add_item("<R>un prep now","Execute prep with the above options",OPT_RUN,"prep",0);
+ add_item("<E>xit this menu","Go up one level",OPT_EXITMENU,"exitmenu",0);
+ baseurl->handler = &checkbox_handler;
+ mountcd->handler = &checkbox_handler;
+ winrep->handler = &checkbox_handler;
+ linrep->handler = &checkbox_handler;
+ network->handler = &network_handler;
+ flags.baseurl = 0;
+ flags.mountcd = 0;
+ flags.winrep = 0;
+ flags.linrep = 0;
+
+ SECRETMENU = add_menu(" Secret Menu ",-1);
+ add_item("secret 1","Secret",OPT_RUN,"A",0);
+ add_item("secret 2","Secret",OPT_RUN,"A",0);
+
+ LONGMENU = add_menu(" Long Menu ",40); // Override default here
+ add_item("<A>a","Aa",OPT_RUN,"A",0);
+ add_item("<B>b","Ab",OPT_RUN,"A",0);
+ add_item("<C>","A",OPT_RUN,"A",0);
+ add_item("<D>","A",OPT_RUN,"A",0);
+ add_item("<E>","A",OPT_RUN,"A",0);
+ add_item("<F>","A",OPT_RUN,"A",0);
+ add_item("<G>","A",OPT_RUN,"A",0);
+ add_item("<H>","A",OPT_RUN,"A",0);
+ add_item("<I>","A",OPT_RUN,"A",0);
+ add_item("<J>","A",OPT_RUN,"A",0);
+ add_item("<K>","A",OPT_RUN,"A",0);
+ add_item("<L>","A",OPT_RUN,"A",0);
+ add_item("<J>","A",OPT_RUN,"A",0);
+ add_item("<K>","A",OPT_RUN,"A",0);
+ add_item("<L>","A",OPT_RUN,"A",0);
+ add_item("<M>","A",OPT_RUN,"A",0);
+ add_item("<N>","A",OPT_RUN,"A",0);
+ add_item("<O>","A",OPT_RUN,"A",0);
+ add_item("<P>","A",OPT_RUN,"A",0);
+ add_item("<Q>","A",OPT_RUN,"A",0);
+ add_item("<R>","A",OPT_RUN,"A",0);
+ add_item("<S>","A",OPT_RUN,"A",0);
+ add_item("<T>","A",OPT_RUN,"A",0);
+ add_item("<U>","A",OPT_RUN,"A",0);
+ add_item("<V>","A",OPT_RUN,"A",0);
+ add_item("<W>","A",OPT_RUN,"A",0);
+ add_item("<X>","A",OPT_RUN,"A",0);
+ add_item("<Y>","A",OPT_RUN,"A",0);
+ add_item("<Z>","A",OPT_RUN,"A",0);
+ add_item("<1>","A",OPT_RUN,"A",0);
+ add_item("<2>","A",OPT_RUN,"A",0);
+ add_item("<3>","A",OPT_RUN,"A",0);
+ add_item("<4>","A",OPT_RUN,"A",0);
+ add_item("<5>","A",OPT_RUN,"A",0);
+ add_item("<6>","A",OPT_RUN,"A",0);
+ add_item("<7>","A",OPT_RUN,"A",0);
+ add_item("<8>","A",OPT_RUN,"A",0);
+ add_item("<9>","A",OPT_RUN,"A",0);
+
+ MAIN = add_menu(" Main Menu ",8);
+ curr = add_item(loginstr,"Login as a privileged user",OPT_RUN,NULL,0);
+ set_item_options(-1,23);
+ curr->handler = &login_handler;
+
+ add_item("<P>repare","prep",OPT_RUN,"prep",0);
+ set_item_options(-1,24);
+ prepopt = add_item("<P>rep options...","Options for prep image: Requires authenticated user",OPT_INACTIVE,NULL,PREPMENU);
+ set_item_options(-1,25);
+
+ add_item("<R>escue options...","Troubleshoot a system",OPT_SUBMENU,NULL,RESCUE);
+ set_item_options(-1,26);
+ add_item("<T>esting...","Options to test hardware",OPT_SUBMENU,NULL,TESTING);
+ set_item_options(-1,27);
+ add_item("<L>ong Menu...","test menu system",OPT_SUBMENU,NULL,LONGMENU);
+ set_item_options(-1,28);
+ secret = add_item("<S>ecret Menu...","Secret menu",OPT_INVISIBLE,NULL,SECRETMENU);
+ set_item_options(-1,29);
+ add_item("<E>xit to prompt", "Exit the menu system", OPT_EXITMENU, "exit", 0);
+ set_item_options(-1,30);
+ csprint("Press any key within 5 seconds to show menu...",0x07);
+ if (!checkkeypress(100,50)) // Granularity of 100 milliseconds
+ {
+ csprint("Sorry! Time's up.\r\n",0x07);
+ return 1;
+ }
+ else clearkbdbuf(); // Just in case user pressed something important
+ curr = showmenus(MAIN);
+ if (curr)
+ {
+ if (curr->action == OPT_RUN)
+ {
+ strcpy(cmd,curr->data);
+ if (curr == runprep)
+ {
+ strcat(cmd,infoline);
+ if (network->data == (void *)stat) // We want static
+ {
+ csprint("Enter IP address (last two octets only): ",0x07);
+ strcpy(ip, "Junk");
+ editstring(ip, sizeof ip);
+ strcat(cmd,"ipaddr=192.168.");
+ strcat(cmd,ip);
+ }
+ }
+ if (issyslinux())
+ runsyslinuxcmd(cmd);
+ else csprint(cmd,0x07);
+ return 1; // Should not happen when run from SYSLINUX
+ }
+ }
+ // If user quits the menu system, control comes here
+ // If you want to execute some specific command uncomment the next two lines
+
+ // if (syslinux) runcommand(YOUR_COMMAND_HERE);
+ // else csprint(YOUR_COMMAND_HERE,0x07);
+
+ // Deallocate space used for these data structures
+ close_passwords();
+ close_help();
+ close_menusystem();
+
+ // Return to prompt
+ return 0;
+}
diff --git a/com32/cmenu/display.c b/com32/cmenu/display.c
new file mode 100644
index 00000000..5391d7fd
--- /dev/null
+++ b/com32/cmenu/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/com32/cmenu/libmenu/com32io.c b/com32/cmenu/libmenu/com32io.c
new file mode 100644
index 00000000..31aec5df
--- /dev/null
+++ b/com32/cmenu/libmenu/com32io.c
@@ -0,0 +1,146 @@
+/* -*- 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <string.h>
+#include <com32.h>
+#include "com32io.h"
+#include "syslnx.h"
+
+com32sys_t inreg,outreg; // Global register sets for use
+
+/* Print character and attribute at cursor */
+void cprint(char chr,char attr,unsigned int times,char disppage)
+{
+ REG_AH(inreg) = 0x09;
+ REG_AL(inreg) = chr;
+ REG_BH(inreg) = disppage;
+ REG_BL(inreg) = attr;
+ REG_CX(inreg) = times;
+ __intcall(0x10,&inreg,&outreg);
+}
+
+void setdisppage(char num) // Set the display page to specified number
+{
+ REG_AH(inreg) = 0x05;
+ REG_AL(inreg) = num;
+ __intcall(0x10,&inreg,&outreg);
+}
+
+char getdisppage() // Get current display page
+{
+ REG_AH(inreg) = 0x0f;
+ __intcall(0x10,&inreg,&outreg);
+ return REG_BH(outreg);
+}
+
+void getpos(char * row, char * col, char page)
+{
+ REG_AH(inreg) = 0x03;
+ REG_BH(inreg) = page;
+ __intcall(0x10,&inreg,&outreg);
+ *row = REG_DH(outreg);
+ *col = REG_DL(outreg);
+}
+
+void gotoxy(char row,char col, char page)
+{
+ REG_AH(inreg) = 0x02;
+ REG_BH(inreg) = page;
+ REG_DX(inreg) = (row << 8)+col;
+ __intcall(0x10,&inreg,&outreg);
+}
+
+unsigned char sleep(unsigned int msec)
+{
+ unsigned long micro = 1000*msec;
+
+ REG_AH(inreg) = 0x86;
+ REG_CX(inreg) = (micro >> 16);
+ REG_DX(inreg) = (micro & 0xFFFF);
+ __intcall(0x15,&inreg,&outreg);
+ return REG_AH(outreg);
+}
+
+void beep()
+{
+ REG_AH(inreg) = 0x0E;
+ REG_AL(inreg) = 0x07;
+ REG_BH(inreg) = 0;
+ __intcall(0x10,&inreg,&outreg);
+}
+
+void scrollupwindow(char top, char left, char bot, char right, char attr,char numlines)
+{
+ REG_AH(inreg) = 0x06;
+ 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);
+ return REG_AL(outreg);
+}
+
+void getcursorshape(char *start, char *end)
+{
+ char page = getdisppage();
+ REG_AH(inreg) = 0x03;
+ REG_BH(inreg) = page;
+ __intcall(0x10,&inreg,&outreg);
+ *start = REG_CH(outreg);
+ *end = REG_CL(outreg);
+}
+
+void setcursorshape(char start, char end)
+{
+ REG_AH(inreg) = 0x01;
+ REG_CH(inreg) = start;
+ REG_CL(inreg) = end;
+ __intcall(0x10,&inreg,&outreg);
+}
+
+char getchar(void)
+{
+ REG_AH(inreg) = 0x08;
+ __intcall(0x21,&inreg,&outreg);
+ return REG_AL(outreg);
+}
+
+void setvideomode(char mode)
+{
+ REG_AH(inreg) = 0x00;
+ REG_AL(inreg) = mode;
+ __intcall(0x10,&inreg,&outreg);
+}
+
+unsigned char checkkbdbuf()
+{
+ REG_AH(inreg) = 0x11;
+ __intcall(0x16,&inreg,&outreg);
+ return !(outreg.eflags.l & EFLAGS_ZF);
+}
+
+// Get char displayed at current position
+unsigned char getcharat(char page)
+{
+ REG_AH(inreg) = 0x08;
+ REG_BH(inreg) = page;
+ __intcall(0x16,&inreg,&outreg);
+ return REG_AL(outreg);
+}
diff --git a/com32/cmenu/libmenu/com32io.h b/com32/cmenu/libmenu/com32io.h
new file mode 100644
index 00000000..78ce72fa
--- /dev/null
+++ b/com32/cmenu/libmenu/com32io.h
@@ -0,0 +1,112 @@
+/* -*- 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 __COM32IO_H__
+#define __COM32IO_H__
+
+#include <com32.h>
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+/* BIOS Assisted output routines */
+
+void cswprint(const char *str, char attr, char left);
+// Print a C str (NUL-terminated) respecting the left edge of window
+// i.e. \n in str will move cursor to column left
+// Print a C str (NUL-terminated)
+
+static inline void csprint(const char *str, char attr)
+{
+ cswprint(str,attr,0);
+}
+
+void cprint(char chr,char attr,unsigned int times, char disppage); // Print a char
+
+void setdisppage(char num); // Set the display page to specified number
+
+char getdisppage(); // Get current display page
+
+void gotoxy(char row,char col, char page);
+
+void getpos(char * row, char * col, char page);
+
+char inputc(char * scancode); // Return ASCII char by val, and scancode by reference
+
+static inline void putch(char x, char attr, char page)
+{
+ cprint(x,attr,1,page);
+}
+
+void setcursorshape(char start,char end); // Set cursor shape
+void getcursorshape(char *start,char *end); // Get shape for current page
+
+// Get char displayed at current position in specified page
+unsigned char getcharat(char page);
+
+static inline void cursoroff(void) /* Turns off cursor */
+{
+ setcursorshape(32,33);
+}
+
+static inline void cursoron(void) /* Turns on cursor */
+{
+ setcursorshape(6,7);
+}
+
+static inline unsigned char readbiosb(unsigned int ofs)
+{
+ return *((unsigned char *)MK_PTR(0,ofs));
+}
+
+static inline char getnumrows()
+{
+ return readbiosb(0x484); // Actually numrows - 1
+}
+
+static inline char getnumcols(void)
+{
+ return readbiosb(0x44a); // Actually numcols
+}
+
+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
+
+unsigned char checkkbdbuf(); // Check to see if there is kbd buffer is non-empty?
+
+static inline void clearkbdbuf() // Clear the kbd buffer (how many chars removed?)
+{
+ while (checkkbdbuf()) inputc(NULL);
+}
+
+#endif
diff --git a/com32/cmenu/libmenu/des.c b/com32/cmenu/libmenu/des.c
new file mode 100644
index 00000000..47ff78c4
--- /dev/null
+++ b/com32/cmenu/libmenu/des.c
@@ -0,0 +1,1101 @@
+/*
+ * FreeSec: libcrypt for NetBSD
+ *
+ * Copyright (c) 1994 David Burren
+ * All rights reserved.
+ *
+ * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet
+ * this file should now *only* export crypt(), in order to make
+ * binaries of libcrypt exportable from the USA
+ *
+ * Adapted for FreeBSD-4.0 by Mark R V Murray
+ * this file should now *only* export crypt_des(), in order to make
+ * a module that can be optionally included in libcrypt.
+ *
+ * Adapted for pxelinux menu environment by Th.Gebhardt
+ * removed dependencies of standard C libs
+ * added LOWSPACE option (using common space for different arrays)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This is an original implementation of the DES and the crypt(3) interfaces
+ * by David Burren <davidb@werj.com.au>.
+ *
+ * An excellent reference on the underlying algorithm (and related
+ * algorithms) is:
+ *
+ * B. Schneier, Applied Cryptography: protocols, algorithms,
+ * and source code in C, John Wiley & Sons, 1994.
+ *
+ * Note that in that book's description of DES the lookups for the initial,
+ * pbox, and final permutations are inverted (this has been brought to the
+ * attention of the author). A list of errata for this book has been
+ * posted to the sci.crypt newsgroup by the author and is available for FTP.
+ *
+ * ARCHITECTURE ASSUMPTIONS:
+ * It is assumed that the 8-byte arrays passed by reference can be
+ * addressed as arrays of u_int32_t's (ie. the CPU is not picky about
+ * alignment).
+ */
+
+
+#define LOWSPACE
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+typedef unsigned long my_u_int32_t;
+typedef unsigned char my_u_char_t;
+
+/* Re-entrantify me -- all this junk needs to be in
+ * struct crypt_data to make this really reentrant... */
+static my_u_char_t inv_key_perm[64];
+static my_u_char_t inv_comp_perm[56];
+static my_u_char_t u_sbox[8][64];
+static my_u_char_t un_pbox[32];
+static my_u_int32_t en_keysl[16], en_keysr[16];
+static my_u_int32_t de_keysl[16], de_keysr[16];
+
+#ifndef LOWSPACE
+static my_u_int32_t ip_maskl[8][256], ip_maskr[8][256];
+static my_u_int32_t fp_maskl[8][256], fp_maskr[8][256];
+static my_u_int32_t key_perm_maskl[8][128], key_perm_maskr[8][128];
+static my_u_int32_t comp_maskl[8][128], comp_maskr[8][128];
+#endif
+
+static my_u_int32_t saltbits;
+static my_u_int32_t old_salt;
+static my_u_int32_t old_rawkey0, old_rawkey1;
+
+#ifdef LOWSPACE
+static my_u_int32_t common[8][256];
+#endif
+
+/* Static stuff that stays resident and doesn't change after
+ * being initialized, and therefore doesn't need to be made
+ * reentrant. */
+static my_u_char_t init_perm[64], final_perm[64];
+static my_u_char_t m_sbox[4][4096];
+
+#ifndef LOWSPACE
+static my_u_int32_t psbox[4][256];
+#endif
+
+/* A pile of data */
+static const my_u_char_t ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static const my_u_char_t IP[64] = {
+ 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
+};
+
+static const my_u_char_t key_perm[56] = {
+ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
+};
+
+static const my_u_char_t key_shifts[16] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+static const my_u_char_t comp_perm[48] = {
+ 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ * No E box is used, as it's replaced by some ANDs, shifts, and ORs.
+ */
+
+static const my_u_char_t sbox[8][64] = {
+ {
+ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
+ },
+ {
+ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
+ },
+ {
+ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
+ },
+ {
+ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
+ },
+ {
+ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
+ },
+ {
+ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
+ },
+ {
+ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
+ },
+ {
+ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
+ }
+};
+
+static const my_u_char_t pbox[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+static const my_u_int32_t bits32[32] =
+{
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static const my_u_int32_t bits28[28] =
+{
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static const my_u_int32_t bits24[24] =
+{
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static const my_u_char_t bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+// static const my_u_int32_t *bits28, *bits24;
+
+
+static int
+ascii_to_bin(char ch)
+{
+ if (ch > 'z')
+ return(0);
+ if (ch >= 'a')
+ return(ch - 'a' + 38);
+ if (ch > 'Z')
+ return(0);
+ if (ch >= 'A')
+ return(ch - 'A' + 12);
+ if (ch > '9')
+ return(0);
+ if (ch >= '.')
+ return(ch - '.');
+ return(0);
+}
+
+static void
+des_init(void)
+{
+
+#ifdef LOWSPACE
+ int i, j, b;
+#else
+ int i, j, b, k, inbit, obit;
+ my_u_int32_t *p, *il, *ir, *fl, *fr;
+#endif
+ static int des_initialised = 0;
+
+ if (des_initialised==1)
+ return;
+
+ old_rawkey0 = old_rawkey1 = 0L;
+ saltbits = 0L;
+ old_salt = 0L;
+ // bits24 = (bits28 = bits32 + 4) + 4;
+
+ /*
+ * Invert the S-boxes, reordering the input bits.
+ */
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 64; j++) {
+ b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf);
+ u_sbox[i][j] = sbox[i][b];
+ }
+
+ /*
+ * Convert the inverted S-boxes into 4 arrays of 8 bits.
+ * Each will handle 12 bits of the S-box input.
+ */
+ for (b = 0; b < 4; b++)
+ for (i = 0; i < 64; i++)
+ for (j = 0; j < 64; j++)
+ m_sbox[b][(i << 6) | j] =
+ (my_u_char_t)((u_sbox[(b << 1)][i] << 4) |
+ u_sbox[(b << 1) + 1][j]);
+
+ /*
+ * Set up the initial & final permutations into a useful form, and
+ * initialise the inverted key permutation.
+ */
+ for (i = 0; i < 64; i++) {
+ init_perm[final_perm[i] = IP[i] - 1] = (my_u_char_t)i;
+ inv_key_perm[i] = 255;
+ }
+
+ /*
+ * Invert the key permutation and initialise the inverted key
+ * compression permutation.
+ */
+ for (i = 0; i < 56; i++) {
+ inv_key_perm[key_perm[i] - 1] = (my_u_char_t)i;
+ inv_comp_perm[i] = 255;
+ }
+
+ /*
+ * Invert the key compression permutation.
+ */
+ for (i = 0; i < 48; i++) {
+ inv_comp_perm[comp_perm[i] - 1] = (my_u_char_t)i;
+ }
+
+ /*
+ * Set up the OR-mask arrays for the initial and final permutations,
+ * and for the key initial and compression permutations.
+ */
+
+#ifndef LOWSPACE
+ for (k = 0; k < 8; k++) {
+ for (i = 0; i < 256; i++) {
+ *(il = &ip_maskl[k][i]) = 0L;
+ *(ir = &ip_maskr[k][i]) = 0L;
+ *(fl = &fp_maskl[k][i]) = 0L;
+ *(fr = &fp_maskr[k][i]) = 0L;
+ for (j = 0; j < 8; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j]) {
+ if ((obit = init_perm[inbit]) < 32)
+ *il |= bits32[obit];
+ else
+ *ir |= bits32[obit-32];
+ if ((obit = final_perm[inbit]) < 32)
+ *fl |= bits32[obit];
+ else
+ *fr |= bits32[obit - 32];
+ }
+ }
+ }
+ for (i = 0; i < 128; i++) {
+ *(il = &key_perm_maskl[k][i]) = 0L;
+ *(ir = &key_perm_maskr[k][i]) = 0L;
+ for (j = 0; j < 7; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j + 1]) {
+ if ((obit = inv_key_perm[inbit]) == 255)
+ continue;
+ if (obit < 28)
+ *il |= bits28[obit];
+ else
+ *ir |= bits28[obit - 28];
+ }
+ }
+ *(il = &comp_maskl[k][i]) = 0L;
+ *(ir = &comp_maskr[k][i]) = 0L;
+ for (j = 0; j < 7; j++) {
+ inbit = 7 * k + j;
+ if (i & bits8[j + 1]) {
+ if ((obit=inv_comp_perm[inbit]) == 255)
+ continue;
+ if (obit < 24)
+ *il |= bits24[obit];
+ else
+ *ir |= bits24[obit - 24];
+ }
+ }
+ }
+ }
+#endif
+
+ /*
+ * Invert the P-box permutation, and convert into OR-masks for
+ * handling the output of the S-box arrays setup above.
+ */
+ for (i = 0; i < 32; i++)
+ un_pbox[pbox[i] - 1] = (my_u_char_t)i;
+
+#ifndef LOWSPACE
+ for (b = 0; b < 4; b++)
+ for (i = 0; i < 256; i++) {
+ *(p = &psbox[b][i]) = 0L;
+ for (j = 0; j < 8; j++) {
+ if (i & bits8[j])
+ *p |= bits32[un_pbox[8 * b + j]];
+ }
+ }
+#endif
+ des_initialised = 1;
+}
+
+
+#ifdef LOWSPACE
+
+static void
+setup_ip_maskl(void)
+{
+ int i, j, k, inbit, obit;
+ my_u_int32_t *il;
+
+ for (k = 0; k < 8; k++) {
+ for (i = 0; i < 256; i++) {
+ *(il = &common[k][i]) = 0L;
+ for (j = 0; j < 8; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j]) {
+ if ((obit = init_perm[inbit]) < 32)
+ *il |= bits32[obit];
+ }
+ }
+ }
+ }
+}
+
+static void
+setup_ip_maskr(void)
+{
+ int i, j, k, inbit, obit;
+ my_u_int32_t *ir;
+
+ for (k = 0; k < 8; k++) {
+ for (i = 0; i < 256; i++) {
+ *(ir = &common[k][i]) = 0L;
+ for (j = 0; j < 8; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j]) {
+ if ((obit = init_perm[inbit]) >= 32)
+ *ir |= bits32[obit-32];
+ }
+ }
+ }
+ }
+}
+
+static void
+setup_fp_maskl(void)
+{
+ int i, j, k, inbit, obit;
+ my_u_int32_t *fl;
+
+ for (k = 0; k < 8; k++) {
+ for (i = 0; i < 256; i++) {
+ *(fl = &common[k][i]) = 0L;
+ for (j = 0; j < 8; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j]) {
+ if ((obit = final_perm[inbit]) < 32)
+ *fl |= bits32[obit];
+ }
+ }
+ }
+ }
+}
+
+static void
+setup_fp_maskr(void)
+{
+ int i, j, k, inbit, obit;
+ my_u_int32_t *fr;
+
+ for (k = 0; k < 8; k++) {
+ for (i = 0; i < 256; i++) {
+ *(fr = &common[k][i]) = 0L;
+ for (j = 0; j < 8; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j]) {
+ if ((obit = final_perm[inbit]) >= 32)
+ *fr |= bits32[obit - 32];
+ }
+ }
+ }
+ }
+}
+
+static void
+setup_key_perm_maskl(void)
+{
+ int i, j, k, inbit, obit;
+ my_u_int32_t *il;
+
+ for (k = 0; k < 8; k++) {
+ for (i = 0; i < 128; i++) {
+ *(il = &common[k][i]) = 0L;
+ for (j = 0; j < 7; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j + 1]) {
+ if ((obit = inv_key_perm[inbit]) == 255)
+ continue;
+ if (obit < 28)
+ *il |= bits28[obit];
+ }
+ }
+ }
+ }
+}
+
+static void
+setup_key_perm_maskr(void)
+{
+ int i, j, k, inbit, obit;
+ my_u_int32_t *ir;
+
+ for (k = 0; k < 8; k++) {
+ for (i = 0; i < 128; i++) {
+ *(ir = &common[k][i]) = 0L;
+ for (j = 0; j < 7; j++) {
+ inbit = 8 * k + j;
+ if (i & bits8[j + 1]) {
+ if ((obit = inv_key_perm[inbit]) == 255)
+ continue;
+ if (obit >= 28)
+ *ir |= bits28[obit - 28];
+ }
+ }
+ }
+ }
+}
+
+static void
+setup_comp_maskl(void)
+{
+ int i, j, k, inbit, obit;
+ my_u_int32_t *il;
+
+ for (k = 0; k < 8; k++) {
+ for (i = 0; i < 128; i++) {
+ *(il = &common[k][i]) = 0L;
+ for (j = 0; j < 7; j++) {
+ inbit = 7 * k + j;
+ if (i & bits8[j + 1]) {
+ if ((obit=inv_comp_perm[inbit]) == 255)
+ continue;
+ if (obit < 24)
+ *il |= bits24[obit];
+ }
+ }
+ }
+ }
+}
+
+static void
+setup_comp_maskr(void)
+{
+ int i, j, k, inbit, obit;
+ my_u_int32_t *ir;
+
+ for (k = 0; k < 8; k++) {
+ for (i = 0; i < 128; i++) {
+ *(ir = &common[k][i]) = 0L;
+ for (j = 0; j < 7; j++) {
+ inbit = 7 * k + j;
+ if (i & bits8[j + 1]) {
+ if ((obit=inv_comp_perm[inbit]) == 255)
+ continue;
+ if (obit >= 24)
+ *ir |= bits24[obit - 24];
+ }
+ }
+ }
+ }
+}
+
+static void
+setup_psbox(void)
+{
+ int i, j, b;
+ my_u_int32_t *p;
+
+ for (b = 0; b < 4; b++)
+ for (i = 0; i < 256; i++) {
+ *(p = &common[b][i]) = 0L;
+ for (j = 0; j < 8; j++) {
+ if (i & bits8[j])
+ *p |= bits32[un_pbox[8 * b + j]];
+ }
+ }
+}
+
+#endif
+
+static void
+setup_salt(my_u_int32_t salt)
+{
+ my_u_int32_t obit, saltbit;
+ int i;
+
+ if (salt == old_salt)
+ return;
+ old_salt = salt;
+
+ saltbits = 0L;
+ saltbit = 1;
+ obit = 0x800000;
+ for (i = 0; i < 24; i++) {
+ if (salt & saltbit)
+ saltbits |= obit;
+ saltbit <<= 1;
+ obit >>= 1;
+ }
+}
+
+
+static my_u_int32_t char_to_int(const char *key)
+{
+ my_u_int32_t byte0,byte1,byte2,byte3;
+ byte0 = (my_u_int32_t) (my_u_char_t) key[0];
+ byte1 = (my_u_int32_t) (my_u_char_t) key[1];
+ byte2 = (my_u_int32_t) (my_u_char_t) key[2];
+ byte3 = (my_u_int32_t) (my_u_char_t) key[3];
+
+ return byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3 ;
+}
+
+
+static int
+des_setkey(const char *key)
+{
+ my_u_int32_t k0, k1, rawkey0, rawkey1;
+ int shifts, round;
+
+ des_init();
+
+ /* rawkey0 = ntohl(*(const my_u_int32_t *) key);
+ * rawkey1 = ntohl(*(const my_u_int32_t *) (key + 4));
+ */
+
+ rawkey0 = char_to_int(key);
+ rawkey1 = char_to_int(key+4);
+
+ if ((rawkey0 | rawkey1)
+ && rawkey0 == old_rawkey0
+ && rawkey1 == old_rawkey1) {
+ /*
+ * Already setup for this key.
+ * This optimisation fails on a zero key (which is weak and
+ * has bad parity anyway) in order to simplify the starting
+ * conditions.
+ */
+ return(0);
+ }
+ old_rawkey0 = rawkey0;
+ old_rawkey1 = rawkey1;
+
+ /*
+ * Do key permutation and split into two 28-bit subkeys.
+ */
+
+#ifdef LOWSPACE
+ setup_key_perm_maskl();
+ k0 = common[0][rawkey0 >> 25]
+ | common[1][(rawkey0 >> 17) & 0x7f]
+ | common[2][(rawkey0 >> 9) & 0x7f]
+ | common[3][(rawkey0 >> 1) & 0x7f]
+ | common[4][rawkey1 >> 25]
+ | common[5][(rawkey1 >> 17) & 0x7f]
+ | common[6][(rawkey1 >> 9) & 0x7f]
+ | common[7][(rawkey1 >> 1) & 0x7f];
+ setup_key_perm_maskr();
+ k1 = common[0][rawkey0 >> 25]
+ | common[1][(rawkey0 >> 17) & 0x7f]
+ | common[2][(rawkey0 >> 9) & 0x7f]
+ | common[3][(rawkey0 >> 1) & 0x7f]
+ | common[4][rawkey1 >> 25]
+ | common[5][(rawkey1 >> 17) & 0x7f]
+ | common[6][(rawkey1 >> 9) & 0x7f]
+ | common[7][(rawkey1 >> 1) & 0x7f];
+#else
+ k0 = key_perm_maskl[0][rawkey0 >> 25]
+ | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskl[4][rawkey1 >> 25]
+ | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];
+ k1 = key_perm_maskr[0][rawkey0 >> 25]
+ | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]
+ | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]
+ | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]
+ | key_perm_maskr[4][rawkey1 >> 25]
+ | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]
+ | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]
+ | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];
+#endif
+
+ /*
+ * Rotate subkeys and do compression permutation.
+ */
+ shifts = 0;
+ for (round = 0; round < 16; round++) {
+ my_u_int32_t t0, t1;
+
+ shifts += key_shifts[round];
+
+ t0 = (k0 << shifts) | (k0 >> (28 - shifts));
+ t1 = (k1 << shifts) | (k1 >> (28 - shifts));
+
+#ifdef LOWSPACE
+ setup_comp_maskl();
+ de_keysl[15 - round] =
+ en_keysl[round] = common[0][(t0 >> 21) & 0x7f]
+ | common[1][(t0 >> 14) & 0x7f]
+ | common[2][(t0 >> 7) & 0x7f]
+ | common[3][t0 & 0x7f]
+ | common[4][(t1 >> 21) & 0x7f]
+ | common[5][(t1 >> 14) & 0x7f]
+ | common[6][(t1 >> 7) & 0x7f]
+ | common[7][t1 & 0x7f];
+
+ setup_comp_maskr();
+ de_keysr[15 - round] =
+ en_keysr[round] = common[0][(t0 >> 21) & 0x7f]
+ | common[1][(t0 >> 14) & 0x7f]
+ | common[2][(t0 >> 7) & 0x7f]
+ | common[3][t0 & 0x7f]
+ | common[4][(t1 >> 21) & 0x7f]
+ | common[5][(t1 >> 14) & 0x7f]
+ | common[6][(t1 >> 7) & 0x7f]
+ | common[7][t1 & 0x7f];
+#else
+ de_keysl[15 - round] =
+ en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]
+ | comp_maskl[1][(t0 >> 14) & 0x7f]
+ | comp_maskl[2][(t0 >> 7) & 0x7f]
+ | comp_maskl[3][t0 & 0x7f]
+ | comp_maskl[4][(t1 >> 21) & 0x7f]
+ | comp_maskl[5][(t1 >> 14) & 0x7f]
+ | comp_maskl[6][(t1 >> 7) & 0x7f]
+ | comp_maskl[7][t1 & 0x7f];
+
+ de_keysr[15 - round] =
+ en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f]
+ | comp_maskr[1][(t0 >> 14) & 0x7f]
+ | comp_maskr[2][(t0 >> 7) & 0x7f]
+ | comp_maskr[3][t0 & 0x7f]
+ | comp_maskr[4][(t1 >> 21) & 0x7f]
+ | comp_maskr[5][(t1 >> 14) & 0x7f]
+ | comp_maskr[6][(t1 >> 7) & 0x7f]
+ | comp_maskr[7][t1 & 0x7f];
+#endif
+ }
+ return(0);
+}
+
+
+static int
+do_des( my_u_int32_t l_in, my_u_int32_t r_in, my_u_int32_t *l_out, my_u_int32_t *r_out, int count)
+{
+ /*
+ * l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
+ */
+ my_u_int32_t l, r, *kl, *kr, *kl1, *kr1;
+ my_u_int32_t f, r48l, r48r;
+ int round;
+
+ if (count == 0) {
+ return(1);
+ } else if (count > 0) {
+ /*
+ * Encrypting
+ */
+ kl1 = en_keysl;
+ kr1 = en_keysr;
+ } else {
+ /*
+ * Decrypting
+ */
+ count = -count;
+ kl1 = de_keysl;
+ kr1 = de_keysr;
+ }
+
+ /*
+ * Do initial permutation (IP).
+ */
+
+#ifdef LOWSPACE
+ setup_ip_maskl();
+ l = common[0][l_in >> 24]
+ | common[1][(l_in >> 16) & 0xff]
+ | common[2][(l_in >> 8) & 0xff]
+ | common[3][l_in & 0xff]
+ | common[4][r_in >> 24]
+ | common[5][(r_in >> 16) & 0xff]
+ | common[6][(r_in >> 8) & 0xff]
+ | common[7][r_in & 0xff];
+ setup_ip_maskr();
+ r = common[0][l_in >> 24]
+ | common[1][(l_in >> 16) & 0xff]
+ | common[2][(l_in >> 8) & 0xff]
+ | common[3][l_in & 0xff]
+ | common[4][r_in >> 24]
+ | common[5][(r_in >> 16) & 0xff]
+ | common[6][(r_in >> 8) & 0xff]
+ | common[7][r_in & 0xff];
+#else
+ l = ip_maskl[0][l_in >> 24]
+ | ip_maskl[1][(l_in >> 16) & 0xff]
+ | ip_maskl[2][(l_in >> 8) & 0xff]
+ | ip_maskl[3][l_in & 0xff]
+ | ip_maskl[4][r_in >> 24]
+ | ip_maskl[5][(r_in >> 16) & 0xff]
+ | ip_maskl[6][(r_in >> 8) & 0xff]
+ | ip_maskl[7][r_in & 0xff];
+ r = ip_maskr[0][l_in >> 24]
+ | ip_maskr[1][(l_in >> 16) & 0xff]
+ | ip_maskr[2][(l_in >> 8) & 0xff]
+ | ip_maskr[3][l_in & 0xff]
+ | ip_maskr[4][r_in >> 24]
+ | ip_maskr[5][(r_in >> 16) & 0xff]
+ | ip_maskr[6][(r_in >> 8) & 0xff]
+ | ip_maskr[7][r_in & 0xff];
+#endif
+
+ while (count--) {
+ /*
+ * Do each round.
+ */
+ kl = kl1;
+ kr = kr1;
+ round = 16;
+ while (round--) {
+ /*
+ * Expand R to 48 bits (simulate the E-box).
+ */
+ r48l = ((r & 0x00000001) << 23)
+ | ((r & 0xf8000000) >> 9)
+ | ((r & 0x1f800000) >> 11)
+ | ((r & 0x01f80000) >> 13)
+ | ((r & 0x001f8000) >> 15);
+
+ r48r = ((r & 0x0001f800) << 7)
+ | ((r & 0x00001f80) << 5)
+ | ((r & 0x000001f8) << 3)
+ | ((r & 0x0000001f) << 1)
+ | ((r & 0x80000000) >> 31);
+ /*
+ * Do salting for crypt() and friends, and
+ * XOR with the permuted key.
+ */
+ f = (r48l ^ r48r) & saltbits;
+ r48l ^= f ^ *kl++;
+ r48r ^= f ^ *kr++;
+ /*
+ * Do sbox lookups (which shrink it back to 32 bits)
+ * and do the pbox permutation at the same time.
+ */
+
+#ifdef LOWSPACE
+ setup_psbox();
+ f = common[0][m_sbox[0][r48l >> 12]]
+ | common[1][m_sbox[1][r48l & 0xfff]]
+ | common[2][m_sbox[2][r48r >> 12]]
+ | common[3][m_sbox[3][r48r & 0xfff]];
+#else
+ f = psbox[0][m_sbox[0][r48l >> 12]]
+ | psbox[1][m_sbox[1][r48l & 0xfff]]
+ | psbox[2][m_sbox[2][r48r >> 12]]
+ | psbox[3][m_sbox[3][r48r & 0xfff]];
+#endif
+ /*
+ * Now that we've permuted things, complete f().
+ */
+ f ^= l;
+ l = r;
+ r = f;
+ }
+ r = l;
+ l = f;
+ }
+ /*
+ * Do final permutation (inverse of IP).
+ */
+
+#ifdef LOWSPACE
+ setup_fp_maskl();
+ *l_out = common[0][l >> 24]
+ | common[1][(l >> 16) & 0xff]
+ | common[2][(l >> 8) & 0xff]
+ | common[3][l & 0xff]
+ | common[4][r >> 24]
+ | common[5][(r >> 16) & 0xff]
+ | common[6][(r >> 8) & 0xff]
+ | common[7][r & 0xff];
+ setup_fp_maskr();
+ *r_out = common[0][l >> 24]
+ | common[1][(l >> 16) & 0xff]
+ | common[2][(l >> 8) & 0xff]
+ | common[3][l & 0xff]
+ | common[4][r >> 24]
+ | common[5][(r >> 16) & 0xff]
+ | common[6][(r >> 8) & 0xff]
+ | common[7][r & 0xff];
+#else
+ *l_out = fp_maskl[0][l >> 24]
+ | fp_maskl[1][(l >> 16) & 0xff]
+ | fp_maskl[2][(l >> 8) & 0xff]
+ | fp_maskl[3][l & 0xff]
+ | fp_maskl[4][r >> 24]
+ | fp_maskl[5][(r >> 16) & 0xff]
+ | fp_maskl[6][(r >> 8) & 0xff]
+ | fp_maskl[7][r & 0xff];
+ *r_out = fp_maskr[0][l >> 24]
+ | fp_maskr[1][(l >> 16) & 0xff]
+ | fp_maskr[2][(l >> 8) & 0xff]
+ | fp_maskr[3][l & 0xff]
+ | fp_maskr[4][r >> 24]
+ | fp_maskr[5][(r >> 16) & 0xff]
+ | fp_maskr[6][(r >> 8) & 0xff]
+ | fp_maskr[7][r & 0xff];
+#endif
+ return(0);
+}
+
+
+#if 0
+static int
+des_cipher(const char *in, char *out, my_u_int32_t salt, int count)
+{
+ my_u_int32_t l_out, r_out, rawl, rawr;
+ int retval;
+ union {
+ my_u_int32_t *ui32;
+ const char *c;
+ } trans;
+
+ des_init();
+
+ setup_salt(salt);
+
+ trans.c = in;
+ rawl = ntohl(*trans.ui32++);
+ rawr = ntohl(*trans.ui32);
+
+ retval = do_des(rawl, rawr, &l_out, &r_out, count);
+
+ trans.c = out;
+ *trans.ui32++ = htonl(l_out);
+ *trans.ui32 = htonl(r_out);
+ return(retval);
+}
+#endif
+
+
+void
+setkey(const char *key)
+{
+ int i, j;
+ my_u_int32_t packed_keys[2];
+ my_u_char_t *p;
+
+ p = (my_u_char_t *) packed_keys;
+
+ for (i = 0; i < 8; i++) {
+ p[i] = 0;
+ for (j = 0; j < 8; j++)
+ if (*key++ & 1)
+ p[i] |= bits8[j];
+ }
+ des_setkey(p);
+}
+
+
+void
+encrypt(char *block, int flag)
+{
+ my_u_int32_t io[2];
+ my_u_char_t *p;
+ int i, j;
+
+ des_init();
+
+ setup_salt(0L);
+ p = block;
+ for (i = 0; i < 2; i++) {
+ io[i] = 0L;
+ for (j = 0; j < 32; j++)
+ if (*p++ & 1)
+ io[i] |= bits32[j];
+ }
+ do_des(io[0], io[1], io, io + 1, flag ? -1 : 1);
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 32; j++)
+ block[(i << 5) | j] = (io[i] & bits32[j]) ? 1 : 0;
+}
+
+char *crypt(const char *key, const char *setting)
+{
+ my_u_int32_t count, salt, l, r0, r1, keybuf[2];
+ my_u_char_t *p, *q;
+ static char output[21];
+
+ des_init();
+
+ /*
+ * Copy the key, shifting each character up by one bit
+ * and padding with zeros.
+ */
+ q = (my_u_char_t *)keybuf;
+ while (q - (my_u_char_t *)keybuf - 8) {
+ *q++ = *key << 1;
+ if (*(q - 1))
+ key++;
+ }
+ if (des_setkey((char *)keybuf))
+ return(NULL);
+
+#if 0
+ if (*setting == _PASSWORD_EFMT1) {
+ int i;
+ /*
+ * "new"-style:
+ * setting - underscore, 4 bytes of count, 4 bytes of salt
+ * key - unlimited characters
+ */
+ for (i = 1, count = 0L; i < 5; i++)
+ count |= ascii_to_bin(setting[i]) << ((i - 1) * 6);
+
+ for (i = 5, salt = 0L; i < 9; i++)
+ salt |= ascii_to_bin(setting[i]) << ((i - 5) * 6);
+
+ while (*key) {
+ /*
+ * Encrypt the key with itself.
+ */
+ if (des_cipher((char *)keybuf, (char *)keybuf, 0L, 1))
+ return(NULL);
+ /*
+ * And XOR with the next 8 characters of the key.
+ */
+ q = (my_u_char_t *)keybuf;
+ while (q - (my_u_char_t *)keybuf - 8 && *key)
+ *q++ ^= *key++ << 1;
+
+ if (des_setkey((char *)keybuf))
+ return(NULL);
+ }
+ strncpy(output, setting, 9);
+
+ /*
+ * Double check that we weren't given a short setting.
+ * If we were, the above code will probably have created
+ * wierd values for count and salt, but we don't really care.
+ * Just make sure the output string doesn't have an extra
+ * NUL in it.
+ */
+ output[9] = '\0';
+ p = (my_u_char_t *)output + strlen(output);
+ } else
+#endif
+ {
+ /*
+ * "old"-style:
+ * setting - 2 bytes of salt
+ * key - up to 8 characters
+ */
+ count = 25;
+
+ salt = (ascii_to_bin(setting[1]) << 6)
+ | ascii_to_bin(setting[0]);
+
+ output[0] = setting[0];
+ /*
+ * If the encrypted password that the salt was extracted from
+ * is only 1 character long, the salt will be corrupted. We
+ * need to ensure that the output string doesn't have an extra
+ * NUL in it!
+ */
+ output[1] = setting[1] ? setting[1] : output[0];
+
+ p = (my_u_char_t *)output + 2;
+ }
+ setup_salt(salt);
+ /*
+ * Do it.
+ */
+ if (do_des(0L, 0L, &r0, &r1, (int)count))
+ return(NULL);
+ /*
+ * Now encode the result...
+ */
+ l = (r0 >> 8);
+ *p++ = ascii64[(l >> 18) & 0x3f];
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+
+ l = (r0 << 16) | ((r1 >> 16) & 0xffff);
+ *p++ = ascii64[(l >> 18) & 0x3f];
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+
+ l = r1 << 2;
+ *p++ = ascii64[(l >> 12) & 0x3f];
+ *p++ = ascii64[(l >> 6) & 0x3f];
+ *p++ = ascii64[l & 0x3f];
+ *p = 0;
+
+ return(output);
+}
diff --git a/com32/cmenu/libmenu/des.h b/com32/cmenu/libmenu/des.h
new file mode 100644
index 00000000..67fc6b70
--- /dev/null
+++ b/com32/cmenu/libmenu/des.h
@@ -0,0 +1,8 @@
+
+#ifndef _DES_H_
+#define _DES_H_
+
+// des crypt
+extern char *crypt (const char *key, const char *salt);
+
+#endif
diff --git a/com32/cmenu/libmenu/help.c b/com32/cmenu/libmenu/help.c
new file mode 100644
index 00000000..31944c79
--- /dev/null
+++ b/com32/cmenu/libmenu/help.c
@@ -0,0 +1,200 @@
+/* -*- 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include "help.h"
+#include <stdio.h>
+#include "string.h"
+#include "com32io.h"
+#include <syslinux/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,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("Filename not given",0x07,HELP_LEFT_MARGIN);
+ while (1) {
+ inputc(&scan);
+ if (scan == ESCAPE) break;
+ }
+ cls();
+ return;
+ }
+
+ 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.
+ 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
+
+ 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 runhelp(const char *filename)
+{
+ char dp;
+ char fullname[HELPDIRLEN+16];
+
+ dp = getdisppage();
+ if (dp != HELPPAGE) setdisppage(HELPPAGE);
+ cursoroff();
+ if (helpbasedir[0] != 0) {
+ 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)
+ strcpy(helpbasedir,helpdir);
+ else helpbasedir[0] = 0;
+}
+
+void close_help(void)
+{
+}
diff --git a/com32/cmenu/libmenu/help.h b/com32/cmenu/libmenu/help.h
new file mode 100644
index 00000000..06832d84
--- /dev/null
+++ b/com32/cmenu/libmenu/help.h
@@ -0,0 +1,49 @@
+/* -*- 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 __HELP_H_
+#define __HELP_H_
+
+#include "menu.h"
+#include "com32io.h"
+#include "tui.h"
+#include <string.h>
+
+// How many rows for the title
+#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);
+
+// 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
+void close_help(void);
+
+#endif
diff --git a/com32/cmenu/libmenu/menu.c b/com32/cmenu/libmenu/menu.c
new file mode 100644
index 00000000..56a7426c
--- /dev/null
+++ b/com32/cmenu/libmenu/menu.c
@@ -0,0 +1,1300 @@
+/* -*- 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include "menu.h"
+#include "com32io.h"
+#include <stdlib.h>
+
+// Local Variables
+static pt_menusystem ms; // Pointer to the menusystem
+char TITLESTR[] = "COMBOOT Menu System for SYSLINUX developed by Murali Krishnan Ganapathy";
+char TITLELONG[] = " TITLE too long ";
+char ITEMLONG[] = " ITEM too long ";
+char ACTIONLONG[] = " ACTION too long ";
+char STATUSLONG[] = " STATUS too long ";
+char EMPTYSTR[] = "";
+
+/* Forward declarations */
+int calc_visible(pt_menu menu,int first);
+int next_visible(pt_menu menu,int index);
+int prev_visible(pt_menu menu,int index);
+int next_visible_sep(pt_menu menu,int index);
+int prev_visible_sep(pt_menu menu,int index);
+int calc_first_early(pt_menu menu,int curr);
+int calc_first_late(pt_menu menu,int curr);
+int isvisible(pt_menu menu,int first, int curr);
+
+
+/* Basic Menu routines */
+
+// This is same as inputc except it honors the ontimeout handler
+// and calls it when needed. For the callee, there is no difference
+// as this will not return unless a key has been pressed.
+char getch(char *scan)
+{
+ unsigned long i;
+ TIMEOUTCODE c;
+ t_timeout_handler th;
+
+ // Wait until keypress if no handler specified
+ 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
+ }
+ }
+ if (!th) continue; // no handler dont call
+ c = th();
+ switch(c)
+ {
+ case CODE_ENTER: // Pretend user hit enter
+ *scan = ENTERA;
+ return '\015'; // \015 octal = 13
+ case CODE_ESCAPE: // Pretend user hit escape
+ *scan = ESCAPE;
+ return '\033'; // \033 octal = 27
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+/* Print a menu item */
+/* attr[0] is non-hilite attr, attr[1] is highlight attr */
+void printmenuitem(const char *str,uchar* attr)
+{
+ uchar page = getdisppage();
+ uchar row,col;
+ int hlite=NOHLITE; // Initially no highlighting
+
+ getpos(&row,&col,page);
+ while ( *str ) {
+ switch (*str)
+ {
+ case '\b':
+ --col;
+ break;
+ case '\n':
+ ++row;
+ break;
+ case '\r':
+ col=0;
+ break;
+ case BELL: // No Bell Char
+ break;
+ case ENABLEHLITE: // Switch on highlighting
+ hlite = HLITE;
+ break;
+ case DISABLEHLITE: // Turn off highlighting
+ hlite = NOHLITE;
+ break;
+ default:
+ putch(*str, attr[hlite], page);
+ ++col;
+ }
+ if (col > getnumcols())
+ {
+ ++row;
+ col=0;
+ }
+ if (row > getnumrows())
+ {
+ scrollup();
+ row= getnumrows();
+ }
+ gotoxy(row,col,page);
+ str++;
+ }
+}
+
+int find_shortcut(pt_menu menu,uchar shortcut, int index)
+// Find the next index with specified shortcut key
+{
+ int ans;
+ pt_menuitem mi;
+
+ // Garbage in garbage out
+ if ((index <0) || (index >= menu->numitems)) return index;
+ ans = index+1;
+ // Go till end of menu
+ while (ans < menu->numitems)
+ {
+ mi = menu->items[ans];
+ if ((mi->action == OPT_INVISIBLE) || (mi->action == OPT_SEP)
+ || (mi->shortcut != shortcut))
+ ans ++;
+ else return ans;
+ }
+ // Start at the beginning and try again
+ ans = 0;
+ while (ans < index)
+ {
+ mi = menu->items[ans];
+ if ((mi->action == OPT_INVISIBLE) || (mi->action == OPT_SEP)
+ || (mi->shortcut != shortcut))
+ ans ++;
+ else return ans;
+ }
+ return index; // Sorry not found
+}
+
+// print the menu starting from FIRST
+// will print a maximum of menu->menuheight items
+void printmenu(pt_menu menu, int curr, uchar top, uchar left, uchar first)
+{
+ int x,row; // x = index, row = position from top
+ int numitems,menuwidth;
+ char fchar[5],lchar[5]; // The first and last char in for each entry
+ const char *str; // and inbetween the item or a seperator is printed
+ uchar *attr; // attribute attr
+ char sep[MENULEN];// and inbetween the item or a seperator is printed
+ pt_menuitem ci;
+
+ numitems = calc_visible(menu,first);
+ if (numitems > menu->menuheight) numitems = menu->menuheight;
+
+ menuwidth = menu->menuwidth+3;
+ clearwindow(top,left-2, top+numitems+1, left+menuwidth+1,
+ ms->menupage, ms->fillchar, ms->shadowattr);
+ drawbox(top-1,left-3,top+numitems,left+menuwidth,
+ ms->menupage,ms->normalattr[NOHLITE],ms->menubt);
+ memset(sep,ms->box_horiz,menuwidth); // String containing the seperator string
+ sep[menuwidth-1] = 0;
+ // Menu title
+ x = (menuwidth - strlen(menu->title) - 1) >> 1;
+ gotoxy(top-1,left+x,ms->menupage);
+ printmenuitem(menu->title,ms->normalattr);
+ row = -1; // 1 less than inital value of x
+ for (x=first; x < menu->numitems; x++)
+ {
+ ci = menu->items[x];
+ if (ci->action == OPT_INVISIBLE) continue;
+ row++;
+ if (row >= numitems) break; // Already have enough number of items
+ // Setup the defaults now
+ lchar[0] = fchar[0] = ' ';
+ lchar[1] = fchar[1] = '\0'; // fchar and lchar are just spaces
+ str = ci->item; // Pointer to item string
+ attr = (x==curr ? ms->reverseattr : ms->normalattr); // Normal attributes
+ switch (ci->action) // set up attr,str,fchar,lchar for everything
+ {
+ case OPT_INACTIVE:
+ attr = (x==curr? ms->revinactattr : ms->inactattr);
+ break;
+ case OPT_SUBMENU:
+ lchar[0] = SUBMENUCHAR; lchar[1] = 0;
+ break;
+ case OPT_RADIOMENU:
+ lchar[0] = RADIOMENUCHAR; lchar[1] = 0;
+ break;
+ case OPT_CHECKBOX:
+ lchar[0] = (ci->itemdata.checked ? CHECKED : UNCHECKED);
+ lchar[1] = 0;
+ break;
+ case OPT_SEP:
+ fchar[0] = '\b'; fchar[1] = ms->box_ltrt; fchar[2] = ms->box_horiz; fchar[3] = ms->box_horiz; fchar[4] = 0;
+ lchar[0] = ms->box_horiz; lchar[1] = ms->box_rtlt; lchar[2] = 0;
+ str = sep;
+ break;
+ case OPT_EXITMENU:
+ fchar[0] = EXITMENUCHAR; fchar[1] = 0;
+ break;
+ default: // Just to keep the compiler happy
+ break;
+ }
+ gotoxy(top+row,left-2,ms->menupage);
+ cprint(ms->spacechar,attr[NOHLITE],menuwidth+2,ms->menupage); // Wipe area with spaces
+ gotoxy(top+row,left-2,ms->menupage);
+ csprint(fchar,attr[NOHLITE]); // Print first part
+ gotoxy(top+row,left,ms->menupage);
+ printmenuitem(str,attr); // Print main part
+ gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any
+ csprint(lchar,attr[NOHLITE]); // Print last part
+ }
+ // Check if we need to MOREABOVE and MOREBELOW to be added
+ // reuse x
+ row = 0;
+ x = next_visible_sep(menu,0); // First item
+ if (! isvisible(menu,first,x)) // There is more above
+ {
+ row = 1;
+ gotoxy(top,left+menuwidth,ms->menupage);
+ cprint(MOREABOVE,ms->normalattr[NOHLITE],1,ms->menupage);
+ }
+ x = prev_visible_sep(menu,menu->numitems); // last item
+ if (! isvisible(menu,first,x)) // There is more above
+ {
+ row = 1;
+ gotoxy(top+numitems-1,left+menuwidth,ms->menupage);
+ cprint(MOREBELOW,ms->normalattr[NOHLITE],1,ms->menupage);
+ }
+ // Add a scroll box
+ x = ((numitems-1)*curr)/(menu->numitems);
+ if ((x>0) && (row==1)) {
+ gotoxy(top+x,left+menuwidth,ms->menupage);
+ cprint(SCROLLBOX,ms->normalattr[NOHLITE],1,ms->menupage);
+ }
+ if (ms->handler) ms->handler(ms,menu->items[curr]);
+}
+
+// Difference between this and regular menu, is that only
+// OPT_INVISIBLE, OPT_SEP are honoured
+void printradiomenu(pt_menu menu, int curr, uchar top, uchar left, int first)
+{
+ int x,row; // x = index, row = position from top
+ int numitems,menuwidth;
+ char fchar[5],lchar[5]; // The first and last char in for each entry
+ const char *str; // and inbetween the item or a seperator is printed
+ uchar *attr; // all in the attribute attr
+ char sep[MENULEN];// and inbetween the item or a seperator is printed
+ pt_menuitem ci;
+
+ numitems = calc_visible(menu,first);
+ if (numitems > menu->menuheight) numitems = menu->menuheight;
+
+ menuwidth = menu->menuwidth+3;
+ clearwindow(top,left-2, top+numitems+1, left+menuwidth+1,
+ ms->menupage, ms->fillchar, ms->shadowattr);
+ drawbox(top-1,left-3,top+numitems,left+menuwidth,
+ ms->menupage,ms->normalattr[NOHLITE],ms->menubt);
+ memset(sep,ms->box_horiz,menuwidth); // String containing the seperator string
+ sep[menuwidth-1] = 0;
+ // Menu title
+ x = (menuwidth - strlen(menu->title) - 1) >> 1;
+ gotoxy(top-1,left+x,ms->menupage);
+ printmenuitem(menu->title,ms->normalattr);
+ row = -1; // 1 less than inital value of x
+ for (x=first; x < menu->numitems; x++)
+ {
+ ci = menu->items[x];
+ if (ci->action == OPT_INVISIBLE) continue;
+ row++;
+ if (row > numitems) break;
+ // Setup the defaults now
+ fchar[0] = RADIOUNSEL; fchar[1]='\0'; // Unselected ( )
+ lchar[0] = '\0'; // Nothing special after
+ str = ci->item; // Pointer to item string
+ attr = ms->normalattr; // Always same attribute
+ fchar[0] = (x==curr ? RADIOSEL : RADIOUNSEL);
+ switch (ci->action) // set up attr,str,fchar,lchar for everything
+ {
+ case OPT_INACTIVE:
+ attr = ms->inactattr;
+ break;
+ case OPT_SEP:
+ fchar[0] = '\b'; fchar[1] = ms->box_ltrt; fchar[2] = ms->box_horiz; fchar[3] = ms->box_horiz; fchar[4] = 0;
+ lchar[0] = ms->box_horiz; lchar[1] = ms->box_rtlt; lchar[3] = 0;
+ str = sep;
+ break;
+ default: // To keep the compiler happy
+ break;
+ }
+ gotoxy(top+row,left-2,ms->menupage);
+ cprint(ms->spacechar,attr[NOHLITE],menuwidth+2,ms->menupage); // Wipe area with spaces
+ gotoxy(top+row,left-2,ms->menupage);
+ csprint(fchar,attr[NOHLITE]); // Print first part
+ gotoxy(top+row,left,ms->menupage);
+ printmenuitem(str,attr); // Print main part
+ gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any
+ csprint(lchar,attr[NOHLITE]); // Print last part
+ }
+ // Check if we need to MOREABOVE and MOREBELOW to be added
+ // reuse x
+ row = 0;
+ x = next_visible_sep(menu,0); // First item
+ if (! isvisible(menu,first,x)) // There is more above
+ {
+ row = 1;
+ gotoxy(top,left+menuwidth,ms->menupage);
+ cprint(MOREABOVE,ms->normalattr[NOHLITE],1,ms->menupage);
+ }
+ x = prev_visible_sep(menu,menu->numitems); // last item
+ if (! isvisible(menu,first,x)) // There is more above
+ {
+ row = 1;
+ gotoxy(top+numitems-1,left+menuwidth,ms->menupage);
+ cprint(MOREBELOW,ms->normalattr[NOHLITE],1,ms->menupage);
+ }
+ // Add a scroll box
+ x = ((numitems-1)*curr)/(menu->numitems);
+ if ((x > 0) && (row == 1))
+ {
+ gotoxy(top+x,left+menuwidth,ms->menupage);
+ cprint(SCROLLBOX,ms->normalattr[NOHLITE],1,ms->menupage);
+ }
+ if (ms->handler) ms->handler(ms,menu->items[curr]);
+}
+
+void cleanupmenu(pt_menu menu, uchar top,uchar left,int numitems)
+{
+ if (numitems > menu->menuheight) numitems = menu->menuheight;
+ clearwindow(top,left-2, top+numitems+1, left+menu->menuwidth+4,
+ ms->menupage, ms->fillchar, ms->fillattr); // Clear the shadow
+ clearwindow(top-1, left-3, top+numitems, left+menu->menuwidth+3,
+ ms->menupage, ms->fillchar, ms->fillattr); // main window
+}
+
+/* Handle a radio menu */
+pt_menuitem getradiooption(pt_menu menu, uchar top, uchar left, uchar startopt)
+ // Return item chosen or NULL if ESC was hit.
+{
+ int curr,i,first,tmp;
+ uchar asc,scan;
+ uchar numitems;
+ pt_menuitem ci; // Current item
+
+ numitems = calc_visible(menu,0);
+ // Setup status line
+ gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage);
+
+ // Initialise current menu item
+ curr = next_visible(menu,startopt);
+
+ gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,1);
+ gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
+ printmenuitem(menu->items[curr]->status,ms->statusattr);
+ first = calc_first_early(menu,curr);
+ while (1) // Forever
+ {
+ printradiomenu(menu,curr,top,left,first);
+ ci = menu->items[curr];
+
+ asc = getch(&scan);
+ switch (scan)
+ {
+ case HOMEKEY:
+ curr = next_visible(menu,0);
+ first = calc_first_early(menu,curr);
+ break;
+ case ENDKEY:
+ curr = prev_visible(menu,numitems-1);
+ first = calc_first_late(menu,curr);
+ break;
+ case PAGEDN:
+ for (i=0; i < 5; i++) curr = next_visible(menu,curr+1);
+ first = calc_first_late(menu,curr);
+ break;
+ case PAGEUP:
+ for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1);
+ first = calc_first_early(menu,curr);
+ break;
+ case UPARROW:
+ curr = prev_visible(menu,curr-1);
+ if (curr < first) first = calc_first_early(menu,curr);
+ break;
+ case DNARROW:
+ curr = next_visible(menu,curr+1);
+ if (! isvisible(menu,first,curr))
+ first = calc_first_late(menu,curr);
+ break;
+ case LTARROW:
+ case ESCAPE:
+ return NULL;
+ break;
+ case RTARROW:
+ case ENTERA:
+ case ENTERB:
+ if (ci->action == OPT_INACTIVE) break;
+ if (ci->action == OPT_SEP) break;
+ return ci;
+ break;
+ default:
+ // Check if this is a shortcut key
+ if (((asc >= 'A') && (asc <= 'Z')) ||
+ ((asc >= 'a') && (asc <= 'z')) ||
+ ((asc >= '0') && (asc <= '9')))
+ {
+ tmp = find_shortcut(menu,asc,curr);
+ if ((tmp > curr) && (! isvisible(menu,first,tmp)))
+ first = calc_first_late(menu,tmp);
+ if (tmp < curr)
+ first = calc_first_early(menu,tmp);
+ curr = tmp;
+ }
+ else {
+ if (ms->keys_handler) // Call extra keys handler
+ ms->keys_handler(ms,menu->items[curr],(scan << 8) | asc);
+ }
+ break;
+ }
+ // Update status line
+ gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage);
+ printmenuitem(menu->items[curr]->status,ms->statusattr);
+ }
+ return NULL; // Should never come here
+}
+
+/* Handle one menu */
+pt_menuitem getmenuoption(pt_menu menu, uchar top, uchar left, uchar startopt)
+ // Return item chosen or NULL if ESC was hit.
+{
+ int curr,i,first,tmp;
+ uchar asc,scan;
+ uchar numitems;
+ pt_menuitem ci; // Current item
+ t_handler_return hr; // Return value of handler
+
+ numitems = calc_visible(menu,0);
+ // Setup status line
+ gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage);
+
+ // Initialise current menu item
+ curr = next_visible(menu,startopt);
+
+ gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,1);
+ gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
+ printmenuitem(menu->items[curr]->status,ms->statusattr);
+ first = calc_first_early(menu,curr);
+ while (1) // Forever
+ {
+ printmenu(menu,curr,top,left,first);
+ ci = menu->items[curr];
+ asc = getch(&scan);
+ switch (scan)
+ {
+ case HOMEKEY:
+ curr = next_visible(menu,0);
+ first = calc_first_early(menu,curr);
+ break;
+ case ENDKEY:
+ curr = prev_visible(menu,numitems-1);
+ first = calc_first_late(menu,curr);
+ break;
+ case PAGEDN:
+ for (i=0; i < 5; i++) curr = next_visible(menu,curr+1);
+ first = calc_first_late(menu,curr);
+ break;
+ case PAGEUP:
+ for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1);
+ first = calc_first_early(menu,curr);
+ break;
+ case UPARROW:
+ curr = prev_visible(menu,curr-1);
+ if (curr < first) first = calc_first_early(menu,curr);
+ break;
+ case DNARROW:
+ curr = next_visible(menu,curr+1);
+ if (! isvisible(menu,first,curr))
+ first = calc_first_late(menu,curr);
+ break;
+ case LTARROW:
+ case ESCAPE:
+ return NULL;
+ break;
+ case RTARROW:
+ case ENTERA:
+ case ENTERB:
+ if (ci->action == OPT_INACTIVE) break;
+ if (ci->action == OPT_CHECKBOX) break;
+ if (ci->action == OPT_SEP) break;
+ if (ci->action == OPT_EXITMENU) return NULL; // As if we hit Esc
+ // If we are going into a radio menu, dont call handler, return ci
+ if (ci->action == OPT_RADIOMENU) return ci;
+ if (ci->handler != NULL) // Do we have a handler
+ {
+ hr = ci->handler(ms,ci);
+ if (hr.refresh) // Do we need to refresh
+ {
+ // Cleanup menu using old number of items
+ cleanupmenu(menu,top,left,numitems);
+ // Recalculate the number of items
+ numitems = calc_visible(menu,0);
+ // Reprint the menu
+ printmenu(menu,curr,top,left,first);
+ }
+ if (hr.valid) return ci;
+ }
+ else return ci;
+ break;
+ case SPACEKEY:
+ if (ci->action != OPT_CHECKBOX) break;
+ ci->itemdata.checked = !ci->itemdata.checked;
+ if (ci->handler != NULL) // Do we have a handler
+ {
+ hr = ci->handler(ms,ci);
+ if (hr.refresh) // Do we need to refresh
+ {
+ // Cleanup menu using old number of items
+ cleanupmenu(menu,top,left,numitems);
+ // Recalculate the number of items
+ numitems = calc_visible(menu,0);
+ // Reprint the menu
+ printmenu(menu,curr,top,left,first);
+ }
+ }
+ break;
+ default:
+ // Check if this is a shortcut key
+ if (((asc >= 'A') && (asc <= 'Z')) ||
+ ((asc >= 'a') && (asc <= 'z')) ||
+ ((asc >= '0') && (asc <= '9')))
+ {
+ tmp = find_shortcut(menu,asc,curr);
+ if ((tmp > curr) && (! isvisible(menu,first,tmp)))
+ first = calc_first_late(menu,tmp);
+ if (tmp < curr)
+ first = calc_first_early(menu,tmp);
+ curr = tmp;
+ }
+ else {
+ if (ms->keys_handler) // Call extra keys handler
+ ms->keys_handler(ms,menu->items[curr],(scan << 8) | asc);
+ }
+ break;
+ }
+ // Update status line
+ gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
+ cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage);
+ printmenuitem(menu->items[curr]->status,ms->statusattr);
+ }
+ return NULL; // Should never come here
+}
+
+/* Handle the entire system of menu's. */
+pt_menuitem runmenusystem(uchar top, uchar left, pt_menu cmenu, uchar startopt, uchar menutype)
+ /*
+ * cmenu
+ * Which menu should be currently displayed
+ * top,left
+ * What is the position of the top,left corner of the menu
+ * startopt
+ * which menu item do I start with
+ * menutype
+ * NORMALMENU or RADIOMENU
+ *
+ * Return Value:
+ * Returns a pointer to the final item chosen, or NULL if nothing chosen.
+ */
+{
+ pt_menuitem opt,choice;
+ uchar startat,mt;
+ uchar row,col;
+
+ if (cmenu == NULL) return NULL;
+ startover:
+ // Set the menu height
+ cmenu->menuheight = ms->maxrow - top-3;
+ if (cmenu->menuheight > ms->maxmenuheight)
+ cmenu->menuheight = ms->maxmenuheight;
+ if (menutype == NORMALMENU)
+ opt = getmenuoption(cmenu,top,left,startopt);
+ else // menutype == RADIOMENU
+ opt = getradiooption(cmenu,top,left,startopt);
+
+ if (opt == NULL)
+ {
+ // User hit Esc
+ cleanupmenu(cmenu,top,left,calc_visible(cmenu,0));
+ return NULL;
+ }
+ // Are we done with the menu system?
+ if ((opt->action != OPT_SUBMENU) && (opt->action != OPT_RADIOMENU))
+ {
+ cleanupmenu(cmenu,top,left,calc_visible(cmenu,0));
+ return opt; // parent cleanup other menus
+ }
+ // Either radiomenu or submenu
+ // Do we have a valid menu number? The next hack uses the fact that
+ // itemdata.submenunum = itemdata.radiomenunum (since enum data type)
+ if (opt->itemdata.submenunum >= ms->nummenus) // This is Bad....
+ {
+ gotoxy(12,12,ms->menupage); // Middle of screen
+ csprint("ERROR: Invalid submenu requested.",0x07);
+ cleanupmenu(cmenu,top,left,calc_visible(cmenu,0));
+ return NULL; // Pretend user hit esc
+ }
+ // Call recursively for submenu
+ // Position the submenu below the current item,
+ // covering half the current window (horizontally)
+ row = ms->menus[(unsigned int)opt->itemdata.submenunum]->row;
+ col = ms->menus[(unsigned int)opt->itemdata.submenunum]->col;
+ if (row == 0xFF) row = top+opt->index+2;
+ if (col == 0xFF) col = left+3+(cmenu->menuwidth >> 1);
+ mt = (opt->action == OPT_SUBMENU ? NORMALMENU : RADIOMENU );
+ startat = 0;
+ if ((opt->action == OPT_RADIOMENU) && (opt->data != NULL))
+ startat = ((t_menuitem *)opt->data)->index;
+
+ choice = runmenusystem(row, col,
+ ms->menus[(unsigned int)opt->itemdata.submenunum],
+ startat, mt );
+ if (opt->action == OPT_RADIOMENU)
+ {
+ if (choice != NULL) opt->data = (void *)choice; // store choice in data field
+ if (opt->handler != NULL) opt->handler(ms,opt);
+ choice = NULL; // Pretend user hit esc
+ }
+ if (choice==NULL) // User hit Esc in submenu
+ {
+ // Startover
+ startopt = opt->index;
+ goto startover;
+ }
+ else
+ {
+ cleanupmenu(cmenu,top,left,calc_visible(cmenu,0));
+ return choice;
+ }
+}
+
+// Finds the indexof the menu with given name
+uchar find_menu_num(const char *name)
+{
+ int i;
+ pt_menu m;
+
+ if (name == NULL) return (uchar)(-1);
+ for (i=0; i < ms->nummenus; i++)
+ {
+ m = ms->menus[i];
+ if ((m->name) && (strcmp(m->name,name)==0)) return i;
+ }
+ return (uchar)(-1);
+}
+
+// Run through all items and if they are submenus
+// with a non-trivial "action" and trivial submenunum
+// replace submenunum with the menu with name "action"
+void fix_submenus()
+{
+ int i,j;
+ pt_menu m;
+ pt_menuitem mi;
+
+ i = 0;
+ for (i=0; i < ms->nummenus; i++)
+ {
+ m = ms->menus[i];
+ for (j=0; j < m->numitems; j++)
+ {
+ mi = m->items[j];
+ // if item is a submenu and has non-empty non-trivial data string
+ if (mi->data && strlen(mi->data) > 0 &&
+ ((mi->action == OPT_SUBMENU) || (mi->action == OPT_RADIOMENU)) ) {
+ mi->itemdata.submenunum = find_menu_num (mi->data);
+ }
+ }
+ }
+}
+
+/* User Callable functions */
+
+pt_menuitem showmenus(uchar startmenu)
+{
+ pt_menuitem rv;
+ uchar oldpage,tpos;
+
+ fix_submenus(); // Fix submenu numbers incase nick names were used
+
+ // Setup screen for menusystem
+ oldpage = getdisppage();
+ setdisppage(ms->menupage);
+ cls();
+ clearwindow(ms->minrow, ms->mincol, ms->maxrow, ms->maxcol,
+ ms->menupage, ms->fillchar, ms->fillattr);
+ tpos = (ms->numcols - strlen(ms->title) - 1) >> 1; // center it on line
+ gotoxy(ms->minrow,ms->mincol,ms->menupage);
+ cprint(ms->tfillchar,ms->titleattr,ms->numcols,ms->menupage);
+ gotoxy(ms->minrow,ms->mincol+tpos,ms->menupage);
+ csprint(ms->title,ms->titleattr);
+
+ cursoroff(); // Doesn't seem to work?
+
+
+ // Go, main menu cannot be a radio menu
+ rv = runmenusystem(ms->minrow+MENUROW, ms->mincol+MENUCOL,
+ ms->menus[(unsigned int)startmenu], 0, NORMALMENU);
+
+ // Hide the garbage we left on the screen
+ cursoron();
+ if (oldpage == ms->menupage) cls(); else setdisppage(oldpage);
+
+ // Return user choice
+ return rv;
+}
+
+pt_menusystem init_menusystem(const char *title)
+{
+ int i;
+
+ ms = NULL;
+ ms = (pt_menusystem) malloc(sizeof(t_menusystem));
+ if (ms == NULL) return NULL;
+ ms->nummenus = 0;
+ // Initialise all menu pointers
+ for (i=0; i < MAXMENUS; i++) ms->menus[i] = NULL;
+
+ ms->title = (char *)malloc(TITLELEN+1);
+ if (title == NULL)
+ strcpy(ms->title,TITLESTR); // Copy string
+ else strcpy(ms->title,title);
+
+ // Timeout settings
+ ms->tm_stepsize = TIMEOUTSTEPSIZE;
+ ms->tm_numsteps = TIMEOUTNUMSTEPS;
+
+ ms->normalattr[NOHLITE] = NORMALATTR;
+ ms->normalattr[HLITE] = NORMALHLITE;
+
+ ms->reverseattr[NOHLITE] = REVERSEATTR;
+ ms->reverseattr[HLITE] = REVERSEHLITE;
+
+ ms->inactattr[NOHLITE] = INACTATTR;
+ ms->inactattr[HLITE] = INACTHLITE;
+
+ ms->revinactattr[NOHLITE] = REVINACTATTR;
+ ms->revinactattr[HLITE] = REVINACTHLITE;
+
+ ms->statusattr[NOHLITE] = STATUSATTR;
+ ms->statusattr[HLITE] = STATUSHLITE;
+
+ ms->statline = STATLINE;
+ ms->tfillchar= TFILLCHAR;
+ ms->titleattr= TITLEATTR;
+
+ ms->fillchar = FILLCHAR;
+ ms->fillattr = FILLATTR;
+ ms->spacechar= SPACECHAR;
+ ms->shadowattr = SHADOWATTR;
+
+ ms->menupage = MENUPAGE; // Usually no need to change this at all
+
+ // Initialise all handlers
+ 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;
+ ACTION_VALID.refresh=0;
+ ACTION_INVALID.valid = 0;
+ ACTION_INVALID.refresh = 0;
+
+ // Figure out the size of the screen we are in now.
+ // By default we use the whole screen for our menu
+ ms->minrow = ms->mincol = 0;
+ ms->numcols = getnumcols();
+ ms->numrows = getnumrows();
+ ms->maxcol = ms->numcols - 1;
+ ms->maxrow = ms->numrows - 1;
+
+ // How many entries per menu can we display at a time
+ ms->maxmenuheight = ms->maxrow - ms->minrow - 3;
+ if (ms->maxmenuheight > MAXMENUHEIGHT)
+ ms->maxmenuheight= MAXMENUHEIGHT;
+
+ // Set up the look of the box
+ set_box_type(MENUBOXTYPE);
+ return ms;
+}
+
+void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected)
+{
+ if (normal != 0xFF) ms->normalattr[0] = normal;
+ if (selected != 0xFF) ms->reverseattr[0] = selected;
+ if (inactivenormal != 0xFF) ms->inactattr[0] = inactivenormal;
+ if (inactiveselected != 0xFF) ms->revinactattr[0] = inactiveselected;
+}
+
+void set_normal_hlite(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected)
+{
+ if (normal != 0xFF) ms->normalattr[1] = normal;
+ if (selected != 0xFF) ms->reverseattr[1] = selected;
+ if (inactivenormal != 0xFF) ms->inactattr[1] = inactivenormal;
+ if (inactiveselected != 0xFF) ms->revinactattr[1] = inactiveselected;
+}
+
+void set_status_info(uchar statusattr, uchar statushlite, uchar statline)
+{
+ if (statusattr != 0xFF) ms->statusattr[NOHLITE] = statusattr;
+ if (statushlite!= 0xFF) ms->statusattr[HLITE] = statushlite;
+ // statline is relative to minrow
+ if (statline >= ms->numrows) statline = ms->numrows - 1;
+ ms->statline = statline; // relative to ms->minrow, 0 based
+}
+
+void set_title_info(uchar tfillchar, uchar titleattr)
+{
+ if (tfillchar != 0xFF) ms->tfillchar = tfillchar;
+ if (titleattr != 0xFF) ms->titleattr = titleattr;
+}
+
+void set_misc_info(uchar fillchar, uchar fillattr,uchar spacechar, uchar shadowattr)
+{
+ if (fillchar != 0xFF) ms->fillchar = fillchar;
+ if (fillattr != 0xFF) ms->fillattr = fillattr;
+ if (spacechar != 0xFF) ms->spacechar = spacechar;
+ if (shadowattr!= 0xFF) ms->shadowattr= shadowattr;
+}
+
+void set_box_type(boxtype bt)
+{
+ uchar *bxc;
+ ms->menubt = bt;
+ bxc = getboxchars(bt);
+ ms->box_horiz = bxc[BOX_HORIZ]; // The char used to draw top line
+ ms->box_ltrt = bxc[BOX_LTRT];
+ ms->box_rtlt = bxc[BOX_RTLT];
+}
+
+void set_menu_options(uchar maxmenuheight)
+{
+ if (maxmenuheight != 0xFF) ms->maxmenuheight = maxmenuheight;
+}
+
+// Set the window which menusystem should use
+void set_window_size(uchar top, uchar left, uchar bot, uchar right)
+{
+
+ uchar nr,nc;
+ if ((top > bot) || (left > right)) return; // Sorry no change will happen here
+ nr = getnumrows();
+ nc = getnumcols();
+ if (bot >= nr) bot = nr-1;
+ if (right >= nc) right = nc-1;
+ ms->minrow = top;
+ ms->mincol = left;
+ ms->maxrow = bot;
+ ms->maxcol = right;
+ ms->numcols = right - left + 1;
+ ms->numrows = bot - top + 1;
+ if (ms->statline >= ms->numrows) ms->statline = ms->numrows - 1; // Clip statline if need be
+}
+
+void reg_handler( t_handler htype, void * handler)
+{
+ // If bad value set to default screen handler
+ switch(htype) {
+ case HDLR_KEYS:
+ ms->keys_handler = (t_keys_handler) handler;
+ break;
+ default:
+ ms->handler = (t_menusystem_handler) handler;
+ break;
+ }
+}
+
+void unreg_handler(t_handler htype)
+{
+ switch(htype) {
+ case HDLR_KEYS:
+ ms->keys_handler = NULL;
+ break;
+ default:
+ ms->handler = NULL;
+ break;
+ }
+}
+
+void reg_ontimeout(t_timeout_handler handler, unsigned int numsteps, unsigned int stepsize)
+{
+ ms->ontimeout = handler;
+ if (numsteps != 0) ms->tm_numsteps = numsteps;
+ if (stepsize != 0) ms->tm_stepsize = stepsize;
+}
+
+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;
+ if (index < 0) ans = 0 ;
+ else if (index >= menu->numitems) ans = menu->numitems-1;
+ else ans = index;
+ while ((ans < menu->numitems-1) &&
+ ((menu->items[ans]->action == OPT_INVISIBLE) ||
+ (menu->items[ans]->action == OPT_SEP)))
+ ans++;
+ return ans;
+}
+
+int prev_visible(pt_menu menu, int index) // Return index of prev visible
+{
+ int ans;
+ if (index < 0) ans = 0;
+ else if (index >= menu->numitems) ans = menu->numitems-1;
+ else ans = index;
+ while ((ans > 0) &&
+ ((menu->items[ans]->action == OPT_INVISIBLE) ||
+ (menu->items[ans]->action == OPT_SEP)))
+ ans--;
+ return ans;
+}
+
+int next_visible_sep(pt_menu menu, int index)
+{
+ int ans;
+ if (index < 0) ans = 0 ;
+ else if (index >= menu->numitems) ans = menu->numitems-1;
+ else ans = index;
+ while ((ans < menu->numitems-1) &&
+ (menu->items[ans]->action == OPT_INVISIBLE))
+ ans++;
+ return ans;
+}
+
+int prev_visible_sep(pt_menu menu, int index) // Return index of prev visible
+{
+ int ans;
+ if (index < 0) ans = 0;
+ else if (index >= menu->numitems) ans = menu->numitems-1;
+ else ans = index;
+ while ((ans > 0) &&
+ (menu->items[ans]->action == OPT_INVISIBLE))
+ ans--;
+ return ans;
+}
+
+int calc_visible(pt_menu menu,int first)
+{
+ int ans,i;
+
+ if (menu == NULL) return 0;
+ ans = 0;
+ for (i=first; i < menu->numitems; i++)
+ if (menu->items[i]->action != OPT_INVISIBLE) ans++;
+ return ans;
+}
+
+// is curr visible if first entry is first?
+int isvisible(pt_menu menu,int first, int curr)
+{
+ if (curr < first) return 0;
+ return (calc_visible(menu,first)-calc_visible(menu,curr) < menu->menuheight);
+}
+
+// Calculate the first entry to be displayed
+// so that curr is visible and make curr as late as possible
+int calc_first_late(pt_menu menu,int curr)
+{
+ int ans,i,nv;
+
+ nv = calc_visible(menu,0);
+ if (nv <= menu->menuheight) return 0;
+ // Start with curr and go back menu->menuheight times
+ ans = curr+1;
+ for (i=0; i < menu->menuheight; i++)
+ ans = prev_visible_sep(menu,ans-1);
+ return ans;
+}
+
+// Calculate the first entry to be displayed
+// so that curr is visible and make curr as early as possible
+int calc_first_early(pt_menu menu,int curr)
+{
+ int ans,i,nv;
+
+ nv = calc_visible(menu,0);
+ if (nv <= menu->menuheight) return 0;
+ // Start with curr and go back till >= menu->menuheight
+ // items are visible
+ nv = calc_visible(menu,curr); // Already nv of them are visible
+ ans = curr;
+ for (i=0; i < menu->menuheight - nv; i++)
+ ans = prev_visible_sep(menu,ans-1);
+ return ans;
+}
+
+// Create a new menu and return its position
+uchar add_menu(const char *title, int maxmenusize)
+{
+ int num,i;
+ pt_menu m;
+
+ num = ms->nummenus;
+ if (num >= MAXMENUS) return -1;
+ m = NULL;
+ m = (pt_menu) malloc(sizeof(t_menu));
+ if (m == NULL) return -1;
+ ms->menus[num] = m;
+ m->numitems = 0;
+ m->name = NULL;
+ m->row = 0xFF;
+ m->col = 0xFF;
+ if (maxmenusize < 1)
+ m->maxmenusize = MAXMENUSIZE;
+ else m->maxmenusize = maxmenusize;
+ m->items = (pt_menuitem *) malloc(sizeof(pt_menuitem)*(m->maxmenusize));
+ for (i=0; i < m->maxmenusize; i++) m->items[i] = NULL;
+
+ m->title = (char *)malloc(MENULEN+1);
+ if (title)
+ {
+ if (strlen(title) > MENULEN - 2)
+ strcpy(m->title,TITLELONG);
+ else strcpy(m->title,title);
+ }
+ else strcpy(m->title,EMPTYSTR);
+ m ->menuwidth = strlen(m->title);
+ ms->nummenus ++;
+ return ms->nummenus - 1;
+}
+
+void set_menu_name(const char *name) // Set the "name" of this menu
+{
+ pt_menu m;
+
+ m = ms->menus[ms->nummenus-1];
+ if (m->name) // Free up previous name
+ {
+ free(m->name);
+ m -> name = NULL;
+ }
+
+ if (name)
+ {
+ m->name = (char *)malloc(strlen(name)+1);
+ strcpy(m->name,name);
+ }
+}
+
+// Create a new named menu and return its position
+uchar add_named_menu(const char * name, const char *title, int maxmenusize)
+{
+ add_menu(title,maxmenusize);
+ set_menu_name(name);
+ return ms->nummenus - 1;
+}
+
+void set_menu_pos(uchar row,uchar col) // Set the position of this menu.
+{
+ pt_menu m;
+
+ m = ms->menus[ms->nummenus-1];
+ m->row = row;
+ m->col = col;
+}
+
+pt_menuitem add_sep() // Add a separator to current menu
+{
+ pt_menuitem mi;
+ pt_menu m;
+
+ m = (ms->menus[ms->nummenus-1]);
+ mi = NULL;
+ mi = (pt_menuitem) malloc(sizeof(t_menuitem));
+ if (mi == NULL) return NULL;
+ m->items[(unsigned int)m->numitems] = mi;
+ mi->handler = NULL; // No handler
+ mi->item = mi->status = mi->data = NULL;
+ mi->action = OPT_SEP;
+ mi->index = m->numitems++;
+ mi->parindex = ms->nummenus-1;
+ mi->shortcut = 0;
+ mi->helpid=0;
+ return mi;
+}
+
+// Add item to the "current" menu
+pt_menuitem add_item(const char *item, const char *status, t_action action,
+ const char *data, uchar itemdata)
+{
+ pt_menuitem mi;
+ pt_menu m;
+ const char *str;
+ uchar inhlite=0; // Are we inside hlite area
+
+ m = (ms->menus[ms->nummenus-1]);
+ mi = NULL;
+ mi = (pt_menuitem) malloc(sizeof(t_menuitem));
+ if (mi == NULL) return NULL;
+ m->items[(unsigned int) m->numitems] = mi;
+ mi->handler = NULL; // No handler
+
+ // Allocate space to store stuff
+ mi->item = (char *)malloc(MENULEN+1);
+ mi->status = (char *)malloc(STATLEN+1);
+ mi->data = (char *)malloc(ACTIONLEN+1);
+
+ if (item) {
+ if (strlen(item) > MENULEN) {
+ strcpy(mi->item,ITEMLONG);
+ } else {
+ strcpy(mi->item,item);
+ }
+ if (strlen(mi->item) > m->menuwidth) m->menuwidth = strlen(mi->item);
+ } else strcpy(mi->item,EMPTYSTR);
+
+ if (status) {
+ if (strlen(status) > STATLEN) {
+ strcpy(mi->status,STATUSLONG);
+ } else {
+ strcpy(mi->status,status);
+ }
+ } else strcpy(mi->status,EMPTYSTR);
+
+ mi->action=action;
+ str = mi->item;
+ mi->shortcut = 0;
+ mi->helpid = 0xFFFF;
+ inhlite = 0; // We have not yet seen an ENABLEHLITE char
+ // Find the first char in [A-Za-z0-9] after ENABLEHLITE and not arg to control char
+ while (*str)
+ {
+ if (*str == ENABLEHLITE)
+ {
+ inhlite=1;
+ }
+ if (*str == DISABLEHLITE)
+ {
+ inhlite = 0;
+ }
+ if ( (inhlite == 1) &&
+ (((*str >= 'A') && (*str <= 'Z')) ||
+ ((*str >= 'a') && (*str <= 'z')) ||
+ ((*str >= '0') && (*str <= '9'))))
+ {
+ mi->shortcut=*str;
+ break;
+ }
+ ++str;
+ }
+ if ((mi->shortcut >= 'A') && (mi->shortcut <= 'Z')) // Make lower case
+ mi->shortcut = mi->shortcut -'A'+'a';
+
+ if (data) {
+ if (strlen(data) > ACTIONLEN) {
+ strcpy(mi->data,ACTIONLONG);
+ } else {
+ strcpy(mi->data,data);
+ }
+ } else strcpy(mi->data,EMPTYSTR);
+
+ switch (action)
+ {
+ case OPT_SUBMENU:
+ mi->itemdata.submenunum = itemdata;
+ break;
+ case OPT_CHECKBOX:
+ mi->itemdata.checked = itemdata;
+ break;
+ case OPT_RADIOMENU:
+ mi->itemdata.radiomenunum = itemdata;
+ if (mi->data) free(mi->data);
+ mi->data = NULL; // No selection made
+ break;
+ default: // to keep the compiler happy
+ break;
+ }
+ mi->index = m->numitems++;
+ mi->parindex = ms->nummenus-1;
+ return mi;
+}
+
+// Set the shortcut key for the current item
+void set_item_options(uchar shortcut,int helpid)
+{
+ pt_menuitem mi;
+ pt_menu m;
+
+ m = (ms->menus[ms->nummenus-1]);
+ if (m->numitems <= 0) return;
+ mi = m->items[(unsigned int) m->numitems-1];
+
+ if (shortcut != 0xFF) mi->shortcut = shortcut;
+ if (helpid != 0xFFFF) mi->helpid = helpid;
+}
+
+// Free internal datasutructures
+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/com32/cmenu/libmenu/menu.h b/com32/cmenu/libmenu/menu.h
new file mode 100644
index 00000000..d8db6c25
--- /dev/null
+++ b/com32/cmenu/libmenu/menu.h
@@ -0,0 +1,291 @@
+/* -*- 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/* This program can be compiled for DOS with the OpenWatcom compiler
+ * (http://www.openwatcom.org/):
+ *
+ * wcl -3 -osx -mt <filename>.c
+ */
+
+#ifndef __MENU_H__
+#define __MENU_H__
+
+#include "com32io.h"
+#include "tui.h"
+#include "syslnx.h"
+#include "scancodes.h"
+#include <string.h>
+
+// TIMEOUT PARAMETERS
+/* If no key is pressed within TIMEOUTNUMSTEPS * TIMEOUTSTEPSIZE milliseconds
+ and if a timeout handler is registered, then that will be called.
+ The handler should either either take control from there on, or return without
+ producing any change in the current video settings.
+
+ For e.g. the handler could
+ * Could just quit the menu program
+ * beep and return.
+
+ TIMEOUTSTEPSIZE is the interval for which the program sleeps without checking for
+ any keystroke. So increasing this will make the response of the system slow.
+ Decreasing this will make a lot of interrupt calls using up your CPU. Default
+ value of TIMEOUTSTEPSIZE of 0.1 seconds should be right in most cases.
+
+ TIMEOUTNUMSTEPS of 3000 corresponds to a wait time of 300 seconds or 5 minutes
+*/
+
+#define TIMEOUTSTEPSIZE 10
+#define TIMEOUTNUMSTEPS 30000L
+
+// Attributes
+#define NORMALATTR 0x17
+#define NORMALHLITE 0x1F // Normal Highlight attribute
+#define REVERSEATTR 0x70
+#define REVERSEHLITE 0x78 // Reverse Hightlight attribute
+#define INACTATTR 0x18
+#define INACTHLITE 0x10 // Inactive Highlight attribute
+#define REVINACTATTR 0x78
+#define REVINACTHLITE 0x70 // Reverse Inactive Highlight attr
+
+#define STATUSATTR 0x74
+#define STATUSHLITE 0x7B // Status highlight
+
+#define FILLCHAR 177
+#define FILLATTR 0x01
+#define SHADOWATTR 0x00
+#define SPACECHAR ' '
+
+#define TFILLCHAR ' '
+#define TITLEATTR 0x70
+
+#define ENABLEHLITE '<' // Char which turns on highlight
+#define DISABLEHLITE '>' // Char which turns off highlight
+#define NOHLITE 0 // The offset into attrib array for non-hilite
+#define HLITE 1 // The offset for Hlite attrib
+
+#define MOREABOVE 24 // char to print when more menu items available above
+#define MOREBELOW 25 // more items available below
+#define SCROLLBOX 176 // Filled char to display
+
+// Attributes of the menu system
+#define MAXMENUS 100 // Maximum number of menu's allowed
+#define MAXMENUSIZE 60 // Default value for max num of entries in each menu
+#define MAXMENUHEIGHT 20 // Maximum number of entries displayed
+#define MENUBOXTYPE BOX_SINSIN // Default box type Look at tui.h for other values
+
+// Upper bounds on lengths
+// We copy the given string, so user can reuse the space used to store incoming arguments.
+#define MENULEN 78 // Each menu entry is atmost MENULEN chars
+#define STATLEN 78 // Maximum length of status string
+#define TITLELEN 78 // Maximum length of title string
+#define ACTIONLEN 255 // Maximum length of an action string
+
+// Layout of menu
+#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 STATLINE 24 // Line number where status line starts (relative to window)
+
+// Used for printing debugging messages
+#define DEBUGLINE 23 // debugging info goes here
+
+// Other Chars
+#define SUBMENUCHAR 175 // This is >> symbol
+#define RADIOMENUCHAR '>' // > symbol for radio menu?
+#define EXITMENUCHAR 174 // This is << symbol
+#define CHECKED 251 // Check mark
+#define UNCHECKED 250 // Light bullet
+#define RADIOSEL '.' // Current Radio Selection
+#define RADIOUNSEL ' ' // Radio option not selected
+
+typedef unsigned char uchar;
+
+// Types of menu's
+#define NORMALMENU 1
+#define RADIOMENU 2
+
+typedef enum {OPT_INACTIVE, OPT_SUBMENU, OPT_RUN, OPT_EXITMENU, OPT_CHECKBOX,
+ OPT_RADIOMENU, OPT_SEP, OPT_INVISIBLE,
+ OPT_RADIOITEM} t_action;
+
+typedef union {
+ uchar submenunum; // For submenu's
+ uchar checked; // For check boxes
+ uchar radiomenunum; // Item mapping to a radio menu
+} t_itemdata;
+
+struct s_menuitem;
+struct s_menu;
+struct s_menusystem;
+
+typedef struct {
+ unsigned int valid :1; // Is action valid?
+ unsigned int refresh:1; // Should we recompute menu stuff?
+ unsigned int reserved:6; // For future expansion
+} t_handler_return;
+
+t_handler_return ACTION_VALID,ACTION_INVALID; // Specific values
+
+typedef t_handler_return (*t_item_handler)(struct s_menusystem *, struct s_menuitem *);
+typedef void (*t_menusystem_handler)(struct s_menusystem *, struct s_menuitem *);
+typedef void (*t_keys_handler)(struct s_menusystem *, struct s_menuitem *,
+ unsigned int scancode);
+ // Last parameter = HIGH BYTE = scan code , LOW BYTE = ASCII CODE
+
+typedef enum {HDLR_SCREEN, HDLR_KEYS } t_handler;
+// Types of handlers for menu system
+
+// TIMEOUT is the list of possible values which can be returned by the handler
+// instructing the menusystem what to do. The default is CODE_WAIT
+typedef enum {CODE_WAIT, CODE_ENTER, CODE_ESCAPE } TIMEOUTCODE;
+typedef TIMEOUTCODE (*t_timeout_handler)(void);
+
+typedef struct s_menuitem {
+ char *item;
+ char *status;
+ char *data; // string containing kernel to run.. but...
+ // 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
+ 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
+
+typedef struct s_menu {
+ pt_menuitem *items; // pointer to array of pointer to menuitems
+ char *title; // Title string for menu
+ char *name; // menu can be referred to by this string
+ int maxmenusize; // the size of array allocated
+ uchar numitems; // how many items do we actually have
+ uchar menuwidth;
+ uchar row,col; // Position where this menu should be displayed
+ uchar menuheight; // Maximum number of items to be displayed
+} t_menu;
+
+typedef t_menu *pt_menu; // Pointer to type menu
+
+typedef struct s_menusystem {
+ pt_menu menus[MAXMENUS];
+ char *title;
+ t_menusystem_handler handler; // Menu system handler
+ t_keys_handler keys_handler; // Handler for unknown keys
+ t_timeout_handler ontimeout; // Timeout handler
+ 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;
+ uchar normalattr[2]; // [0] is non-hlite attr, [1] is hlite attr
+ uchar reverseattr[2];
+ uchar inactattr[2];
+ uchar revinactattr[2];
+ uchar statusattr[2];
+ uchar fillchar;
+ uchar fillattr;
+ uchar spacechar;
+ uchar tfillchar;
+ uchar titleattr;
+ uchar shadowattr;
+ uchar statline;
+ uchar menupage;
+ uchar maxrow,minrow,numrows; // Number of rows in the window
+ uchar maxcol,mincol,numcols; // Number of columns in the window
+
+ // Menu box look
+ boxtype menubt; // What type of boxes should be drawn
+ char box_horiz,box_ltrt,box_rtlt; // Some chars of the box, for redrawing portions of the box
+
+} t_menusystem;
+
+typedef t_menusystem *pt_menusystem; // Pointer to type menusystem
+
+pt_menuitem showmenus(uchar startmenu);
+
+pt_menusystem init_menusystem(const char *title);
+
+void close_menusystem(); // Deallocate memory used
+
+void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected);
+
+void set_normal_hlite(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected);
+
+void set_status_info(uchar statusattr, uchar statushlite, uchar statline);
+
+void set_title_info(uchar tfillchar, uchar titleattr);
+
+void set_misc_info(uchar fillchar, uchar fillattr,uchar spacechar, uchar shadowattr);
+void set_box_type(boxtype bt);
+
+void set_window_size(uchar top, uchar left, uchar bot, uchar right); // Set the window which menusystem should use
+
+void set_menu_options(uchar maxmenuheight);
+// maximum height of a menu
+
+void reg_handler(t_handler htype, void * handler); // Register handler
+
+void unreg_handler( t_handler htype);
+
+void reg_ontimeout(t_timeout_handler, unsigned int numsteps, unsigned int stepsize);
+// Set timeout handler, set 0 for default values.
+// 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);
+
+// Create a new menu and return its position
+uchar add_menu(const char *title, int maxmenusize);
+
+// Create a named menu and return its position
+uchar add_named_menu(const char *name, const char *title, int maxmenusize);
+
+void set_menu_pos(uchar row,uchar col); // Set the position of this menu.
+
+// Add item to the "current" menu
+pt_menuitem add_item(const char *item, const char *status, t_action action, const char *data, uchar itemdata);
+
+// Set shortcut key and help id
+void set_item_options(uchar shortcut,int helpid);
+
+// Set the shortcut key for the current item
+static inline void set_shortcut(uchar shortcut)
+{
+ set_item_options(shortcut,0xFFFF);
+}
+
+// Add a separator to the "current" menu
+pt_menuitem add_sep();
+
+// 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/com32/cmenu/libmenu/passwords.c b/com32/cmenu/libmenu/passwords.c
new file mode 100644
index 00000000..40b5c49f
--- /dev/null
+++ b/com32/cmenu/libmenu/passwords.c
@@ -0,0 +1,140 @@
+/* -*- 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,
+ * Bostom MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include "passwords.h"
+#include "des.h"
+#include "string.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "tui.h"
+
+#define MAX_LINE 512
+// Max line length in a pwdfile
+p_pwdentry userdb[MAX_USERS]; // Array of pointers
+int numusers; // Actual number of users
+
+// returns true or false, i.e. 1 or 0
+char authenticate_user(const char * username, const char* pwd)
+{
+ char salt[12];
+ int i;
+
+ for (i=0; i< numusers; i++) {
+ if (userdb[i] == NULL) continue;
+ if (strcmp(username,userdb[i]->username)==0) {
+ strcpy(salt, userdb[i]->pwdhash);
+ salt[2] = '\0';
+ if (strcmp(userdb[i]->pwdhash,crypt(pwd,salt))==0) return 1;
+ }
+ }
+ return 0;
+}
+
+// Does user USERNAME have permission PERM
+char isallowed(const char *username, const char *perm)
+{
+ int i;
+ 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);
+ dperm[0] = ':';
+ dperm[strlen(perm)+1]=':';
+ dperm[strlen(perm)+2]=0;
+ // Now dperm = ":perm:"
+ for (i=0; i < numusers; i++) {
+ if (strcmp(userdb[i]->username,username)==0) // Found the user
+ {
+ if (userdb[i]->perms == NULL) return 0; // No permission
+ tmp = strstr(userdb[i]->perms,dperm); // Search for permission
+ free (dperm); // Release memory
+ if (tmp == NULL) return 0; else return 1;
+ }
+ }
+ // User not found return 0
+ free (dperm);
+ return 0;
+}
+
+// Initialise the list of of user passwords permissions from file
+void init_passwords(const char *filename)
+{
+ int i;
+ char line[MAX_LINE], *p,*user,*pwdhash,*perms;
+ FILE *f;
+
+ for (i=0; i < MAX_USERS; i++) userdb[i] = NULL;
+ numusers = 0;
+
+ if ( !filename ) return; // No filename specified
+
+ f = fopen(filename,"r");
+ if ( !f ) return; // File does not exist
+
+ // Process each line
+ while ( fgets(line, sizeof line, f) ) {
+ // Replace EOLN with \0
+ p = strchr(line, '\r');
+ if ( p ) *p = '\0';
+ p = strchr(line, '\n');
+ if ( p ) *p = '\0';
+
+ // If comment line or empty ignore line
+ p = line;
+ while (*p==' ') p++; // skip initial spaces
+ if ( (*p == '#') || (*p == '\0')) continue; // Skip comment lines
+
+ user = p; // This is where username starts
+ p = strchr(user,':');
+ if (p == NULL) continue; // Malformed line skip
+ *p = '\0';
+ pwdhash = p+1;
+ if (*pwdhash == 0) continue; // Malformed line (no password specified)
+ p = strchr(pwdhash,':');
+ if (p == NULL) { // No perms specified
+ perms = NULL;
+ } else {
+ *p = '\0';
+ perms = p+1;
+ if (*perms == 0) perms = NULL;
+ }
+ // At this point we have user,pwdhash and perms setup
+ userdb[numusers] = (p_pwdentry)malloc(sizeof(pwdentry));
+ strcpy(userdb[numusers]->username,user);
+ strcpy(userdb[numusers]->pwdhash,pwdhash);
+ if (perms == NULL)
+ userdb[numusers]->perms = NULL;
+ else {
+ userdb[numusers]->perms = (char *)malloc(strlen(perms)+3);
+ (userdb[numusers]->perms)[0] = ':';
+ strcpy(userdb[numusers]->perms + 1,perms);
+ (userdb[numusers]->perms)[strlen(perms)+1] = ':';
+ (userdb[numusers]->perms)[strlen(perms)+2] = 0;
+ // Now perms field points to ":perms:"
+ }
+ numusers++;
+ }
+ fclose(f);
+}
+
+void close_passwords()
+{
+ int i;
+
+ for (i=0; i < numusers; i++)
+ if (userdb[i] != NULL) free(userdb[i]);
+ numusers = 0;
+}
diff --git a/com32/cmenu/libmenu/passwords.h b/com32/cmenu/libmenu/passwords.h
new file mode 100644
index 00000000..00e5702d
--- /dev/null
+++ b/com32/cmenu/libmenu/passwords.h
@@ -0,0 +1,27 @@
+#ifndef _PASSWORDS_H_
+#define _PASSWORDS_H_
+
+char authenticate_user(const char * username, const char* pwd);
+
+char isallowed(const char *username, const char * perm);
+
+// Initialise the list of of user passwords permissions from file
+void init_passwords(const char *filename);
+// Free all space used for internal data structures
+void close_passwords();
+
+#define MAX_USERS 128 // Maximum number of users
+#define USERNAME_LENGTH 12 // Max length of user name
+#define PWDHASH_LENGTH 40 // Max lenght of pwd hash
+
+typedef struct {
+ char username[USERNAME_LENGTH+1];
+ char pwdhash[PWDHASH_LENGTH+1];
+ char *perms; // pointer to string containing ":" delimited permissions
+} pwdentry;
+
+typedef pwdentry *p_pwdentry;
+
+#define GUEST_USER "guest"
+
+#endif
diff --git a/com32/cmenu/libmenu/scancodes.h b/com32/cmenu/libmenu/scancodes.h
new file mode 100644
index 00000000..d3f625a6
--- /dev/null
+++ b/com32/cmenu/libmenu/scancodes.h
@@ -0,0 +1,86 @@
+/* -*- 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 __SCANCODES_H__
+#define __SCANCODES_H__
+
+// Scancodes of some keys
+#define ESCAPE 1
+#define ENTERA 28
+#define ENTERB 224
+
+#define HOMEKEY 71
+#define UPARROW 72
+#define PAGEUP 73
+#define LTARROW 75
+#define RTARROW 77
+#define ENDKEY 79
+#define DNARROW 80
+#define PAGEDN 81
+#define INSERT 82
+#define DELETE 83
+#define SPACEKEY 57 // Scan code for SPACE
+
+#define CTRLLT 0x73
+#define CTRLRT 0x74
+
+#define F1 0x3B
+#define F2 0x3C
+#define F3 0x3D
+#define F4 0x3E
+#define F5 0x3F
+#define F6 0x40
+#define F7 0x41
+#define F8 0x42
+#define F9 0x43
+#define F10 0x44
+#define F11 0x85
+#define F12 0x86
+
+#define CTRLF1 0x5E
+#define CTRLF2 0x5F
+#define CTRLF3 0x60
+#define CTRLF4 0x61
+#define CTRLF5 0x62
+#define CTRLF6 0x63
+#define CTRLF7 0x64
+#define CTRLF8 0x65
+#define CTRLF9 0x66
+#define CTRLF10 0x67
+#define CTRLF11 0x89
+#define CTRLF12 0x8A
+
+#define ALTF1 0x68
+#define ALTF2 0x69
+#define ALTF3 0x6A
+#define ALTF4 0x6B
+#define ALTF5 0x6C
+#define ALTF6 0x6D
+#define ALTF7 0x6E
+#define ALTF8 0x6F
+#define ALTF9 0x70
+#define ALTF10 0x71
+#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/com32/cmenu/libmenu/syslnx.c b/com32/cmenu/libmenu/syslnx.c
new file mode 100644
index 00000000..d2b0aef4
--- /dev/null
+++ b/com32/cmenu/libmenu/syslnx.c
@@ -0,0 +1,88 @@
+/* -*- 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <string.h>
+#include <com32.h>
+#include "syslnx.h"
+
+com32sys_t inreg,outreg; // Global registers for this module
+
+char issyslinux(void)
+{
+ REG_EAX(inreg) = 0x00003000;
+ REG_EBX(inreg) = REG_ECX(inreg) = REG_EDX(inreg) = 0xFFFFFFFF;
+ __intcall(0x21,&inreg,&outreg);
+ return (REG_EAX(outreg) == 0x59530000) &&
+ (REG_EBX(outreg) == 0x4c530000) &&
+ (REG_ECX(outreg) == 0x4e490000) &&
+ (REG_EDX(outreg) == 0x58550000);
+}
+
+void runsyslinuxcmd(const char *cmd)
+{
+ strcpy(__com32.cs_bounce, cmd);
+ REG_AX(inreg) = 0x0003; // Run command
+ REG_BX(inreg) = OFFS(__com32.cs_bounce);
+ REG_ES(inreg) = SEG(__com32.cs_bounce);
+ __intcall(0x22, &inreg, &outreg);
+}
+
+void gototxtmode(void)
+{
+ REG_AX(inreg) = 0x0005;
+ __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/com32/cmenu/libmenu/syslnx.h b/com32/cmenu/libmenu/syslnx.h
new file mode 100644
index 00000000..755b9690
--- /dev/null
+++ b/com32/cmenu/libmenu/syslnx.h
@@ -0,0 +1,64 @@
+/* -*- 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 __SYSLNX_H__
+#define __SYSLNX_H__
+
+#include <com32.h>
+
+//Macros which help user not have to remember the structure of register
+// Data structure
+
+#define REG_AH(x) ((x).eax.b[1])
+#define REG_AL(x) ((x).eax.b[0])
+#define REG_AX(x) ((x).eax.w[0])
+#define REG_EAX(x) ((x).eax.l)
+
+#define REG_BH(x) ((x).ebx.b[1])
+#define REG_BL(x) ((x).ebx.b[0])
+#define REG_BX(x) ((x).ebx.w[0])
+#define REG_EBX(x) ((x).ebx.l)
+
+#define REG_CH(x) ((x).ecx.b[1])
+#define REG_CL(x) ((x).ecx.b[0])
+#define REG_CX(x) ((x).ecx.w[0])
+#define REG_ECX(x) ((x).ecx.l)
+
+#define REG_DH(x) ((x).edx.b[1])
+#define REG_DL(x) ((x).edx.b[0])
+#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/com32/cmenu/libmenu/tui.c b/com32/cmenu/libmenu/tui.c
new file mode 100644
index 00000000..cb8c1936
--- /dev/null
+++ b/com32/cmenu/libmenu/tui.c
@@ -0,0 +1,357 @@
+/* -*- 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include "tui.h"
+#include <string.h>
+#include <com32.h>
+#include <stdlib.h>
+
+com32sys_t inreg,outreg; // Global register sets for use
+
+char bkspstr[] = " \b$";
+char eolstr[] = "\n$";
+#define GETSTRATTR 0x07
+
+// Reads a line of input from stdin. Replace CR with NUL byte
+// password <> 0 implies not echoed on screen
+// showoldvalue <> 0 implies currentvalue displayed first
+// If showoldvalue <> 0 then caller responsibility to ensure that
+// str is NULL terminated.
+void getuserinput(char *stra, unsigned int size, unsigned int password,
+ unsigned int showoldvalue)
+{
+ unsigned char c,scan;
+ char *p,*q; // p = current char of string, q = tmp
+ char *last; // The current last char of string
+ char *str; // pointer to string which is going to be allocated
+ char page;
+ char row,col;
+ char start,end; // Cursor shape
+ char fudge; // How many chars should be removed from output
+ char insmode; // Are we in insert or overwrite
+
+ page = getdisppage();
+ getpos(&row,&col,page); // Get current position
+ getcursorshape(&start,&end);
+ insmode = 1;
+
+ str = (char *)malloc(size+1); // Allocate memory to store user input
+ memset(str,0,size+1); // Zero it out
+ if (password != 0) showoldvalue = 0; // Password's never displayed
+
+ if (showoldvalue != 0) strcpy(str,stra); // If show old value copy current value
+
+ last = str;
+ while (*last) {last++;} // Find the terminating null byte
+ p = str+ strlen(str);
+
+ if (insmode == 0)
+ setcursorshape(1,7); // Block cursor
+ else setcursorshape(6,7); // Normal cursor
+
+ // Invariants: p is the current char
+ // col is the corresponding column on the screen
+ if (password == 0) // Not a password, print initial value
+ {
+ gotoxy(row,col,page);
+ csprint(str,GETSTRATTR);
+ }
+ while (1) { // Do forever
+ c = inputc(&scan);
+ if (c == '\r') break; // User hit Enter getout of loop
+ if (scan == ESCAPE) // User hit escape getout and nullify string
+ { *str = 0;
+ break;
+ }
+ fudge = 0;
+ // if scan code is regognized do something
+ // else if char code is recognized do something
+ // else ignore
+ switch(scan) {
+ case HOMEKEY:
+ p = str;
+ break;
+ case ENDKEY:
+ p = last;
+ break;
+ case LTARROW:
+ if (p > str) p--;
+ break;
+ case CTRLLT:
+ if (p==str) break;
+ if (*p == ' ')
+ while ((p > str) && (*p == ' ')) p--;
+ else {
+ if (*(p-1) == ' ') {
+ p--;
+ while ((p > str) && (*p == ' ')) p--;
+ }
+ }
+ while ((p > str) && ((*p == ' ') || (*(p-1) != ' '))) p--;
+ break;
+ case RTARROW:
+ if (p < last) p++;
+ break;
+ case CTRLRT:
+ if (*p==0) break; // At end of string
+ if (*p != ' ')
+ while ((*p!=0) && (*p != ' ')) p++;
+ while ((*p!=0) && ((*p == ' ') && (*(p+1) != ' '))) p++;
+ if (*p==' ') p++;
+ break;
+ case DELETE:
+ q = p;
+ while (*(q+1)) {*q = *(q+1); q++; }
+ if (last > str) last--;
+ fudge = 1;
+ break;
+ case INSERT:
+ insmode = 1-insmode; // Switch mode
+ if (insmode == 0)
+ setcursorshape(1,7); // Block cursor
+ else setcursorshape(6,7); // Normal cursor
+ break;
+
+ default: // Unrecognized scan code, look at the ascii value
+ switch (c) {
+ case '\b': // Move over by one
+ q=p;
+ while ( q <= last ) { *(q-1)=*q; q++;}
+ if (last > str) last--;
+ if (p > str) p--;
+ fudge = 1;
+ break;
+ case '\x15': /* Ctrl-U: kill input */
+ fudge = last-str;
+ while ( p > str ) *p--=0;
+ p = str; *p=0; last = str;
+ break;
+ default: // Handle insert and overwrite mode
+ if ((c >= ' ') && (c < 128) &&
+ ((unsigned int)(p-str) < size-1) ) {
+ if (insmode == 0) { // Overwrite mode
+ if (p==last) last++;
+ *last = 0;
+ *p++ = c;
+ } else { // Insert mode
+ if (p==last) { // last char
+ last++;
+ *last=0;
+ *p++=c;
+ } else { // Non-last char
+ q=last++;
+ while (q >= p) { *q=*(q-1); q--;}
+ *p++=c;
+ }
+ }
+ }
+ else beep();
+ }
+ break;
+ }
+ // Now the string has been modified, print it
+ if (password == 0) {
+ gotoxy(row,col,page);
+ csprint(str,GETSTRATTR);
+ if (fudge > 0) cprint(' ',GETSTRATTR,fudge,page);
+ gotoxy(row,col+(p-str),page);
+ }
+ }
+ *p = '\0';
+ if (password == 0) csprint("\r\n",GETSTRATTR);
+ setcursorshape(start,end); // Block cursor
+ // If user hit ESCAPE so return without any changes
+ if (scan != ESCAPE) strcpy(stra,str);
+ free(str);
+}
+
+/* Print a C string (NUL-terminated) */
+void cswprint(const char *str,char attr,char left)
+{
+ char page = getdisppage();
+ char newattr=0,cha,chb;
+ char row,col;
+ char nr,nc;
+
+ nr = getnumrows();
+ nc = getnumcols();
+ getpos(&row,&col,page);
+ while ( *str ) {
+ switch (*str)
+ {
+ case '\b':
+ --col;
+ break;
+ case '\n':
+ ++row;
+ col = left;
+ break;
+ case '\r':
+ //col=left;
+ break;
+ case BELL: // Bell Char
+ beep();
+ break;
+ case CHRELATTR: // change attribute (relatively)
+ case CHABSATTR: // change attribute (absolute)
+ cha = *(str+1);
+ chb = *(str+2);
+ if ((((cha >= '0') && (cha <= '9')) ||
+ ((cha >= 'A') && (cha <= 'F'))) &&
+ (((chb >= '0') && (chb <= '9')) ||
+ ((chb >= 'A') && (chb <= 'F')))) // Next two chars are legal
+ {
+ if ((cha >= 'A') && (cha <= 'F'))
+ cha = cha - 'A'+10;
+ else cha = cha - '0';
+ if ((chb >= 'A') && (chb <= 'F'))
+ chb = chb - 'A'+10;
+ else chb = chb - '0';
+ newattr = (cha << 4) + chb;
+ attr = (*str == CHABSATTR ? newattr : attr ^ newattr);
+ str += 2; // Will be incremented again later
+ }
+ break;
+ default:
+ putch(*str, attr, page);
+ ++col;
+ }
+ if (col >= nc)
+ {
+ ++row;
+ col=left;
+ }
+ if (row > nr)
+ {
+ scrollup();
+ row= nr;
+ }
+ gotoxy(row,col,page);
+ str++;
+ }
+}
+
+void clearwindow(char top, char left, char bot, char right, char page, char fillchar, char fillattr)
+{
+ char x;
+ for (x=top; x < bot+1; x++)
+ {
+ gotoxy(x,left,page);
+ cprint(fillchar,fillattr,right-left+1,page);
+ }
+}
+
+void cls(void)
+{
+ unsigned char dp = getdisppage();
+ gotoxy(0,0,dp);
+ cprint(' ',GETSTRATTR,(1+getnumrows())*getnumcols(),dp);
+}
+
+//////////////////////////////Box Stuff
+
+// This order of numbers must match
+// the values of BOX_TOPLEFT,... in the header file
+
+unsigned char SINSIN_CHARS[] = {218,192,191,217, //Corners
+ 196,179, // Horiz and Vertical
+ 195,180,194,193,197}; // Connectors & Middle
+
+unsigned char DBLDBL_CHARS[] = {201,200,187,188, // Corners
+ 205,186, // Horiz and Vertical
+ 199,182,203,202,206}; // Connectors & Middle
+
+unsigned char SINDBL_CHARS[] = {214,211,183,189, // Corners
+ 196,186, // Horiz & Vert
+ 199,182,210,208,215}; // Connectors & Middle
+
+unsigned char DBLSIN_CHARS[] = {213,212,184,190, // Corners
+ 205,179, // Horiz & Vert
+ 198,181,209,207,216}; // Connectors & Middle
+
+unsigned char * getboxchars(boxtype bt)
+{
+ switch (bt)
+ {
+ case BOX_SINSIN:
+ return SINSIN_CHARS;
+ break;
+ case BOX_DBLDBL:
+ return DBLDBL_CHARS;
+ break;
+ case BOX_SINDBL:
+ return SINDBL_CHARS;
+ break;
+ case BOX_DBLSIN:
+ return DBLSIN_CHARS;
+ break;
+ default:
+ return SINSIN_CHARS;
+ break;
+ }
+ return SINSIN_CHARS;
+}
+
+// Draw box and lines
+void drawbox(char top,char left,char bot, char right,
+ char page, char attr,boxtype bt)
+{
+ unsigned char *box_chars; // pointer to array of box chars
+ unsigned char x;
+
+ box_chars = getboxchars(bt);
+ // Top border
+ gotoxy(top,left,page);
+ cprint(box_chars[BOX_TOPLEFT],attr,1,page);
+ gotoxy(top,left+1,page);
+ cprint(box_chars[BOX_TOP],attr,right-left,page);
+ gotoxy(top,right,page);
+ cprint(box_chars[BOX_TOPRIGHT],attr,1,page);
+ // Bottom border
+ gotoxy(bot,left,page);
+ cprint(box_chars[BOX_BOTLEFT],attr,1,page);
+ gotoxy(bot,left+1,page);
+ cprint(box_chars[BOX_BOT],attr,right-left,page);
+ gotoxy(bot,right,page);
+ cprint(box_chars[BOX_BOTRIGHT],attr,1,page);
+ // Left & right borders
+ for (x=top+1; x < bot; x++)
+ {
+ gotoxy(x,left,page);
+ cprint(box_chars[BOX_LEFT],attr,1,page);
+ gotoxy(x,right,page);
+ cprint(box_chars[BOX_RIGHT],attr,1,page);
+ }
+}
+
+void drawhorizline(char top, char left, char right, char page, char attr,
+ boxtype bt, char dumb)
+{
+ unsigned char start,end;
+ unsigned char *box_chars = getboxchars(bt);
+ if (dumb==0) {
+ start = left+1;
+ end = right-1;
+ } else {
+ start = left;
+ end = right;
+ }
+ gotoxy(top,start,page);
+ cprint(box_chars[BOX_HORIZ],attr,end-start+1,page);
+ if (dumb == 0)
+ {
+ gotoxy(top,left,page);
+ cprint(box_chars[BOX_LTRT],attr,1,page);
+ gotoxy(top,right,page);
+ cprint(box_chars[BOX_RTLT],attr,1,page);
+ }
+}
diff --git a/com32/cmenu/libmenu/tui.h b/com32/cmenu/libmenu/tui.h
new file mode 100644
index 00000000..92f93863
--- /dev/null
+++ b/com32/cmenu/libmenu/tui.h
@@ -0,0 +1,88 @@
+/* -*- 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 __TUI_H__
+#define __TUI_H__
+
+#include <com32.h>
+#include "syslnx.h"
+#include "com32io.h"
+#include "scancodes.h"
+
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define BELL 0x07
+// CHRELATTR = ^N, CHABSATTR = ^O
+#define CHABSATTR 15
+#define CHRELATTR 14
+
+void clearwindow(char top, char left, char bot, char right,
+ char page, char fillchar, char fillattr);
+
+void cls(void); /* Clears the entire current screen page */
+
+// Generic user input,
+// password = 0 iff chars echoed on screen
+// showoldvalue <> 0 iff current displayed for editing
+void getuserinput(char *str, unsigned int size,
+ unsigned int password, unsigned int showoldvalue);
+
+static inline void getstring(char *str, unsigned int size)
+{
+ getuserinput(str,size,0,0);
+}
+
+static inline void editstring(char *str, unsigned int size)
+{
+ getuserinput(str,size,0,1);
+}
+
+static inline void getpwd(char * str, unsigned int size)
+{
+ getuserinput(str,size,1,0);
+}
+
+// Box drawing Chars offsets into array
+#define BOX_TOPLEFT 0x0
+#define BOX_BOTLEFT 0x1
+#define BOX_TOPRIGHT 0x2
+#define BOX_BOTRIGHT 0x3
+#define BOX_TOP 0x4 // TOP = BOT = HORIZ
+#define BOX_BOT 0x4
+#define BOX_HORIZ 0x4
+#define BOX_LEFT 0x5
+#define BOX_RIGHT 0x5
+#define BOX_VERT 0x5 // LEFT=RIGHT=VERT
+#define BOX_LTRT 0x6
+#define BOX_RTLT 0x7
+#define BOX_TOPBOT 0x8
+#define BOX_BOTTOP 0x9
+#define BOX_MIDDLE 0xA
+
+typedef enum {BOX_SINSIN,BOX_DBLDBL, BOX_SINDBL, BOX_DBLSIN} boxtype;
+
+unsigned char * getboxchars(boxtype bt);
+
+void drawbox(char top,char left,char bot, char right,
+ char page, char attr,boxtype bt);
+
+// Draw a horizontal line
+// dumb == 1, means just draw the line
+// dumb == 0 means check the first and last positions and depending on what is
+// currently on the screen make it a LTRT and/or RTLT appropriately.
+void drawhorizline(char top, char left, char right, char page, char attr,
+ boxtype bt, char dumb);
+
+#endif
diff --git a/com32/cmenu/menugen.py b/com32/cmenu/menugen.py
new file mode 100644
index 00000000..70ec1f87
--- /dev/null
+++ b/com32/cmenu/menugen.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python
+
+import sys, re, getopt
+
+class Menusystem:
+
+ 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.init_entry()
+ self.init_menu()
+ self.init_system()
+ 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 = self.entry_init.copy()
+
+ def init_menu(self):
+ self.menu = self.menu_init.copy()
+
+ def init_system(self):
+ self.system = self.system_init.copy()
+
+ def add_menu(self,name):
+ self.add_item()
+ self.init_menu()
+ self.menu["name"] = name
+ self.menu["_updated"] = 1
+ self.menus.append( (self.menu,[]) )
+
+ def add_item(self):
+ if self.menu["_updated"]: # menu details have changed
+ self.menus[-1][0].update(self.menu)
+ self.init_menu()
+ if self.entry["_updated"]:
+ if not self.entry["info"]:
+ self.entry["info"] = self.entry["data"]
+ if not self.menus:
+ print "Error before line %d" % self.lineno
+ print "REASON: menu must be declared before a menu item is declared"
+ sys.exit(1)
+ self.menus[-1][1].append(self.entry)
+ self.init_entry()
+
+ 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 "\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 "\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):
+ if not self.menu.has_key(name):
+ 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: 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):
+ # 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)
+
+ if not err: return
+
+ # all errors so return item's error message
+ print err
+ sys.exit(1)
+
+ def print_entry(self,entry,fd):
+ entry["type"] = self.types[entry["type"]]
+ 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.templates["menu"] % menu)
+ if (menu["row"] != "0xFF") or (menu["col"] != "0xFF"):
+ fd.write(' set_menu_pos(%(row)s,%(col)s);\n' % menu)
+
+
+ def output(self,filename):
+ 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(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(self.templates["footer"])
+ fd.close()
+ if not self.foundmain:
+ print "main menu not found"
+ print self.menus
+ sys.exit(1)
+
+ def input(self,filename):
+ 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:
+ 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
+
+ # add property of current entry
+ pos = line.find("=") # find the first = in string
+ if pos < 0:
+ print "Syntax error in line %d" % self.lineno
+ print "REASON: non-section lines must be of the form ATTRIBUTE=VALUE"
+ sys.exit(1)
+ attr = line[:pos].strip().lower()
+ value = line[pos+1:].strip()
+ self.set(attr,value)
+ except:
+ print "Error while parsing line %d: %s" % (self.lineno,line)
+ raise
+ fd.close()
+ self.add_item()
+
+def usage():
+ 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():
+ 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/com32/cmenu/password b/com32/cmenu/password
new file mode 100644
index 00000000..3caffe22
--- /dev/null
+++ b/com32/cmenu/password
@@ -0,0 +1,18 @@
+# This file should be available as /isolinux/password
+# for complex.c to use.
+#
+# All lines starting with # and empty lines are ignored
+#
+# All non-comment lines here are of the form
+# USERNAME:PWDHASH:PERM1:PERM2:...:
+#
+# where USERNAME is maximum of 12 chars,
+# PWDHASH is maximum of 40 chars (DES ENCRYPTED)
+# PERM1,... are arbitrary strings
+#
+# The current lines correspond to
+# user1:secret1, user2:secret2, user3:secret3
+
+user1:LcMRo3YZGtP0c:editcmd
+user2:FqewzyxP78a7A:
+user3:MKjmc.IHoXBNU:root
diff --git a/com32/cmenu/simple.c b/com32/cmenu/simple.c
new file mode 100644
index 00000000..92e8ab12
--- /dev/null
+++ b/com32/cmenu/simple.c
@@ -0,0 +1,79 @@
+/* -*- 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)
+
+ // Choose the default title and setup default values for all attributes....
+ init_menusystem(NULL);
+ set_window_size(1,1,23,78); // Leave one row/col border all around
+
+ // Choose the default values for all attributes and char's
+ // -1 means choose defaults (Actually the next 4 lines are not needed)
+ //set_normal_attr (-1,-1,-1,-1);
+ //set_status_info (-1,-1);
+ //set_title_info (-1,-1);
+ //set_misc_info(-1,-1,-1,-1);
+
+ // menuindex = add_named_menu("name"," Menu Title ",-1);
+ // add_item("Item string","Status String",TYPE,"any string",NUM)
+ // TYPE = OPT_RUN | OPT_EXITMENU | OPT_SUBMENU | OPT_CHECKBOX | OPT_INACTIVE
+ // "any string" useful for storing kernel names
+ // In case of OPT_SUBMENU, "any string" can be set to "name" of menu to be linked
+ // in which case value NUM is ignored
+ // NUM = index of submenu if OPT_SUBMENU,
+ // 0/1 default checked state if OPT_CHECKBOX
+ // unused otherwise.
+
+ add_named_menu("testing"," Testing ",-1);
+ add_item("Self Loop","Go to testing",OPT_SUBMENU,"testing",0);
+ add_item("Memory Test","Perform extensive memory testing",OPT_RUN, "memtest",0);
+ add_item("Exit this menu","Go one level up",OPT_EXITMENU,"exit",0);
+
+ add_named_menu("rescue"," Rescue Options ",-1);
+ add_item("Linux Rescue","linresc",OPT_RUN,"linresc",0);
+ add_item("Dos Rescue","dosresc",OPT_RUN,"dosresc",0);
+ add_item("Windows Rescue","winresc",OPT_RUN,"winresc",0);
+ add_item("Exit this menu","Go one level up",OPT_EXITMENU,"exit",0);
+
+ add_named_menu("main"," Main Menu ",-1);
+ add_item("Prepare","prep",OPT_RUN,"prep",0);
+ add_item("Rescue options...","Troubleshoot a system",OPT_SUBMENU,"rescue",0);
+ add_item("Testing...","Options to test hardware",OPT_SUBMENU,"testing",0);
+ add_item("Exit to prompt", "Exit the menu system", OPT_EXITMENU, "exit", 0);
+
+ 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;
+}
diff --git a/com32/cmenu/test.menu b/com32/cmenu/test.menu
new file mode 100644
index 00000000..061c548e
--- /dev/null
+++ b/com32/cmenu/test.menu
@@ -0,0 +1,60 @@
+# choose default title
+title = "A test of the test.menu file"
+top = 1
+left = 1
+bot = 23
+right = 78
+
+[testing]
+title = " Testing "
+
+item="Self Loop"
+info="Go to Testing"
+type=submenu
+data=testing
+
+item="Memory Test"
+info="Perform extensive memory testing"
+data="memtest"
+
+item="Exit this menu"
+info="Go one level up"
+type=exitmenu
+
+[rescue]
+title = " Rescue Options "
+row = 10
+col = 10
+
+item="Linux Rescue"
+data="linresc"
+
+item="Dos Rescue"
+data="dosresc"
+
+item="Windows Rescue"
+data="winresc"
+
+item="Exit this menu"
+info="Go one level up"
+type=exitmenu
+
+[main]
+title = " Main Menu "
+
+item="Prepare"
+data="prep"
+
+item="Rescue options..."
+info="Troubleshoot a system"
+type=submenu
+data="rescue"
+
+item="Testing..."
+info="Options to test hardware"
+type=submenu
+data="testing"
+
+item="Exit this menu"
+info="Go one level up"
+type=exitmenu
diff --git a/com32/cmenu/test2.menu b/com32/cmenu/test2.menu
new file mode 100644
index 00000000..4570dc2c
--- /dev/null
+++ b/com32/cmenu/test2.menu
@@ -0,0 +1,142 @@
+
+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