Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/CHANGES
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/CHANGES	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/CHANGES	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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.
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/HISTORY
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/HISTORY	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/HISTORY	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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.
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/MANUAL
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/MANUAL	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/MANUAL	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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.
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/MENU_FORMAT
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/MENU_FORMAT	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/MENU_FORMAT	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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.
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/Makefile
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/Makefile	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/Makefile	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,74 @@
+## -----------------------------------------------------------------------
+##
+##   Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
+##   Copyright 2009 Intel Corporation; author: H. Peter Anvin
+##
+##   This program is free software; you can redistribute it and/or modify
+##   it under the terms of the GNU General Public License as published by
+##   the Free Software Foundation, Inc., 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
+##
+
+NOGPL := 1
+
+LIBS  = libmenu/libmenu.c32 \
+        $(objdir)/com32/libutil/libutil.c32 \
+        $(objdir)/com32/lib/libcom32.c32
+
+C_LIBS	  = libmenu/libmenu.c32
+
+VPATH = $(SRC)
+include $(MAKEDIR)/elf.mk
+
+CFLAGS	  += -I$(SRC)/libmenu
+
+LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \
+	libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o \
+	$(objdir)/com32/libutil/libutil.c32 $(objdir)/com32/lib/libcom32.c32
+
+CMENUS = $(patsubst %.c,%.c32,$(wildcard $(SRC)/*.c))
+IMENUS = $(patsubst %.menu,%.c32,$(wildcard $(SRC)/*.menu))
+
+MENUS = $(LIBS) $(subst $(SRC)/,,$(CMENUS) $(IMENUS))
+
+.SUFFIXES: .S .c .o .elf .c32 .menu
+
+.PRECIOUS: %.c
+%.c: %.menu adv_menu.tpl
+	$(PYTHON) $(SRC)/menugen.py --input=$< --output=$@ --template=$(SRC)/adv_menu.tpl
+
+all:	makeoutputdirs menus
+
+makeoutputdirs:
+	@mkdir -p $(OBJ)/libmenu
+
+libmenu/libmenu.elf: $(LIBMENU)
+	$(LD) -shared $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) \
+		-o $@ $^
+
+tidy dist:
+	rm -f *.o *.lo *.lst *.elf */*.o */*.elf .*.d */.*.d
+
+libclean:
+	rm -f libmenu/*.c32
+
+clean: tidy menuclean
+	rm -f *.lss *.com
+
+menuclean:
+	rm -f $(patsubst %.menu,%.c,$(wildcard *.menu))
+
+spotless: clean libclean menuclean
+	rm -f *~ \#* *.c32
+
+menus: $(MENUS)
+
+install:	# Don't install samples
+
+-include .*.d */.*.d
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/README
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/README	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/README	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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)
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/TODO
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/TODO	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/TODO	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/adv_menu.tpl
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/adv_menu.tpl	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/adv_menu.tpl	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,465 @@
+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 "cmenu.h"
+#include "help.h"
+#include "passwords.h"
+#include "com32io.h"
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.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(void)
+{
+   return timeout(timeoutcmd);
+}
+
+TIMEOUTCODE ontotaltimeout(void)
+{
+   return timeout(totaltimeoutcmd);
+}
+
+void keys_handler(t_menusystem * ms __attribute__ (( unused )), t_menuitem * mi, int scancode)
+{
+   int nc, nr;
+
+   if (getscreensize(1, &nr, &nc)) {
+       /* Unknown screen size? */
+       nc = 80;
+       nr = 24;
+   }
+
+   if ( (scancode == KEY_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 == KEY_TAB) && (mi->action == OPT_RUN) &&
+       (EDIT_ROW < nr) && (EDIT_ROW > 0) &&
+       (isallowed(username,"editcmd") || isallowed(username,"root"))) {
+     // User typed TAB and has permissions to edit command line
+     gotoxy(EDIT_ROW,1);
+     csprint("Command line:",0x07);
+     editstring(mi->data,ACTIONLEN);
+     gotoxy(EDIT_ROW,1);
+     cprint(' ',0x07,nc-1);
+   }
+}
+
+t_handler_return login_handler(t_menusystem *ms, t_menuitem *mi)
+{
+  (void)mi; // Unused
+  char pwd[40];
+  char login[40];
+  int nc, nr;
+  t_handler_return rv;
+
+  (void)ms;
+
+  rv = ACTION_INVALID;
+  if (PWD_ROW < 0) return rv; // No need to authenticate
+
+  if (mi->item == loginstr) { /* User wants to login */
+    if (getscreensize(1, &nr, &nc)) {
+        /* Unknown screen size? */
+        nc = 80;
+        nr = 24;
+    }
+
+    gotoxy(PWD_ROW,1);
+    csprint("Enter Username: ",0x07);
+    getstring(login, sizeof username);
+    gotoxy(PWD_ROW,1);
+    cprint(' ',0x07,nc);
+    csprint("Enter Password: ",0x07);
+    getpwd(pwd, sizeof pwd);
+    gotoxy(PWD_ROW,1);
+    cprint(' ',0x07,nc);
+
+    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,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--
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/complex.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/complex.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/complex.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,450 @@
+/* -*- 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 "cmenu.h"
+#include "com32io.h"
+#include "help.h"
+#include "passwords.h"
+#include "des.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <getkey.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(void)
+{
+    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 __attribute__ (( unused )), t_menuitem * mi, int scancode)
+{
+    int nc, nr;
+
+    if ((scancode) == KEY_F1 && mi->helpid != 0xFFFF) {	// 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 == KEY_TAB) && (mi->action == OPT_RUN) &&
+	(isallowed(username, "editcmd") || isallowed(username, "root"))) {
+    if (getscreensize(1, &nr, &nc)) {
+        /* Unknown screen size? */
+        nc = 80;
+        nr = 24;
+    }
+	// User typed TAB and has permissions to edit command line
+	gotoxy(EDITPROMPT, 1);
+	csprint("Command line:", 0x07);
+	editstring(mi->data, ACTIONLEN);
+	gotoxy(EDITPROMPT, 1);
+    clear_line();
+    }
+}
+
+t_handler_return login_handler(t_menusystem * ms, t_menuitem * mi)
+{
+    (void)mi;			// Unused
+    char pwd[40];
+    char login[40];
+    int nc, nr;
+    t_handler_return rv;
+
+    (void)ms;
+
+    if (mi->item == loginstr) {	/* User wants to login */
+    if (getscreensize(1, &nr, &nc)) {
+        /* Unknown screen size? */
+        nc = 80;
+        nr = 24;
+    }
+	gotoxy(PWDPROMPT, 1);
+	csprint("Enter Username: ", 0x07);
+	getstring(login, sizeof username);
+	gotoxy(PWDPROMPT, 1);
+    clear_line();
+	csprint("Enter Password: ", 0x07);
+	getpwd(pwd, sizeof pwd);
+	gotoxy(PWDPROMPT, 1);
+    clear_line();
+
+	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;
+    rv.reserved = 0;
+    return rv;
+}
+
+void msys_handler(t_menusystem * ms, t_menuitem * mi)
+{
+    int nc, nr;
+    void *v;
+
+    if (getscreensize(1, &nr, &nc)) {
+        /* Unknown screen size? */
+        nc = 80;
+        nr = 24;
+    }
+    gotoxy(PWDLINE, PWDCOLUMN);
+    csprint("User: ", PWDATTR);
+    cprint(ms->fillchar, ms->fillattr, sizeof username);
+    gotoxy(PWDLINE, PWDCOLUMN + 6);
+    csprint(username, PWDATTR);
+
+    if (mi->parindex != PREPMENU)	// If we are not in the PREP MENU
+    {
+	gotoxy(INFLINE, 0);
+    reset_colors();
+    clear_line();
+	gotoxy(INFLINE + 1, 0);
+    clear_line();
+	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);
+    reset_colors();
+    clear_line();
+    gotoxy(INFLINE + 1, 0);
+    clear_line();
+    gotoxy(INFLINE, 0);
+    csprint("Kernel Arguments:", 0x07);
+    gotoxy(INFLINE, 17);
+    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 */
+
+    t_handler_return rv;
+
+    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);
+
+    rv.valid = 0;
+    rv.refresh = 1;
+    rv.reserved = 0;
+    return rv;
+}
+
+int main(void)
+{
+    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, 10, 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 (get_key(stdin, 50) == KEY_NONE)	// Granularity of 100 milliseconds
+    {
+	csprint("Sorry! Time's up.\r\n", 0x07);
+	return 1;
+    }
+    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;
+}
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/display.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/display.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/display.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,36 @@
+/* -*- 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 "cmenu.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;
+}
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/cmenu.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/cmenu.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/cmenu.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,294 @@
+/* -*- 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 <string.h>
+#include <unistd.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      ' '
+#define FILLATTR      NORMALATTR
+#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    '^'		// char to print when more menu items available above
+#define MOREBELOW    'v'		// more items available below
+
+// Attributes of the menu system
+#define MAXMENUS      250	// Maximum number of menu's allowed
+#define MAXMENUSIZE   100	// 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 RADIOMENUCHAR '>'	// > symbol for radio menu?
+#define CHECKED       '\140'	// Check mark
+#define UNCHECKED     '\146'	// 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;
+    int maxrow, minrow, numrows;	// Number of rows in the window
+    int maxcol, mincol, numcols;	// Number of columns in the window
+
+    // Menu box look
+    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(void);	// 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_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);
+
+void reg_ontotaltimeout(t_timeout_handler, unsigned long numcentiseconds);
+void unreg_ontotaltimeout(void);
+
+// 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(void);
+
+// 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
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/com32io.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/com32io.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/com32io.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,78 @@
+/* -*- 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 "tui.h"
+#include "syslnx.h"
+
+com32sys_t inreg, outreg;	// Global register sets for use
+
+void getpos(char *row, char *col, char page)
+{
+    memset(&inreg, 0, sizeof inreg);
+    REG_AH(inreg) = 0x03;
+    REG_BH(inreg) = page;
+    __intcall(0x10, &inreg, &outreg);
+    *row = REG_DH(outreg);
+    *col = REG_DL(outreg);
+}
+
+char inputc(char *scancode)
+{
+    syslinux_idle();		/* So syslinux can perform periodic activity */
+    memset(&inreg, 0, sizeof inreg);
+    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 = 0; // XXX TODO
+    memset(&inreg, 0, sizeof inreg);
+    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)
+{
+    memset(&inreg, 0, sizeof inreg);
+    REG_AH(inreg) = 0x01;
+    REG_CH(inreg) = start;
+    REG_CL(inreg) = end;
+    __intcall(0x10, &inreg, &outreg);
+}
+
+void setvideomode(char mode)
+{
+    memset(&inreg, 0, sizeof inreg);
+    REG_AH(inreg) = 0x00;
+    REG_AL(inreg) = mode;
+    __intcall(0x10, &inreg, &outreg);
+}
+
+// Get char displayed at current position
+unsigned char getcharat(char page)
+{
+    memset(&inreg, 0, sizeof inreg);
+    REG_AH(inreg) = 0x08;
+    REG_BH(inreg) = page;
+    __intcall(0x16, &inreg, &outreg);
+    return REG_AL(outreg);
+}
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/com32io.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/com32io.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/com32io.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,66 @@
+/* -*- 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>
+#include <stdio.h>
+#include <libansi.h>
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+/* 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)
+
+/* BIOS Assisted output routines */
+
+void getpos(char *row, char *col, char page);
+
+char inputc(char *scancode);	// Return ASCII char by val, and scancode by reference
+
+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 unsigned char readbiosb(unsigned int ofs)
+{
+    return *((unsigned char *)MK_PTR(0, ofs));
+}
+
+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
+
+void setvideomode(char mode);	// Set the video mode.
+
+static inline char getvideomode(void)	// Get the current video mode
+{
+    return readbiosb(0x449);
+}
+
+#endif
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/des.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/des.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/des.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,1064 @@
+/*
+ * 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;
+    char *p, packed_keys[8];
+
+    p = 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 = (my_u_char_t *)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);
+}
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/des.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/des.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/des.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,8 @@
+
+#ifndef _DES_H_
+#define _DES_H_
+
+// des crypt
+extern char *crypt(const char *key, const char *salt);
+
+#endif
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/help.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/help.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/help.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,231 @@
+/* -*- 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
+
+int nc, nr; // Number of columns/rows of the screen
+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
+static 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
+static 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
+static void printtext(char *buf, int from)
+{
+    char *f, *t;
+    int nlines, i;
+
+    // clear window to print
+    nlines = nr - HELP_BODY_ROW - HELP_BOTTOM_MARGIN - 1;
+
+    f = findline(buf, from);
+    if (!f)
+	return;			// nothing to print
+    if (*f == '\n')
+	f++;			// start of from+1st line
+    t = f;
+
+    for (i = 0; i < nlines; i++) {
+        gotoxy(HELP_BODY_ROW + i, HELP_LEFT_MARGIN);
+        clear_end_of_line();
+        putchar(SO);
+        gotoxy(HELP_BODY_ROW + i, nc - 1);
+        putch(LEFT_BORDER, 0x07);
+        putchar(SI);
+
+        gotoxy(HELP_BODY_ROW + i, HELP_LEFT_MARGIN);
+        while (*t != '\n') {
+            if (*t == '\0')
+                return;
+            putchar(*t);
+            t++;
+        }
+        putchar('\n');
+        t++;
+    }
+}
+
+void showhelp(const char *filename)
+{
+    char ph;
+    char *title, *text;
+    union {
+	char *buffer;
+	void *vbuf;
+    } buf;			// This is to avoild type-punning issues
+
+    char line[512];
+    size_t size;
+    int scan;
+    int rv, numlines, curr_line;
+
+    if (getscreensize(1, &nr, &nc)) {
+        /* Unknown screen size? */
+        nc = 80;
+        nr = 24;
+    }
+    ph = nr - HELP_BODY_ROW;
+    cls();
+
+    /* Turn autowrap off, to avoid scrolling the menu */
+    printf(CSI "?7l");
+
+    if (filename == NULL) {	// print file contents
+        strcpy(line, "Filename not given");
+        goto puke;
+    }
+
+    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);
+        goto puke;
+    }
+
+    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.
+    numlines = countlines(text);
+    curr_line = 0;
+    scan = KEY_ESC + 1;		// anything except ESCAPE
+
+    /* top, left, bottom, right, attr */
+    drawbox(0, 0, nr - 1, nc - 1, 0x07);
+    while (scan != KEY_ESC) {
+    /* Title */
+    gotoxy(1, (nc - strlen(title)) / 2);
+    fputs(title, stdout);
+    drawhorizline(2, HELP_LEFT_MARGIN - 1, nc - HELP_RIGHT_MARGIN, 0x07, 0);	// dumb==0
+    /* Text */
+	printtext(text, curr_line);
+    gotoxy(HELP_BODY_ROW - 1, nc - HELP_RIGHT_MARGIN);
+	if (curr_line > 0)
+	    putchar(HELP_MORE_ABOVE);
+	else
+	    putchar(' ');
+	gotoxy(nr - HELP_BOTTOM_MARGIN - 1, nc - HELP_RIGHT_MARGIN);
+	if (curr_line < numlines - ph)
+	    putchar(HELP_MORE_BELOW);
+	else
+	    putchar(' ');
+
+    scan = get_key(stdout, 0); // wait for user keypress
+
+	switch (scan) {
+	case KEY_HOME:
+	    curr_line = 0;
+	    break;
+	case KEY_END:
+	    curr_line = numlines;
+	    break;
+	case KEY_UP:
+	    curr_line--;
+	    break;
+	case KEY_DOWN:
+	    curr_line++;
+	    break;
+	case KEY_PGUP:
+	    curr_line -= ph;
+	    break;
+	case KEY_PGDN:
+	    curr_line += ph;
+	    break;
+	default:
+	    break;
+	}
+	if (curr_line > numlines - ph)
+	    curr_line = numlines - ph;
+	if (curr_line < 0)
+	    curr_line = 0;
+    }
+out:
+    cls();
+    return;
+
+puke:
+    gotoxy(HELP_BODY_ROW, HELP_LEFT_MARGIN);
+    fputs(line, stdout);
+    while (1) {
+        scan = get_key(stdin, 0);
+        if (scan == KEY_ESC)
+            break;
+    }
+    goto out;
+}
+
+void runhelp(const char *filename)
+{
+    char fullname[HELPDIRLEN + 16];
+
+	cls();
+    cursoroff();
+    if (helpbasedir[0] != 0) {
+	strcpy(fullname, helpbasedir);
+	strcat(fullname, "/");
+	strcat(fullname, filename);
+	showhelp(fullname);
+    } else
+	showhelp(filename);	// Assume filename is absolute
+}
+
+void runhelpsystem(unsigned int helpid)
+{
+    char filename[15];
+
+    sprintf(filename, "hlp%05d.txt", helpid);
+    runhelp(filename);
+}
+
+void init_help(const char *helpdir)
+{
+    if (helpdir != NULL)
+	strcpy(helpbasedir, helpdir);
+    else
+	helpbasedir[0] = 0;
+}
+
+void close_help(void)
+{
+}
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/help.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/help.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/help.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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 "cmenu.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 1	// Number of lines not use from bottom of screen
+
+#define HELPBOX BOX_SINSIN
+#define HELPDIRLEN  64
+#define HELPPAGE 2
+
+#define HELP_MORE_ABOVE '^'	// to print when more is available above
+#define HELP_MORE_BELOW 'v'	// 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
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/menu.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/menu.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/menu.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,1273 @@
+/* -*- 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 "cmenu.h"
+#include "com32io.h"
+#include <stdlib.h>
+#include <console.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.
+static int getch(void)
+{
+    t_timeout_handler th;
+    int key;
+    unsigned long i;
+
+    // Wait until keypress if no handler specified
+    if ((ms->ontimeout == NULL) && (ms->ontotaltimeout == NULL))
+        return get_key(stdin, 0);
+
+    th = ms->ontimeout;
+    for (;;) {
+        for (i = 0; i < ms->tm_numsteps; i++) {
+            key = get_key(stdin, ms->tm_stepsize);
+            if (key != KEY_NONE)
+                return key;
+
+            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
+        key = th();
+        switch (key) {
+        case CODE_ENTER:    // Pretend user hit enter
+            return KEY_ENTER;
+        case CODE_ESCAPE:   // Pretend user hit escape
+            return KEY_ESC;
+        default:
+            break;
+        }
+    }
+    return KEY_NONE;
+}
+
+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
+}
+
+/* Redraw background and title */
+static void reset_ui(void)
+{
+    uchar tpos;
+
+    cls();
+    clearwindow(ms->minrow, ms->mincol, ms->maxrow, ms->maxcol,
+                ms->fillchar, ms->fillattr);
+
+    tpos = (ms->numcols - strlen(ms->title) - 1) >> 1;  // center it on line
+    gotoxy(ms->minrow, ms->mincol);
+    cprint(ms->tfillchar, ms->titleattr, ms->numcols);
+    gotoxy(ms->minrow, ms->mincol + tpos);
+    csprint(ms->title, ms->titleattr);
+
+    cursoroff();
+}
+
+/*
+ * Print a menu item
+ *
+ * attr[0] is non-hilite attr, attr[1] is highlight attr
+ */
+void printmenuitem(const char *str, uchar * attr)
+{
+    int hlite = NOHLITE;    // Initially no highlighting
+
+    while (*str) {
+        switch (*str) {
+            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]);
+        }
+        str++;
+    }
+}
+
+
+/**
+ * print_line - Print a whole line in a menu
+ * @menu:   current menu to handle
+ * @curr:   index of the current entry highlighted
+ * @top:    top coordinate of the @menu
+ * @left:   left coordinate of the @menu
+ * @x:      index in the menu of curr
+ * @row:    row currently displayed
+ * @radio:  radio item?
+ **/
+static void print_line(pt_menu menu, int curr, uchar top, uchar left,
+                       int x, int row, bool radio)
+{
+    pt_menuitem ci;
+    char fchar[6], lchar[6];    // The first and last char in for each entry
+    const char *str;            // Item string (cf printmenuitem)
+    char sep[MENULEN];          // Separator (OPT_SEP)
+    uchar *attr;                // Attribute
+    int menuwidth = menu->menuwidth + 3;
+
+    if (row >= menu->menuheight)
+        return;
+
+    ci = menu->items[x];
+
+    memset(sep, ms->box_horiz, menuwidth);
+    sep[menuwidth - 1] = 0;
+
+    // Setup the defaults now
+    if (radio) {
+        fchar[0] = '\b';
+        fchar[1] = SO;
+        fchar[2] = (x == curr ? RADIOSEL : RADIOUNSEL);
+        fchar[3] = SI;
+        fchar[4] = '\0';    // Unselected ( )
+        lchar[0] = '\0';    // Nothing special after
+        attr = ms->normalattr;  // Always same attribute
+    } else {
+        lchar[0] = fchar[0] = ' ';
+        lchar[1] = fchar[1] = '\0'; // fchar and lchar are just spaces
+        attr = (x == curr ? ms->reverseattr : ms->normalattr);  // Normal attributes
+    }
+    str = ci->item;     // Pointer to item string
+    switch (ci->action) // set up attr,str,fchar,lchar for everything
+    {
+    case OPT_INACTIVE:
+        if (radio)
+            attr = ms->inactattr;
+        else
+            attr = (x == curr ? ms->revinactattr : ms->inactattr);
+        break;
+    case OPT_SUBMENU:
+        if (radio)
+            break;      // Not supported for radio menu
+        lchar[0] = '>';
+        lchar[1] = 0;
+        break;
+    case OPT_RADIOMENU:
+        if (radio)
+            break;      // Not supported for radio menu
+        lchar[0] = RADIOMENUCHAR;
+        lchar[1] = 0;
+        break;
+    case OPT_CHECKBOX:
+        if (radio)
+            break;      // Not supported for radio menu
+        lchar[0] = '\b';
+        lchar[1] = SO;
+        lchar[2] = (ci->itemdata.checked ? CHECKED : UNCHECKED);
+        lchar[3] = SI;
+        lchar[4] = 0;
+        break;
+    case OPT_SEP:
+        fchar[0] = '\b';
+        fchar[1] = SO;
+        fchar[2] = LEFT_MIDDLE_BORDER;
+        fchar[3] = MIDDLE_BORDER;
+        fchar[4] = MIDDLE_BORDER;
+        fchar[5] = 0;
+        memset(sep, MIDDLE_BORDER, menuwidth);
+        sep[menuwidth - 1] = 0;
+        str = sep;
+        lchar[0] = MIDDLE_BORDER;
+        lchar[1] = RIGHT_MIDDLE_BORDER;
+        lchar[2] = SI;
+        lchar[3] = 0;
+        break;
+    case OPT_EXITMENU:
+        if (radio)
+            break;      // Not supported for radio menu
+        fchar[0] = '<';
+        fchar[1] = 0;
+        break;
+    default:        // Just to keep the compiler happy
+        break;
+    }
+
+    // Wipe area with spaces
+    gotoxy(top + row, left - 2);
+    cprint(ms->spacechar, attr[NOHLITE], menuwidth + 2);
+
+    // Print first part
+    gotoxy(top + row, left - 2);
+    csprint(fchar, attr[NOHLITE]);
+
+    // Print main part
+    gotoxy(top + row, left);
+    printmenuitem(str, attr);
+
+    // Print last part
+    gotoxy(top + row, left + menuwidth - 1);
+    csprint(lchar, attr[NOHLITE]);
+}
+
+// print the menu starting from FIRST
+// will print a maximum of menu->menuheight items
+static void printmenu(pt_menu menu, int curr, uchar top, uchar left, uchar first, bool radio)
+{
+    int x, row;         // x = index, row = position from top
+    int numitems, menuwidth;
+    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->fillchar, ms->shadowattr);
+    drawbox(top - 1, left - 3, top + numitems, left + menuwidth,
+        ms->normalattr[NOHLITE]);
+
+    // Menu title
+    x = (menuwidth - strlen(menu->title) - 1) >> 1;
+    gotoxy(top - 1, left + x);
+    printmenuitem(menu->title, ms->normalattr);
+
+    // All lines in the menu
+    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
+        print_line(menu, curr, top, left, x, row, radio);
+    }
+    // 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);
+    cprint(MOREABOVE, ms->normalattr[NOHLITE], 1);
+    }
+    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);
+    cprint(MOREBELOW, ms->normalattr[NOHLITE], 1);
+    }
+    // Add a scroll box
+    x = ((numitems - 1) * curr) / (menu->numitems);
+    if ((x > 0) && (row == 1)) {
+    gotoxy(top + x, left + menuwidth);
+    csprint("\016\141\017", ms->normalattr[NOHLITE]);
+    }
+    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->fillchar, ms->fillattr); // Clear the shadow
+    clearwindow(top - 1, left - 3, top + numitems, left + menu->menuwidth + 3, ms->fillchar, ms->fillattr); // main window
+}
+
+
+/* Handle one menu */
+static pt_menuitem getmenuoption(pt_menu menu, uchar top, uchar left, uchar startopt, bool radio)
+     // Return item chosen or NULL if ESC was hit.
+{
+    int prev, prev_first, curr, i, first, tmp;
+    int asc = 0;
+    bool redraw = true; // Need to draw the menu the first time
+    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);
+    cprint(ms->spacechar, ms->statusattr[NOHLITE], ms->numcols);
+
+    // Initialise current menu item
+    curr = next_visible(menu, startopt);
+    prev = curr;
+
+    gotoxy(ms->minrow + ms->statline, ms->mincol);
+    cprint(ms->spacechar, ms->statusattr[NOHLITE], ms->numcols);
+    gotoxy(ms->minrow + ms->statline, ms->mincol);
+    printmenuitem(menu->items[curr]->status, ms->statusattr);
+    first = calc_first_early(menu, curr);
+    prev_first = first;
+    while (1)           // Forever
+    {
+    /* Redraw everything if:
+     *  + we need to scroll (take care of scroll bars, ...)
+     *  + menuoption
+     */
+    if (prev_first != first || redraw) {
+        printmenu(menu, curr, top, left, first, radio);
+    } else {
+        /* Redraw only the highlighted entry */
+        print_line(menu, curr, top, left, prev, prev - first, radio);
+        print_line(menu, curr, top, left, curr, curr - first, radio);
+    }
+    redraw = false;
+    prev = curr;
+    prev_first = first;
+    ci = menu->items[curr];
+    asc = getch();
+    switch (asc) {
+        case KEY_CTRL('L'):
+        redraw = true;
+        break;
+    case KEY_HOME:
+        curr = next_visible(menu, 0);
+        first = calc_first_early(menu, curr);
+        break;
+    case KEY_END:
+        curr = prev_visible(menu, numitems - 1);
+        first = calc_first_late(menu, curr);
+        break;
+    case KEY_PGDN:
+        for (i = 0; i < 5; i++)
+        curr = next_visible(menu, curr + 1);
+        first = calc_first_late(menu, curr);
+        break;
+    case KEY_PGUP:
+        for (i = 0; i < 5; i++)
+        curr = prev_visible(menu, curr - 1);
+        first = calc_first_early(menu, curr);
+        break;
+    case KEY_UP:
+        curr = prev_visible(menu, curr - 1);
+        if (curr < first)
+        first = calc_first_early(menu, curr);
+        break;
+    case KEY_DOWN:
+        curr = next_visible(menu, curr + 1);
+        if (!isvisible(menu, first, curr))
+        first = calc_first_late(menu, curr);
+        break;
+    case KEY_LEFT:
+    case KEY_ESC:
+        return NULL;
+        break;
+    case KEY_RIGHT:
+    case KEY_ENTER:
+        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, radio);
+        }
+        if (hr.valid)
+            return ci;
+        } else
+        return ci;
+        break;
+    case SPACECHAR:
+        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, radio);
+        }
+        }
+        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], asc);
+
+            /* The handler may have changed the UI, reset it on exit */
+            reset_ui();
+            // 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, radio);
+        }
+        break;
+    }
+    // Update status line
+    /* Erase the previous status */
+    gotoxy(ms->minrow + ms->statline, ms->mincol);
+    cprint(ms->spacechar, ms->statusattr[NOHLITE], ms->numcols);
+    /* Print the new status */
+    gotoxy(ms->minrow + ms->statline, ms->mincol);
+    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, false);
+    else            // menutype == RADIOMENU
+    opt = getmenuoption(cmenu, top, left, startopt, true);
+
+    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); // 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(void)
+{
+    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;
+
+    fix_submenus();     // Fix submenu numbers incase nick names were used
+
+    /* Turn autowrap off, to avoid scrolling the menu */
+    printf(CSI "?7l");
+
+    // Setup screen for menusystem
+    reset_ui();
+
+    // 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
+    cls();
+    gotoxy(ms->minrow, ms->mincol);
+    cursoron();
+
+    // 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
+    if (getscreensize(1, &ms->numrows, &ms->numcols)) {
+        /* Unknown screen size? */
+        ms->numcols = 80;
+        ms->numrows = 24;
+    }
+    ms->minrow = ms->mincol = 0;
+    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;
+
+    console_ansi_raw();
+
+    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_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)
+{
+    int nr, nc;
+
+    if ((top > bot) || (left > right))
+    return;         // Sorry no change will happen here
+
+    if (getscreensize(1, &nr, &nc)) {
+        /* Unknown screen size? */
+        nr = 80;
+        nc = 24;
+    }
+    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(void)
+{
+    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(void)
+{
+    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(void)       // 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;
+
+    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);
+}
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/passwords.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/passwords.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/passwords.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,159 @@
+/* -*- 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(void)
+{
+    int i;
+
+    for (i = 0; i < numusers; i++)
+	if (userdb[i] != NULL)
+	    free(userdb[i]);
+    numusers = 0;
+}
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/passwords.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/passwords.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/passwords.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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(void);
+
+#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
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/syslnx.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/syslnx.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/syslnx.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,65 @@
+/* -*- 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 <core.h>
+#include <graphics.h>
+#include "syslnx.h"
+#include <syslinux/config.h>
+#include <syslinux/video.h>
+
+com32sys_t inreg, outreg;	// Global registers for this module
+
+void runsyslinuxcmd(const char *cmd)
+{
+    char *bounce;
+
+    bounce = lmalloc(strlen(cmd) + 1);
+    if (!bounce)
+	return;
+
+    strcpy(bounce, cmd);
+    load_kernel(bounce);
+}
+
+void gototxtmode(void)
+{
+    syslinux_force_text_mode();
+}
+
+void syslinux_idle(void)
+{
+    __idle();
+}
+
+unsigned int getversion(char *deriv, unsigned int *numfun)
+{
+    if (deriv)
+	*deriv = __syslinux_version.filesystem;
+    if (numfun)
+	*numfun = __syslinux_version.max_api;
+    return __syslinux_version.version;
+}
+
+char issyslinux(void)
+{
+    return !!getversion(NULL, NULL);
+}
+
+void runsyslinuximage(const char *cmd, long ipappend)
+{
+    (void)ipappend;		// XXX: Unused?!
+
+    getversion(NULL, NULL);
+    runsyslinuxcmd(cmd);
+}
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/syslnx.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/syslnx.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/syslnx.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/tui.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/tui.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/tui.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,258 @@
+/* -*- 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>
+#include "com32io.h"
+
+com32sys_t inreg, outreg;	// Global register sets for use
+
+char bkspstr[] = " \b$";
+char eolstr[] = "\n$";
+
+// 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 int c;
+    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 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
+
+    getpos(&row, &col, 0);	// 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);
+	csprint(str, GETSTRATTR);
+    }
+    while (1) {			// Do forever
+	c = get_key(stdin, 0);
+	if (c == KEY_ENTER)
+	    break;		// User hit Enter getout of loop
+	if (c == KEY_ESC)	// 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 (c) {
+	case KEY_HOME:
+	    p = str;
+	    break;
+	case KEY_END:
+	    p = last;
+	    break;
+	case KEY_LEFT:
+	    if (p > str)
+		p--;
+	    break;
+	case KEY_CTRL(KEY_LEFT):
+	    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 KEY_RIGHT:
+	    if (p < last)
+		p++;
+	    break;
+	case KEY_CTRL(KEY_RIGHT):
+	    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 KEY_DEL:
+	case KEY_DELETE:
+	    q = p;
+	    while (*(q + 1)) {
+		*q = *(q + 1);
+		q++;
+	    }
+	    if (last > str)
+		last--;
+	    fudge = 1;
+	    break;
+	case KEY_INSERT:
+	    insmode = 1 - insmode;	// Switch mode
+	    if (insmode == 0)
+		setcursorshape(1, 7);	// Block cursor
+	    else
+		setcursorshape(6, 7);	// Normal cursor
+	    break;
+	case KEY_BACKSPACE:		// 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 KEY_CTRL('U'):	/* 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);
+	    csprint(str, GETSTRATTR);
+	    if (fudge > 0)
+		cprint(' ', GETSTRATTR, fudge);
+	    gotoxy(row, col + (p - str));
+	}
+    } /* while */
+    *p = '\0';
+    if (password == 0)
+	csprint("\r\n", GETSTRATTR);
+    setcursorshape(start, end);	// Block cursor
+    // If user hit ESCAPE so return without any changes
+    if (c != KEY_ESC)
+	strcpy(stra, str);
+    free(str);
+}
+
+//////////////////////////////Box Stuff
+
+// Draw box and lines
+void drawbox(const char top, const char left, const char bot,
+	     const char right, const char attr)
+{
+    unsigned char x;
+	putchar(SO);
+    // Top border
+    gotoxy(top, left);
+    putch(TOP_LEFT_CORNER_BORDER, attr);
+    cprint(TOP_BORDER, attr, right - left - 1);
+    putch(TOP_RIGHT_CORNER_BORDER, attr);
+    // Bottom border
+    gotoxy(bot, left);
+    putch(BOTTOM_LEFT_CORNER_BORDER, attr);
+    cprint(BOTTOM_BORDER, attr, right - left - 1);
+    putch(BOTTOM_RIGHT_CORNER_BORDER, attr);
+    // Left & right borders
+    for (x = top + 1; x < bot; x++) {
+	gotoxy(x, left);
+	putch(LEFT_BORDER, attr);
+	gotoxy(x, right);
+	putch(RIGHT_BORDER, attr);
+    }
+	putchar(SI);
+}
+
+void drawhorizline(const char top, const char left, const char right,
+		   const char attr, char dumb)
+{
+    unsigned char start, end;
+    if (dumb == 0) {
+	start = left + 1;
+	end = right - 1;
+    } else {
+	start = left;
+	end = right;
+    }
+    gotoxy(top, start);
+	putchar(SO);
+    cprint(MIDDLE_BORDER, attr, end - start + 1);
+    if (dumb == 0) {
+	gotoxy(top, left);
+	putch(MIDDLE_BORDER, attr);
+	gotoxy(top, right);
+	putch(MIDDLE_BORDER, attr);
+    }
+	putchar(SI);
+}
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/tui.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/tui.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/libmenu/tui.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,75 @@
+/* -*- 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 <getkey.h>
+#include <consoles.h>
+#include "syslnx.h"
+#include "com32io.h"
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define SO '\016'
+#define SI '\017'
+
+#define TOP_LEFT_CORNER_BORDER '\154'
+#define TOP_BORDER '\161'
+#define TOP_RIGHT_CORNER_BORDER '\153'
+#define BOTTOM_LEFT_CORNER_BORDER '\155'
+#define BOTTOM_BORDER '\161'
+#define BOTTOM_RIGHT_CORNER_BORDER '\152'
+#define LEFT_BORDER '\170'
+#define RIGHT_BORDER '\170'
+#define LEFT_MIDDLE_BORDER '\164'
+#define MIDDLE_BORDER '\161'
+#define RIGHT_MIDDLE_BORDER '\165'
+
+#define BELL 0x07
+#define GETSTRATTR 0x07
+
+// 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);
+}
+
+void drawbox(const char, const char, const char, const char,
+	     const char);
+
+// 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(const char, const char, const char, const char,
+		   const char dumb);
+
+#endif
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/menugen.py
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/menugen.py	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/menugen.py	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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(list(self.types.keys()))
+       self.vattrs = " OR ".join([x for x in list(self.entry.keys()) if x[0] != "_"])
+       self.mattrs = " OR ".join([x for x in list(self.menu.keys()) if x[0] != "_"])
+
+   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 name not in self.entry:
+          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 value not in self.types:
+          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 name not in self.menu:
+          return "Error: Unknown keyword %s" % name
+       self.menu[name] = value
+       self.menu["_updated"] = 1
+       return ""
+
+   def set_system(self,name,value):
+       if name not in self.system:
+          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([_f for _f in parts if _f])
+       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 x not in self.templates: 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()
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/password
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/password	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/password	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/simple.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/simple.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/simple.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,82 @@
+/* -*- 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 "cmenu.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;
+}
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/test.menu
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/test.menu	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/test.menu	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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
Index: bootcd/isolinux/syslinux-6.03/com32/cmenu/test2.menu
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/cmenu/test2.menu	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/cmenu/test2.menu	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -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
