Rewritten advanced menuing system from Murali.
authorhpa <hpa>
Thu, 28 Apr 2005 23:12:09 +0000 (23:12 +0000)
committerhpa <hpa>
Thu, 28 Apr 2005 23:12:09 +0000 (23:12 +0000)
35 files changed:
menu/CHANGES [new file with mode: 0644]
menu/HISTORY [new file with mode: 0644]
menu/MANUAL [new file with mode: 0644]
menu/Makefile
menu/README
menu/TODO [new file with mode: 0644]
menu/biosio.c [deleted file]
menu/biosio.h [deleted file]
menu/com16.ld [deleted file]
menu/complex.c
menu/heap.c [deleted file]
menu/heap.h [deleted file]
menu/libmenu/com32io.c [new file with mode: 0644]
menu/libmenu/com32io.h [new file with mode: 0644]
menu/libmenu/des.c [new file with mode: 0644]
menu/libmenu/des.h [new file with mode: 0644]
menu/libmenu/help.c [new file with mode: 0644]
menu/libmenu/help.h [new file with mode: 0644]
menu/libmenu/menu.c [moved from menu/menu.c with 59% similarity]
menu/libmenu/menu.h [moved from menu/menu.h with 54% similarity]
menu/libmenu/passwords.c [new file with mode: 0644]
menu/libmenu/passwords.h [new file with mode: 0644]
menu/libmenu/scancodes.h [new file with mode: 0644]
menu/libmenu/syslnx.c [new file with mode: 0644]
menu/libmenu/syslnx.h [new file with mode: 0644]
menu/libmenu/tui.c [new file with mode: 0644]
menu/libmenu/tui.h [new file with mode: 0644]
menu/main.c [deleted file]
menu/password [new file with mode: 0644]
menu/simple.c
menu/startup.S16 [deleted file]
menu/string.c [deleted file]
menu/string.h [deleted file]
menu/syslinux.c [deleted file]
menu/syslinux.h [deleted file]

diff --git a/menu/CHANGES b/menu/CHANGES
new file mode 100644 (file)
index 0000000..3998f1b
--- /dev/null
@@ -0,0 +1,12 @@
+Changes in v1.1
+---------------
+* Additional handler type: Keys handler
+* Menuitem handlers now have a return value of type t_handler_return.
+  For all simple cases, you just return ACTION_VALID or ACTION_INVALID
+  (For some types of menu items, handlers are ignored, and for 
+   others the return value is ignored)
+* add_menu takes an extra argument (to better control memory footprint)
+  You can just set it to -1 to choose the default value
+* Now the menu system support long menu's using scroll bars.
+* Support for passwords and context sensitive help is added.
+
diff --git a/menu/HISTORY b/menu/HISTORY
new file mode 100644 (file)
index 0000000..06d3360
--- /dev/null
@@ -0,0 +1,20 @@
+
+GCC & 32-bit code
+-----------------
+Due to the limitations of the COM file format,
+(64KB limit on memory footprint) the code has been changed 
+so that the code compiles to a 32-bit COMBOOT program.
+Since the code makes use of BIOS calls, this code cannot be
+compiled into a format which can execute under Linux. As a 
+side effect, there is no nice way to debug this code. In order
+to debug this code, you will have to run the code under syslinux.
+
+GCC & 16-bit code
+-----------------
+The code was ported to GCC by Peter Anvin. 
+
+OpenWatcom & 16-bit code
+------------------------
+Originally this code was written for the Openwatcom compiler
+and generated .COM files, which could execute under DOS as well as
+SYSLINUX. 
diff --git a/menu/MANUAL b/menu/MANUAL
new file mode 100644 (file)
index 0000000..50652fb
--- /dev/null
@@ -0,0 +1,330 @@
+          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_sep();
+  add_item("checkbox,"Checkbox Info",OPT_CHECKBOX,NULL,CHECKED);
+  add_item("Exit ","Status String",OPT_EXITMENU,NULL,0);
+  //   "any string" not used by the menu system, useful for storing kernel names
+  //   NUM = index of submenu if OPT_SUBMENU, 
+  //         0/1 default checked state if OPT_CHECKBOX
+  //         unused otherwise.
+</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. Currently the code compiles to a .COM file which 
+has a 64K limit on memory used. 
+
+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. This pointer is just
+stored. In case of a radiomenu this points to the menuitem chosen (Dont 
+forget to typecase this pointer to (t_menuitem *) when reading this info).
+
+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. For a RADIOMENU it should be the
+index of the menu which contains all the options (All items in that menu
+should 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
+</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 bab8f48..ea75350 100644 (file)
@@ -1,52 +1,79 @@
-gcc_ok   = $(shell if $(CC) $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \
+#ident "$Id$"
+## -----------------------------------------------------------------------
+##   
+##   Copyright 2001-2005 H. Peter Anvin - All Rights Reserved
+##
+##   This program is free software; you can redistribute it and/or modify
+##   it under the terms of the GNU General Public License as published by
+##   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+##   Boston MA 02111-1307, USA; either version 2 of the License, or
+##   (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## samples for syslinux users
+##
+
+gcc_ok   = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \
                   then echo $(1); else echo $(2); fi)
 
 M32     := $(call gcc_ok,-m32,)
-ALIGN   := $(call gcc_ok,-falign-functions=0 -falign-jumps=0 -falign-loops=0,-malign-functions=0 -malign-jumps=0 -malign-loops=0)
 
-CC     = gcc
-CFLAGS  =  $(M32) -funsigned-char -g -W -Wall -march=i386 $(ALIGN) -Os
-AR      = ar
-AS      = as
-LD      = ld -m elf_i386
-OBJCOPY = objcopy
-RANLIB  = ranlib
+CC         = gcc
+LD         = ld -m elf_i386
+AR        = ar
+NASM      = nasm
+RANLIB    = ranlib
+COM32DIR   = ../com32
+LUDIR      = $(COM32DIR)/libutil
+LDIR       = $(COM32DIR)/lib
+CFLAGS     = $(M32) -mregparm=3 -DREGPARM=3 -W -Wall -march=i386 -Os -fomit-frame-pointer -I$(LUDIR)/include -I$(COM32DIR)/include  -Ilibmenu -D__COM32__
+SFLAGS     = -D__COM32__ -march=i386
+LDFLAGS    = -T $(LDIR)/com32.ld 
+OBJCOPY    = objcopy
+LIBGCC    := $(shell $(CC) --print-libgcc)
 
-LIBMENU = main.o16 biosio.o16 string.o16 menu.o16 syslinux.o16 heap.o16
+LIBS      = libmenu/libmenu.a $(LUDIR)/libutil_com.a $(LDIR)/libcom32.a $(LIBGCC)
 
-MENUS   = simple.com complex.com
+LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \
+       libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o 
 
-.SUFFIXES: .c .s .s16 .o16 .elf .com
+MENUS = $(patsubst %.c,%.c32,$(wildcard *.c))
 
-.c.s:
-       $(CC) $(CFLAGS) -MMD -S -o $@ $<
+.SUFFIXES: .S .c .o .elf .c32 
 
-.s.s16:
-       echo '.code16gcc' | cat - $< > $@
+.PRECIOUS: %.o
+%.o: %.S
+       $(CC) $(SFLAGS) -c -o $@ $<
 
-.s16.o16:
-       $(AS) -o $@ $<
+.PRECIOUS: %.o
+%.o: %.c %.h
+       $(CC) $(CFLAGS) -c -o $@ $<
 
-.elf.com:
-       $(OBJCOPY) -O binary $< $@
-
-%.elf: %.o16 startup.o16 com16.ld libmenu.a
-       $(LD) -T com16.ld -o $@ startup.o16 $< libmenu.a
+.PRECIOUS: %.elf 
+%.elf: %.o $(LIBS)
+       $(LD) $(LDFLAGS) -o $@ $^ 
 
-all : $(MENUS)
+%.c32: %.elf
+       $(OBJCOPY) -O binary $< $@
 
-startup.s16: startup.S16
-       $(CC) $(CFLAGS) -x assembler-with-cpp -E -o $@ $<
+all: menus
 
-libmenu.a: $(LIBMENU)
+libmenu/libmenu.a: $(LIBMENU)
        -rm -f $@
        $(AR) cq $@ $^
        $(RANLIB) $@
 
-clean:
-       -rm -f *.s *.s16 *.o16 *.elf *.com *.a *.d
+tidy:
+       rm -f *.o *.lo *.a *.lst *.elf libmenu/*.o libmenu/*.a
+
+clean: tidy
+       rm -f *.lss *.c32 *.com
 
 spotless: clean
-       -rm -f *~ \#* .\#*
+       rm -f *~ \#*
+
+menus: $(MENUS)
 
--include *.d
+install:       # Don't install samples
index dd22142..66116e9 100644 (file)
@@ -2,17 +2,18 @@
           ---------------------------------
 
 This is a menu system written by Murali Krishnan Ganapathy and ported
-from OpenWatcom to gcc by HPA.
+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; then add the name with a .com
+for your own menu configuration file; then add the name with a .c32
 extension to the MENUS list in the Makefile.
 
-The resulting code runs both under DOS as well as SYSLINUX. A trivial
-memory allocation routine is implemented, to reduce the memory footprint 
-of this utility.
+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, 
@@ -20,7 +21,10 @@ Menu Features currently supported are:
 * disabled items,
 * checkboxes,
 * invisible items (useful for dynamic menus), and
-* Radio menus
+* Radio menus,
+* Context sensitive help
+* Authenticated users 
+* Editing commands associated with items
 
 The keys used are:
 
@@ -49,11 +53,17 @@ customizable. Some features include:
 * 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 Handler
+* 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
@@ -75,6 +85,9 @@ Credits
 -------
 * The Watcom developers and Peter Anvin for figuring out an OS 
   independent startup code.
+* Thomas for porting the crypt function and removing all C library 
+  dependencies
+* Peter Anvin for porting the code to GCC 
 
 - Murali (gmurali+guicd@cs.uchicago.edu)
 
diff --git a/menu/TODO b/menu/TODO
new file mode 100644 (file)
index 0000000..59e653c
--- /dev/null
+++ b/menu/TODO
@@ -0,0 +1,9 @@
+* Read menu structure from config files
+  - This will eliminate the need for recompiling the code, especially 
+    for the simple menus
+* Features to add
+  - Parse commandline arguments
+* Help support
+  - Beef up help.c so that the text file can be larger than one page, and 
+    user can scroll down page to view extra text.
+
diff --git a/menu/biosio.c b/menu/biosio.c
deleted file mode 100644 (file)
index 9927ffb..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/* -*- c -*- ------------------------------------------------------------- *
- *   
- *   Copyright 2004 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 "biosio.h"
-
-/*
- * Note: don't use "r" or "g" for 8-bit values.  Some versions of gcc
- * will actually try to generate x86-64 registers that way!  Use
- * "abcd" or "abcdmi", respectively.  Newer gccs have the newer "q"
- * and "Q" constraints, but older gccs don't know those.
- */
-
-/* BIOS Assisted output routines */
-
-void bios_int10(void)
-{
-  asm volatile("pushl %ebp ; int $0x10 ; popl %ebp");
-}
-
-/* Print character and attribute at cursor */
-static inline void asm_cprint(char chr, char attr, int times, char disppage)
-{
-    asm volatile("movb $0x09,%%ah ; call bios_int10"
-                : "+a" (chr) : "b" (attr + (disppage << 8)), "c" (times));
-}
-
-void cprint(char chr,char attr,int times,char disppage)
-{
-    asm_cprint(chr,attr,times,disppage);
-}
-
-static inline void asm_setdisppage(char num)
-{
-    asm volatile("movb $0x05,%%ah ; call bios_int10"
-                : "+a" (num));
-}
-
-void setdisppage(char num) // Set the display page to specified number
-{
-    asm_setdisppage(num);
-}
-
-static inline char asm_getdisppage(void)
-{
-    char page;
-    
-    asm("movb $0x0f,%%ah ; "
-       "call bios_int10 ; "
-       "movb %%bh,%0"
-       : "=abcdm" (page) : : "eax");
-    return page;
-}
-
-char getdisppage() // Get current display page 
-{
-    return asm_getdisppage();
-}
-
-static inline void asm_getpos(char *row, char *col, char page)
-{
-    asm("movb %2,%%bh ; "
-       "movb $0x03,%%ah ; "
-       "call bios_int10 ; "
-       "movb %%dh,%0 ; "
-       "movb %%dl,%1"
-       : "=m" (*row), "=m" (*col)
-       : "abcdmi" (page)
-       : "eax", "ebx", "ecx", "edx");
-}
-
-void getpos(char * row, char * col, char page)
-{
-    asm_getpos(row,col,page);
-}
-
-static inline void asm_gotoxy(char row,char col, char page)
-{
-    asm volatile("movb %1,%%bh ; "
-                "movb $0x02,%%ah ; "
-                "call bios_int10"
-                : : "d" ((row << 8) + col), "abcdmi" (page)
-                : "eax", "ebx");
-}
-
-void gotoxy(char row,char col, char page)
-{
-    asm_gotoxy(row,col,page);
-}
-
-static inline unsigned char asm_sleep(unsigned int milli)
-{ // ah = 86, int 15, cx:dx = microseconds
-  // mul op16 : dx:ax = ax * op16
-  unsigned char ans;
-  asm volatile ("mul  %%cx; "
-               "xchg %%dx, %%ax; "
-               "movw %%ax, %%cx; "
-               "movb $0x86, %%ah;"
-               "int $0x15;"
-               "setnc %0"
-               : "=r" (ans) 
-               : "a" (milli), "c" (1000)
-               : "edx");
-  return ans;
-}
-
-unsigned char sleep(unsigned int msec)
-{
- return asm_sleep(msec);
-}
-
-void asm_beep()
-{
-  // For a beep the page number (bh) does not matter, so set it to zero
-  asm volatile("movw $0x0E07, %%ax;"
-              "xor  %%bh,%%bh;"
-              "call bios_int10"
-              : : : "eax","ebx");
-}
-
-void beep()
-{
-  asm_beep();
-}
-
-static inline void asm_putchar(char x, char attr,char page)
-{
-    asm volatile("movb %1,%%bh;"
-                "movb %2,%%bl;"
-                "movb $0x09,%%ah;"
-                "movw $0x1, %%cx;"
-                "call bios_int10"
-                : "+a" (x)
-                : "abcdmi" (page), "acdmi" (attr)
-                : "ebx", "ecx");
-}
-
-void putch(char x, char attr, char page)
-{
-  asm_putchar(x,attr,page);
-}
-
-void scrollup()
-{
-  unsigned short dx = (getnumrows()<< 8) + getnumcols();
-  
-  asm volatile("movw $0x0601, %%ax;"
-              "movb $0x07, %%bh;"
-              "xor %%cx, %%cx;"
-              "call bios_int10"
-              : "+d" (dx)
-              : : "eax","ebx","ecx");
-}
-
-/* Print a C string (NUL-terminated) */
-void csprint(const char *str,char attr)
-{
-    char page = asm_getdisppage();
-    char newattr=0,cha,chb;
-    char row,col;
-
-    asm_getpos(&row,&col,page);
-    while ( *str ) {
-      switch (*str) 
-       {
-       case '\b':
-         --col;
-         break;
-       case '\n':
-         ++row;
-         break;
-       case '\r':
-         col=0;
-         break;
-       case BELL: // Bell Char
-         asm_beep();
-         break;
-       case CHRELATTR: // change attribute (relatively)
-       case CHABSATTR: // change attribute (absolute)
-         cha = *(str+1);
-         chb = *(str+2);
-         if ((((cha >= '0') && (cha <= '9')) || 
-              ((cha >= 'A') && (cha <= 'F'))) &&
-             (((chb >= '0') && (chb <= '9')) || 
-              ((chb >= 'A') && (chb <= 'F')))) // Next two chars are legal
-           {
-             if ((cha >= 'A') && (cha <= 'F'))
-               cha = cha - 'A'+10;
-             else cha = cha - '0';
-             if ((chb >= 'A') && (chb <= 'F'))
-               chb = chb - 'A'+10;
-             else chb = chb - '0';
-             newattr = (cha << 4) + chb;
-             attr = (*str == CHABSATTR ? newattr : attr ^ newattr);
-             str += 2; // Will be incremented again later
-           }
-         break;
-       default:
-         asm_putchar(*str, attr, page);
-         ++col;
-       }
-      if (col > getnumcols())
-       {
-         ++row;
-         col=0;
-       }
-      if (row > getnumrows())
-       {
-         scrollup();
-         row= getnumrows();
-       }
-      asm_gotoxy(row,col,page);
-      str++;
-    }
-}
-
-void clearwindow(char top, char left, char bot, char right, char page, char fillchar, char fillattr)
-{
-    char x;
-    for (x=top; x < bot+1; x++)
-    {
-        gotoxy(x,left,page);
-        asm_cprint(fillchar,fillattr,right-left+1,page);
-    }
-}
-
-void cls(void)
-{
-    gotoxy(0,0,getdisppage());
-    asm_cprint(' ',0x07,getnumrows()*getnumcols(),getdisppage());
-}
-
-char asm_inputc(char *scancode)
-{
-  unsigned short ax;
-
-  asm volatile("movb $0x10,%%ah ; "
-              "int $0x16"
-              : "=a" (ax));
-  
-  if (scancode)
-      *scancode = (ax >> 8);
-  
-  return (char)ax;
-}
-   
-char inputc(char * scancode)
-{
-    return asm_inputc(scancode);
-}
-
-static inline void asm_cursorshape(char start, char end)
-{
-    asm volatile("movb $0x01,%%ah ; int $0x10"
-                : : "c" ((start << 8) + end) : "eax");
-}
-
-void cursoroff(void)
-{
-    asm_cursorshape(32,32);
-}
-
-void cursoron(void)
-{
-    asm_cursorshape(6,7);
-}
-
-char bkspstr[] = " \b$";
-char eolstr[] = "\n$";
-
-static inline char asm_getchar(void)
-{
-    char v;
-    
-    /* Get key without echo */
-    asm("movb $0x08,%%ah ; int $0x21" : "=a" (v));
-    
-    return v;
-}
-
-#define GETSTRATTR 0x07
-
-// Reads a line of input from stdin. Replace CR with NUL byte
-void getstring(char *str, unsigned int size)
-{
-    char c;
-    char *p = str;
-    char page = asm_getdisppage();
-    char row,col;
-
-    while ( (c = asm_getchar()) != '\r' ) {
-       switch (c) {
-       case '\0':              /* Extended char prefix */
-           asm_getchar();      /* Drop */
-           break;
-       case '\b':
-           if ( p > str ) {
-               p--;
-               csprint("\b \b",GETSTRATTR);
-           }
-           break;
-       case '\x15':            /* Ctrl-U: kill input */
-           while ( p > str ) {
-               p--;
-               csprint("\b \b",GETSTRATTR);
-           }
-           break;
-       default:
-           if ( c >= ' ' && (unsigned int)(p-str) < size-1 ) {
-             *p++ = c;
-             asm_getpos(&row,&col,page);
-             asm_putchar(c, GETSTRATTR, page);
-             asm_gotoxy(row,col+1,page);
-           }
-           break;
-       }
-    }
-    *p = '\0';
-    csprint("\r\n",GETSTRATTR);
-}
-
-static inline void asm_setvideomode(char mode)
-{
-    /* This BIOS function is notoriously register-dirty,
-       so push/pop around it */
-    asm volatile("pushal ; xorb %%ah,%%ah ; int $0x10 ; popal"
-                : : "a" (mode) );
-}
-
-void setvideomode(char mode)
-{
-    asm_setvideomode(mode);
-}
-
-static inline unsigned char asm_checkkbdbuf()
-{
-  unsigned char ans;
-
-  asm volatile("movb $0x11, %%ah;"
-              "int $0x16 ;"
-              "setnz %0;"
-              : "=abcdm" (ans)
-              : 
-              : "eax");
-  return ans;
-}
-
-unsigned char checkkbdbuf()
-{
-  return asm_checkkbdbuf();
-}
-
-void clearkbdbuf()
-{
-  while (asm_checkkbdbuf()) asm_inputc(NULL);
-}
diff --git a/menu/biosio.h b/menu/biosio.h
deleted file mode 100644 (file)
index 0e095a0..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- c -*- ------------------------------------------------------------- *
- *   
- *   Copyright 2004 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 __BIOSIO_H__
-#define __BIOSIO_H__
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
-#define BELL 0x07
-// CHRELATTR = ^N, CHABSATTR = ^O
-#define CHABSATTR 15 
-#define CHRELATTR 14
-
-/* BIOS Assisted output routines */
-
-void csprint(const char *str, char attr); // Print a C str (NUL-terminated)
-
-void cprint(char chr,char attr,int times,char disppage); // Print a char 
-
-void setdisppage(char num); // Set the display page to specified number
-
-char getdisppage(); // Get current display page 
-
-void clearwindow(char top, char left, char bot, char right, 
-                char page, char fillchar, char fillattr);
-
-void cls(void);                        /* Clears the entire current screen page */
-
-void gotoxy(char row,char col, char page);
-
-void getpos(char * row, char * col, char page);
-
-char inputc(char * scancode); // Return ASCII char by val, and scancode by reference
-
-
-void putch(char x, char attr, char page); // Print one char
-
-void cursoroff(void);          /* Turns on cursor */
-
-void cursoron(void);           /* Turns off cursor */
-
-void getstring(char *str, unsigned int size);
-
-static inline unsigned char readbiosb(unsigned short addr)
-{
-    unsigned char v;
-
-    asm("movw %2,%%fs ; "
-       "movb %%fs:%1,%0"
-       : "=abcd" (v)
-       : "m" (*(unsigned char *)(unsigned int)addr),
-       "r" ((unsigned short)0));
-    return v;
-}
-static inline char getnumrows()
-{
-    return readbiosb(0x484);
-}
-
-static inline char getnumcols(void)
-{
-    return readbiosb(0x44a);
-}
-
-void scrollup(); //Scroll up display screen by one line
-void setvideomode(char mode); // Set the video mode.
-
-unsigned char sleep(unsigned int msec); // Sleep for specified time
-
-void beep(); // A Bell
-
-unsigned char checkkbdbuf(); // Check to see if there is kbd buffer is non-empty?
-
-void clearkbdbuf(); // Clear the kbd buffer (how many chars removed?)
-
-#endif
diff --git a/menu/com16.ld b/menu/com16.ld
deleted file mode 100644 (file)
index 8154f2a..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* Simple linker script to pre-link DOS .com files */
-
-OUTPUT_FORMAT("elf32-i386", "elf32-i386",
-             "elf32-i386")
-OUTPUT_ARCH(i386)
-ENTRY(_start)
-SECTIONS
-{
-  /* Read-only sections, merged into text segment: */
-  . = 0x100;
-  .interp         : { *(.interp) }
-  .hash           : { *(.hash) }
-  .dynsym         : { *(.dynsym) }
-  .dynstr         : { *(.dynstr) }
-  .gnu.version    : { *(.gnu.version) }
-  .gnu.version_d  : { *(.gnu.version_d) }
-  .gnu.version_r  : { *(.gnu.version_r) }
-  .rel.dyn        :
-    {
-      *(.rel.init)
-      *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
-      *(.rel.fini)
-      *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
-      *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
-      *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
-      *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
-      *(.rel.ctors)
-      *(.rel.dtors)
-      *(.rel.got)
-      *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
-    }
-  .rela.dyn       :
-    {
-      *(.rela.init)
-      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
-      *(.rela.fini)
-      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
-      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
-      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
-      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
-      *(.rela.ctors)
-      *(.rela.dtors)
-      *(.rela.got)
-      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
-    }
-  .rel.plt        : { *(.rel.plt) }
-  .rela.plt       : { *(.rela.plt) }
-  .init           :
-  {
-    KEEP (*(.init))
-  } =0x90909090
-  .plt            : { *(.plt) }
-  .text           :
-  {
-    *(.text .stub .text.* .gnu.linkonce.t.*)
-    /* .gnu.warning sections are handled specially by elf32.em.  */
-    *(.gnu.warning)
-  } =0x90909090
-  .fini           :
-  {
-    KEEP (*(.fini))
-  } =0x90909090
-  PROVIDE (__etext = .);
-  PROVIDE (_etext = .);
-  PROVIDE (etext = .);
-  .rodata             : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
-  .rodata1            : { *(.rodata1) }
-  .eh_frame_hdr       : { *(.eh_frame_hdr) }
-  .eh_frame           : { KEEP (*(.eh_frame)) }
-  .gcc_except_table   : { *(.gcc_except_table) }
-  /* For backward-compatibility with tools that don't support the
-     *_array_* sections below, our glibc's crt files contain weak
-     definitions of symbols that they reference.  We don't want to use
-     them, though, unless they're strictly necessary, because they'd
-     bring us empty sections, unlike PROVIDE below, so we drop the
-     sections from the crt files here.  */
-  /DISCARD/ : {
-      */crti.o(.init_array .fini_array .preinit_array)
-      */crtn.o(.init_array .fini_array .preinit_array)
-  }
-  /* Ensure the __preinit_array_start label is properly aligned.  We
-     could instead move the label definition inside the section, but
-     the linker would then create the section even if it turns out to
-     be empty, which isn't pretty.  */
-  . = ALIGN(32 / 8);
-  PROVIDE (__preinit_array_start = .);
-  .preinit_array     : { *(.preinit_array) }
-  PROVIDE (__preinit_array_end = .);
-  PROVIDE (__init_array_start = .);
-  .init_array     : { *(.init_array) }
-  PROVIDE (__init_array_end = .);
-  PROVIDE (__fini_array_start = .);
-  .fini_array     : { *(.fini_array) }
-  PROVIDE (__fini_array_end = .);
-  .data           :
-  {
-    *(.data .data.* .gnu.linkonce.d.*)
-    SORT(CONSTRUCTORS)
-  }
-  .data1          : { *(.data1) }
-  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
-  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
-  .dynamic        : { *(.dynamic) }
-  .ctors          :
-  {
-    /* gcc uses crtbegin.o to find the start of
-       the constructors, so we make sure it is
-       first.  Because this is a wildcard, it
-       doesn't matter if the user does not
-       actually link against crtbegin.o; the
-       linker won't look for a file to match a
-       wildcard.  The wildcard also means that it
-       doesn't matter which directory crtbegin.o
-       is in.  */
-    KEEP (*crtbegin.o(.ctors))
-    /* We don't want to include the .ctor section from
-       from the crtend.o file until after the sorted ctors.
-       The .ctor section from the crtend file contains the
-       end of ctors marker and it must be last */
-    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
-    KEEP (*(SORT(.ctors.*)))
-    KEEP (*(.ctors))
-  }
-  .dtors          :
-  {
-    KEEP (*crtbegin.o(.dtors))
-    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
-    KEEP (*(SORT(.dtors.*)))
-    KEEP (*(.dtors))
-  }
-  .jcr            : { KEEP (*(.jcr)) }
-  .got            : { *(.got.plt) *(.got) }
-  _edata = .;
-  PROVIDE (edata = .);
-  __bss_start = .;
-  .bss            :
-  {
-   *(.dynbss)
-   *(.bss .bss.* .gnu.linkonce.b.*)
-   *(COMMON)
-   /* Align here to ensure that the .bss section occupies space up to
-      _end.  Align after .bss to ensure correct alignment even if the
-      .bss section disappears because there are no input sections.  */
-   . = ALIGN(32 / 8);
-  }
-  . = ALIGN(32 / 8);
-  _end = .;
-  PROVIDE (end = .);
-
-  /* Stabs debugging sections.  */
-  .stab          0 : { *(.stab) }
-  .stabstr       0 : { *(.stabstr) }
-  .stab.excl     0 : { *(.stab.excl) }
-  .stab.exclstr  0 : { *(.stab.exclstr) }
-  .stab.index    0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment       0 : { *(.comment) }
-  /* DWARF debug sections.
-     Symbols in the DWARF debugging sections are relative to the beginning
-     of the section so we begin them at 0.  */
-  /* DWARF 1 */
-  .debug          0 : { *(.debug) }
-  .line           0 : { *(.line) }
-  /* GNU DWARF 1 extensions */
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  /* DWARF 1.1 and DWARF 2 */
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  /* DWARF 2 */
-  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
-  .debug_abbrev   0 : { *(.debug_abbrev) }
-  .debug_line     0 : { *(.debug_line) }
-  .debug_frame    0 : { *(.debug_frame) }
-  .debug_str      0 : { *(.debug_str) }
-  .debug_loc      0 : { *(.debug_loc) }
-  .debug_macinfo  0 : { *(.debug_macinfo) }
-  /* SGI/MIPS DWARF 2 extensions */
-  .debug_weaknames 0 : { *(.debug_weaknames) }
-  .debug_funcnames 0 : { *(.debug_funcnames) }
-  .debug_typenames 0 : { *(.debug_typenames) }
-  .debug_varnames  0 : { *(.debug_varnames) }
-}
index fa7d9f2..dc4cbce 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- c -*- ------------------------------------------------------------- *
  *   
- *   Copyright 2004 Murali Krishnan Ganapathy - All Rights Reserved
+ *   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
 #endif
 
 #include "menu.h"
-#include "biosio.h"
-#include "string.h"
-#include "syslinux.h"
+#include "com32io.h"
+#include "help.h"
+#include "passwords.h"
+#include "des.h"
+#include <stdlib.h>
+#include <stdio.h>
 
 /* Global variables */
 char infoline[160];
+char buffer[80];
 
 // Different network options
 static char nonet[] = "<n>etwork [none]";
 static char dhcpnet[]="<n>etwork [dhcp]";
 static char statnet[]="<n>etwork [static]";
 
+static char loginstr[] = "<L>ogin  ";
+static char logoutstr[]= "<L>ogout ";
+
 struct {
     unsigned int baseurl : 1; // Do we need to specify by url
     unsigned int mountcd : 1; // Should we mount the cd
@@ -34,14 +41,16 @@ struct {
     unsigned int linrep  : 1; // Want to repair linux?
 } flags;
 
-t_menuitem *baseurl,*mountcd,*network,*runprep,*winrep,*linrep;
 // Some menu options
-t_menuitem * stat,*dhcp,*none;
+t_menuitem *baseurl,*mountcd,*network,*runprep,*winrep,*linrep;
+t_menuitem * stat,*dhcp,*none,*prepopt,*secret;
+
 // all the menus we are going to declare
-char TESTING,RESCUE,MAIN,PREP,NETMENU;
+unsigned char TESTING,RESCUE,MAIN,PREPMENU,NETMENU,LONGMENU,SECRETMENU;
 
-/* End globals */
+char username[12]; // Name of user currently using the system
 
+/* End globals */
 
 TIMEOUTCODE ontimeout()
 {
@@ -51,6 +60,82 @@ TIMEOUTCODE ontimeout()
 
 
 #define INFLINE 22
+#define PWDLINE 3
+#define PWDPROMPT 21
+#define PWDCOLUMN 60
+#define PWDATTR 0x74
+#define EDITPROMPT 21
+
+void keys_handler(t_menusystem *ms, t_menuitem *mi,unsigned int scancode)
+{
+   char nc;
+
+   if ((scancode >> 8) == F1) { // If scancode of F1
+      runhelpsystem(mi->helpid);
+   }
+   // If user hit TAB, and item is an "executable" item
+   // and user has privileges to edit it, edit it in place.
+   if (((scancode & 0xFF) == 0x09) && (mi->action == OPT_RUN) &&
+       (isallowed(username,"editcmd") || isallowed(username,"root"))) { 
+     nc = getnumcols();
+     // User typed TAB and has permissions to edit command line
+     gotoxy(EDITPROMPT,1,ms->menupage);
+     csprint("Command line:",0x07);
+     editstring(mi->data,ACTIONLEN);
+     gotoxy(EDITPROMPT,1,ms->menupage);
+     cprint(' ',0x07,nc-1,ms->menupage);
+   }
+}
+
+t_handler_return login_handler(t_menusystem *ms, t_menuitem *mi)
+{
+  (void)mi; // Unused
+  char pwd[40];
+  char login[40];
+  char nc;
+  t_handler_return rv;
+
+  if (mi->item == loginstr) { /* User wants to login */
+    nc = getnumcols();
+    gotoxy(PWDPROMPT,1,ms->menupage);
+    csprint("Enter Username: ",0x07);
+    getstring(login, sizeof username);
+    gotoxy(PWDPROMPT,1,ms->menupage);
+    cprint(' ',0x07,nc,ms->menupage);
+    csprint("Enter Password: ",0x07);
+    getpwd(pwd, sizeof pwd);
+    gotoxy(PWDPROMPT,1,ms->menupage);
+    cprint(' ',0x07,nc,ms->menupage);
+
+    if (authenticate_user(login,pwd))
+    {
+      strcpy(username,login); 
+      mi->item = logoutstr; // Change item to read "Logout"
+    }
+    else strcpy(username,GUEST_USER);
+  }
+  else // User needs to logout
+  {
+    strcpy(username,GUEST_USER);
+    mi->item = loginstr;
+  }
+
+  if (strcmp(username,GUEST_USER)==0)
+  {
+     prepopt->action = OPT_INACTIVE;
+     secret->action = OPT_INVISIBLE;
+  }
+  else 
+  {
+     prepopt->action = OPT_SUBMENU;
+     prepopt->itemdata.radiomenunum = PREPMENU;
+     secret->action = OPT_SUBMENU;
+     secret->itemdata.submenunum = SECRETMENU;
+  }
+  rv.valid = 0;
+  rv.refresh = 1;
+  return rv;
+}
 
 void msys_handler(t_menusystem *ms, t_menuitem *mi)
 {
@@ -58,10 +143,18 @@ void msys_handler(t_menusystem *ms, t_menuitem *mi)
     void *v;
     nc = getnumcols(); // Get number of columns
 
-    if (mi->parindex != PREP) // If we are not in the PREP MENU
+    gotoxy(PWDLINE,PWDCOLUMN,ms->menupage);
+    csprint("User: ",PWDATTR);
+    cprint(ms->fillchar,ms->fillattr,sizeof username,ms->menupage);
+    gotoxy(PWDLINE,PWDCOLUMN +6,ms->menupage);
+    csprint(username,PWDATTR);
+
+    if (mi->parindex != PREPMENU) // If we are not in the PREP MENU
     {
         gotoxy(INFLINE,0,ms->menupage);
         cprint(' ',0x07,nc,ms->menupage);
+        gotoxy(INFLINE+1,0,ms->menupage);
+        cprint(' ',0x07,nc,ms->menupage);
         return;
     }
     strcpy (infoline," ");
@@ -86,7 +179,7 @@ void msys_handler(t_menusystem *ms, t_menuitem *mi)
     csprint(infoline,0x07);
 }
 
-void network_handler(t_menusystem *ms, t_menuitem *mi)
+t_handler_return network_handler(t_menusystem *ms, t_menuitem *mi)
 {
   // mi=network since this is handler only for that.
   (void)ms; // Unused
@@ -94,13 +187,14 @@ void network_handler(t_menusystem *ms, t_menuitem *mi)
   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
 }
 
-void checkbox_handler(t_menusystem *ms, t_menuitem *mi)
+t_handler_return checkbox_handler(t_menusystem *ms, t_menuitem *mi)
 {
   (void)ms; /* Unused */
 
-    if (mi->action != OPT_CHECKBOX) return;
+    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) {
@@ -128,6 +222,7 @@ void checkbox_handler(t_menusystem *ms, t_menuitem *mi)
         }
     }
     if (strcmp(mi->data,"mountcd") == 0) flags.mountcd = (mi->itemdata.checked ? 1 : 0);
+  return ACTION_VALID;
 }
 
 /*
@@ -149,18 +244,21 @@ int checkkeypress(int stepsize, int numsteps)
   return 0;
 }
 
-int menumain(char *cmdline)
+int main()
 {
   t_menuitem * curr;
   char cmd[160];
   char ip[30];
 
-  (void)cmdline;               /* Not used */
+  // 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
   
@@ -172,28 +270,29 @@ int menumain(char *cmdline)
   //set_misc_info(-1,-1,-1,-1);
 
   // Register the menusystem handler
-  reg_handler(&msys_handler);
+  reg_handler(HDLR_SCREEN,&msys_handler);
+  reg_handler(HDLR_KEYS,&keys_handler);
   // Register the ontimeout handler, with a time out of 10 seconds
   reg_ontimeout(ontimeout,1000,0);
 
-  NETMENU = add_menu(" Init Network ");
+  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 ");
+  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 ");
+  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);
 
-  PREP = add_menu(" Prep options ");
+  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);
@@ -213,13 +312,70 @@ int menumain(char *cmdline)
   flags.winrep = 0;
   flags.linrep = 0;
 
-  MAIN = add_menu(" Main Menu ");  
+  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);
-  add_item("<P>rep options...","Options for prep image",OPT_SUBMENU,NULL,PREP);
+  set_item_options(-1,24);
+  prepopt = add_item("<P>rep options...","Options for prep image: Requires authenticated user",OPT_INACTIVE,NULL,PREPMENU);
+  set_item_options(-1,25);
+
   add_item("<R>escue options...","Troubleshoot a system",OPT_SUBMENU,NULL,RESCUE);
+  set_item_options(-1,26);
   add_item("<T>esting...","Options to test hardware",OPT_SUBMENU,NULL,TESTING);
+  set_item_options(-1,27);
+  add_item("<L>ong Menu...","test menu system",OPT_SUBMENU,NULL,LONGMENU);
+  set_item_options(-1,28);
+  secret = add_item("<S>ecret Menu...","Secret menu",OPT_INVISIBLE,NULL,SECRETMENU);
+  set_item_options(-1,29);
   add_item("<E>xit to prompt", "Exit the menu system", OPT_EXITMENU, "exit", 0);
-
+  set_item_options(-1,30);
   csprint("Press any key within 5 seconds to show menu...",0x07);
   if (!checkkeypress(100,50)) // Granularity of 100 milliseconds
     {
@@ -239,13 +395,14 @@ int menumain(char *cmdline)
                if (network->data == (void *)stat) // We want static
                 {
                     csprint("Enter IP address (last two octets only): ",0x07);
-                    getstring(ip, sizeof ip);
+                    strcpy(ip, "Junk");
+                    editstring(ip, sizeof ip);
                     strcat(cmd,"ipaddr=192.168.");
                     strcat(cmd,ip);
                 }
             }
-            if (syslinux)
-               runcommand(cmd);
+            if (issyslinux())
+               runsyslinuxcmd(cmd);
             else csprint(cmd,0x07);
             return 1; // Should not happen when run from SYSLINUX
         }
@@ -256,6 +413,11 @@ int menumain(char *cmdline)
   // if (syslinux) runcommand(YOUR_COMMAND_HERE);
   // else csprint(YOUR_COMMAND_HERE,0x07);
 
+  // Deallocate space used for these data structures
+  close_passwords();
+  close_help();
+  close_menusystem(); 
+
   // Return to prompt
   return 0;
 }
diff --git a/menu/heap.c b/menu/heap.c
deleted file mode 100644 (file)
index aa95454..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Very simple heap manager.
- * Allocation Strategy: The lower end of the heap, is the end of the BSS.
- *
- * During an alloc, if there is enough space below the high end of heap, 
- *    we return a pointer to the allocated space and move curr.
- * Space once allocated is never deallocated!
- * We run out of space if we get within BUFSIZE bytes of the stack pointer.
- */
-
-#include "heap.h"
-#include "string.h"
-#include "biosio.h"
-
-#ifndef NULL
-#define NULL ((void *)0)
-#endif
-
-extern char _end[];
-static unsigned int heap_curr  = (unsigned int)_end;
-
-static inline unsigned int currsp(void)
-{
-    unsigned int esp;
-    
-    asm("movl %%esp,%0 " : "=rm" (esp));
-    return esp;
-}
-
-static inline void _checkheap(void)
-{
-    if (currsp() < heap_curr) // Heap corrupted
-    {
-       csprint("\r\nHeap overflow, aborting!\r\n",0x07);
-       asm volatile("int $0x21" : : "a" (0x4C7f)); /* Exit with error */
-       return;
-    }
-}
-
-void * malloc(unsigned int num) // Allocate so much space
-{
-    unsigned int ans, heap_max;
-
-    _checkheap();
-    heap_max = currsp() - STACKSIZE;
-
-    ans = (heap_curr+3) & ~3;  // Align to 4-byte boundary
-
-    if ( ans+num > heap_max )
-       return NULL;
-
-    heap_curr = ans+num;
-    return (void *) ans;
-}
-
-/* We don't actually ever use these; if enabled,
-   probably _checkheap() shouldn't be inline.*/
-#if 0
-
-int checkalloc(unsigned int num)
-{
-    _checkheap();
-    return (heap_curr + num < heap_max);
-}
-
-
-void free(void * ptr)
-{
-    _checkheap();
-    return;
-}
-
-#endif
diff --git a/menu/heap.h b/menu/heap.h
deleted file mode 100644 (file)
index 52f8858..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-
-#ifndef _HEAP_H_
-#define _HEAP_H_
-
-// How much space to reserve for the stack
-#define STACKSIZE (8*1024)
-
-// Will an allocation of num bytes be successful?
-// We need this because we dont do any deallocation
-extern int checkalloc(unsigned int num); 
-
-// Allocate so much space
-extern void * malloc(unsigned int num); 
-
-// This is a nop for now may be future implementations will actually do something
-extern void free(void *); // Dealloc space. 
-
-#endif
-
diff --git a/menu/libmenu/com32io.c b/menu/libmenu/com32io.c
new file mode 100644 (file)
index 0000000..a493142
--- /dev/null
@@ -0,0 +1,147 @@
+/* -*- c -*- ------------------------------------------------------------- *
+ *   
+ *   Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <string.h>
+#include <com32.h>
+#include "com32io.h"
+#include "syslnx.h"
+
+com32sys_t inreg,outreg; // Global register sets for use
+
+/* Print character and attribute at cursor */
+void cprint(char chr,char attr,unsigned int times,char disppage)
+{
+    REG_AH(inreg) = 0x09;
+    REG_AL(inreg) = chr;
+    REG_BH(inreg) = disppage;
+    REG_BL(inreg) = attr;
+    REG_CX(inreg) = times;
+    __intcall(0x10,&inreg,&outreg);
+}
+
+void setdisppage(char num) // Set the display page to specified number
+{
+    REG_AH(inreg) = 0x05;
+    REG_AL(inreg) = num;
+    __intcall(0x10,&inreg,&outreg);
+}
+
+char getdisppage() // Get current display page 
+{
+    REG_AH(inreg) = 0x0f;
+    __intcall(0x10,&inreg,&outreg);
+    return REG_BH(outreg);
+}
+
+void getpos(char * row, char * col, char page)
+{
+   REG_AH(inreg) = 0x03;
+   REG_BH(inreg) = page;
+   __intcall(0x10,&inreg,&outreg);
+   *row = REG_DH(outreg);
+   *col = REG_DL(outreg);
+}
+
+void gotoxy(char row,char col, char page)
+{
+   REG_AH(inreg) = 0x02;
+   REG_BH(inreg) = page;
+   REG_DX(inreg) = (row << 8)+col;
+   __intcall(0x10,&inreg,&outreg);
+}
+
+unsigned char sleep(unsigned int msec)
+{
+   unsigned long micro = 1000*msec;
+
+   REG_AH(inreg) = 0x86;
+   REG_CX(inreg) = (micro >> 16);
+   REG_DX(inreg) = (micro % 0x10000);
+   __intcall(0x15,&inreg,&outreg);
+   return REG_AH(outreg);
+}
+
+void beep()
+{
+   REG_AH(inreg) = 0x0E;
+   REG_AL(inreg) = 0x07;
+   REG_BH(inreg) = 0; 
+   __intcall(0x10,&inreg,&outreg);
+}
+
+void scrollup()
+{
+  unsigned int dx = (getnumrows()<< 8) + getnumcols();
+  REG_AH(inreg) = 0x06;
+  REG_AL(inreg) = 0x01;
+  REG_BH(inreg) = 0x07; // Attribute to write blanks lines
+  REG_DX(inreg) = dx; // BOT RIGHT corner to window
+  REG_CX(inreg) = 0; // TOP LEFT of window
+}
+
+char inputc(char * scancode)
+{
+  REG_AH(inreg) = 0x10;
+  __intcall(0x16,&inreg,&outreg);
+  if (scancode)
+      *scancode = REG_AH(outreg);
+  return REG_AL(outreg);
+}
+   
+void getcursorshape(char *start, char *end)
+{
+   char page = getdisppage();
+   REG_AH(inreg) = 0x03;
+   REG_BH(inreg) = page;
+   __intcall(0x10,&inreg,&outreg);
+   *start = REG_CH(outreg);
+   *end = REG_CL(outreg);
+}
+
+void setcursorshape(char start, char end)
+{
+   REG_AH(inreg) = 0x01;
+   REG_CH(inreg) = start;
+   REG_CL(inreg) = end;
+   __intcall(0x10,&inreg,&outreg);
+}
+
+char getchar(void)
+{
+   REG_AH(inreg) = 0x08;
+   __intcall(0x21,&inreg,&outreg);
+   return REG_AL(outreg);
+}
+
+void setvideomode(char mode)
+{
+   REG_AH(inreg) = 0x00;
+   REG_AL(inreg) = mode;
+   __intcall(0x10,&inreg,&outreg);
+}
+
+unsigned char checkkbdbuf()
+{
+   REG_AH(inreg) = 0x11;
+   __intcall(0x16,&inreg,&outreg);
+   return (outreg.eflags.l & EFLAGS_ZF);
+}
+
+// Get char displayed at current position
+unsigned char getcharat(char page)
+{
+   REG_AH(inreg) = 0x08;
+   REG_BH(inreg) = page;
+   __intcall(0x16,&inreg,&outreg);
+   return REG_AL(outreg);
+}
+
diff --git a/menu/libmenu/com32io.h b/menu/libmenu/com32io.h
new file mode 100644 (file)
index 0000000..899260d
--- /dev/null
@@ -0,0 +1,97 @@
+/* -*- c -*- ------------------------------------------------------------- *
+ *   
+ *   Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef __COM32IO_H__
+#define __COM32IO_H__
+
+#include <com32.h>
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+/* BIOS Assisted output routines */
+
+void cswprint(const char *str, char attr, char left); 
+// Print a C str (NUL-terminated) respecting the left edge of window
+// i.e. \n in str will move cursor to column left
+// Print a C str (NUL-terminated)
+
+static inline void csprint(const char *str, char attr)
+{
+  cswprint(str,attr,0);
+}
+
+void cprint(char chr,char attr,unsigned int times, char disppage); // Print a char 
+
+void setdisppage(char num); // Set the display page to specified number
+
+char getdisppage(); // Get current display page 
+
+void gotoxy(char row,char col, char page);
+
+void getpos(char * row, char * col, char page);
+
+char inputc(char * scancode); // Return ASCII char by val, and scancode by reference
+
+static inline void putch(char x, char attr, char page)
+{ 
+   cprint(x,attr,1,page);
+}
+
+void setcursorshape(char start,char end); // Set cursor shape
+void getcursorshape(char *start,char *end); // Get shape for current page
+
+// Get char displayed at current position in specified page
+unsigned char getcharat(char page); 
+
+static inline void cursoroff(void) /* Turns off cursor */
+{
+   setcursorshape(32,33);
+}
+
+static inline void cursoron(void) /* Turns on cursor */
+{
+   setcursorshape(6,7);
+}
+
+static inline unsigned char readbiosb(unsigned int ofs)
+{
+   return *((unsigned char *)MK_PTR(0,ofs));
+}
+
+static inline char getnumrows()
+{
+    return readbiosb(0x484); // Actually numrows - 1
+}
+
+static inline char getnumcols(void)
+{
+    return readbiosb(0x44a); // Actually numcols
+}
+
+void scrollup(); //Scroll up display screen by one line
+void setvideomode(char mode); // Set the video mode.
+
+unsigned char sleep(unsigned int msec); // Sleep for specified time
+
+void beep(); // A Bell
+
+unsigned char checkkbdbuf(); // Check to see if there is kbd buffer is non-empty?
+
+static inline void clearkbdbuf()   // Clear the kbd buffer (how many chars removed?)
+{ 
+   while (checkkbdbuf()) inputc(NULL);
+} 
+
+#endif
diff --git a/menu/libmenu/des.c b/menu/libmenu/des.c
new file mode 100644 (file)
index 0000000..6309453
--- /dev/null
@@ -0,0 +1,1102 @@
+/*
+ * FreeSec: libcrypt for NetBSD
+ *
+ * Copyright (c) 1994 David Burren
+ * All rights reserved.
+ *
+ * Adapted for FreeBSD-2.0 by Geoffrey M. Rehmet
+ *     this file should now *only* export crypt(), in order to make
+ *     binaries of libcrypt exportable from the USA
+ *
+ * Adapted for FreeBSD-4.0 by Mark R V Murray
+ *     this file should now *only* export crypt_des(), in order to make
+ *     a module that can be optionally included in libcrypt.
+ *
+ * Adapted for pxelinux menu environment by Th.Gebhardt
+ *      removed dependencies of standard C libs
+ *      added LOWSPACE option (using common space for different arrays)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This is an original implementation of the DES and the crypt(3) interfaces
+ * by David Burren <davidb@werj.com.au>.
+ *
+ * An excellent reference on the underlying algorithm (and related
+ * algorithms) is:
+ *
+ *     B. Schneier, Applied Cryptography: protocols, algorithms,
+ *     and source code in C, John Wiley & Sons, 1994.
+ *
+ * Note that in that book's description of DES the lookups for the initial,
+ * pbox, and final permutations are inverted (this has been brought to the
+ * attention of the author).  A list of errata for this book has been
+ * posted to the sci.crypt newsgroup by the author and is available for FTP.
+ *
+ * ARCHITECTURE ASSUMPTIONS:
+ *     It is assumed that the 8-byte arrays passed by reference can be
+ *     addressed as arrays of u_int32_t's (ie. the CPU is not picky about
+ *     alignment).
+ */
+
+
+#define LOWSPACE
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+typedef unsigned long my_u_int32_t;
+typedef unsigned char my_u_char_t;
+
+/* Re-entrantify me -- all this junk needs to be in 
+ * struct crypt_data to make this really reentrant... */
+static my_u_char_t     inv_key_perm[64];
+static my_u_char_t     inv_comp_perm[56];
+static my_u_char_t     u_sbox[8][64];
+static my_u_char_t     un_pbox[32];
+static my_u_int32_t en_keysl[16], en_keysr[16];
+static my_u_int32_t de_keysl[16], de_keysr[16];
+
+#ifndef LOWSPACE
+static my_u_int32_t ip_maskl[8][256], ip_maskr[8][256];
+static my_u_int32_t fp_maskl[8][256], fp_maskr[8][256];
+static my_u_int32_t key_perm_maskl[8][128], key_perm_maskr[8][128];
+static my_u_int32_t comp_maskl[8][128], comp_maskr[8][128];
+#endif
+
+static my_u_int32_t saltbits;
+static my_u_int32_t old_salt;
+static my_u_int32_t old_rawkey0, old_rawkey1;
+
+#ifdef LOWSPACE
+static my_u_int32_t common[8][256];
+#endif
+
+/* Static stuff that stays resident and doesn't change after 
+ * being initialized, and therefore doesn't need to be made 
+ * reentrant. */
+static my_u_char_t     init_perm[64], final_perm[64];
+static my_u_char_t     m_sbox[4][4096];
+
+#ifndef LOWSPACE
+static my_u_int32_t psbox[4][256];
+#endif
+
+/* A pile of data */
+static const my_u_char_t       ascii64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static const my_u_char_t       IP[64] = {
+       58, 50, 42, 34, 26, 18, 10,  2, 60, 52, 44, 36, 28, 20, 12,  4,
+       62, 54, 46, 38, 30, 22, 14,  6, 64, 56, 48, 40, 32, 24, 16,  8,
+       57, 49, 41, 33, 25, 17,  9,  1, 59, 51, 43, 35, 27, 19, 11,  3,
+       61, 53, 45, 37, 29, 21, 13,  5, 63, 55, 47, 39, 31, 23, 15,  7
+};
+
+static const my_u_char_t       key_perm[56] = {
+       57, 49, 41, 33, 25, 17,  9,  1, 58, 50, 42, 34, 26, 18,
+       10,  2, 59, 51, 43, 35, 27, 19, 11,  3, 60, 52, 44, 36,
+       63, 55, 47, 39, 31, 23, 15,  7, 62, 54, 46, 38, 30, 22,
+       14,  6, 61, 53, 45, 37, 29, 21, 13,  5, 28, 20, 12,  4
+};
+
+static const my_u_char_t       key_shifts[16] = {
+       1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+};
+
+static const my_u_char_t       comp_perm[48] = {
+       14, 17, 11, 24,  1,  5,  3, 28, 15,  6, 21, 10,
+       23, 19, 12,  4, 26,  8, 16,  7, 27, 20, 13,  2,
+       41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
+       44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
+};
+
+/*
+ *     No E box is used, as it's replaced by some ANDs, shifts, and ORs.
+ */
+
+static const my_u_char_t       sbox[8][64] = {
+       {
+               14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
+                0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
+                4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
+               15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13
+       },
+       {
+               15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
+                3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
+                0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
+               13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9
+       },
+       {
+               10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
+               13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
+               13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
+                1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12
+       },
+       {
+                7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
+               13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
+               10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
+                3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14
+       },
+       {
+                2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
+               14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
+                4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
+               11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3
+       },
+       {
+               12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
+               10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
+                9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
+                4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13
+       },
+       {
+                4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
+               13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
+                1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
+                6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12
+       },
+       {
+               13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
+                1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
+                7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
+                2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
+       }
+};
+
+static const my_u_char_t       pbox[32] = {
+       16,  7, 20, 21, 29, 12, 28, 17,  1, 15, 23, 26,  5, 18, 31, 10,
+        2,  8, 24, 14, 32, 27,  3,  9, 19, 13, 30,  6, 22, 11,  4, 25
+};
+
+static const my_u_int32_t bits32[32] =
+{
+       0x80000000, 0x40000000, 0x20000000, 0x10000000,
+       0x08000000, 0x04000000, 0x02000000, 0x01000000,
+       0x00800000, 0x00400000, 0x00200000, 0x00100000,
+       0x00080000, 0x00040000, 0x00020000, 0x00010000,
+       0x00008000, 0x00004000, 0x00002000, 0x00001000,
+       0x00000800, 0x00000400, 0x00000200, 0x00000100,
+       0x00000080, 0x00000040, 0x00000020, 0x00000010,
+       0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static const my_u_int32_t bits28[28] =
+{
+       0x08000000, 0x04000000, 0x02000000, 0x01000000,
+       0x00800000, 0x00400000, 0x00200000, 0x00100000,
+       0x00080000, 0x00040000, 0x00020000, 0x00010000,
+       0x00008000, 0x00004000, 0x00002000, 0x00001000,
+       0x00000800, 0x00000400, 0x00000200, 0x00000100,
+       0x00000080, 0x00000040, 0x00000020, 0x00000010,
+       0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static const my_u_int32_t bits24[24] =
+{
+       0x00800000, 0x00400000, 0x00200000, 0x00100000,
+       0x00080000, 0x00040000, 0x00020000, 0x00010000,
+       0x00008000, 0x00004000, 0x00002000, 0x00001000,
+       0x00000800, 0x00000400, 0x00000200, 0x00000100,
+       0x00000080, 0x00000040, 0x00000020, 0x00000010,
+       0x00000008, 0x00000004, 0x00000002, 0x00000001
+};
+
+static const my_u_char_t       bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+// static const my_u_int32_t *bits28, *bits24;
+
+
+static int 
+ascii_to_bin(char ch)
+{
+       if (ch > 'z')
+               return(0);
+       if (ch >= 'a')
+               return(ch - 'a' + 38);
+       if (ch > 'Z')
+               return(0);
+       if (ch >= 'A')
+               return(ch - 'A' + 12);
+       if (ch > '9')
+               return(0);
+       if (ch >= '.')
+               return(ch - '.');
+       return(0);
+}
+
+static void
+des_init(void)
+{
+
+#ifdef LOWSPACE
+       int     i, j, b;
+#else
+       int     i, j, b, k, inbit, obit;
+       my_u_int32_t    *p, *il, *ir, *fl, *fr;
+#endif
+       static int des_initialised = 0;
+
+       if (des_initialised==1)
+           return;
+
+       old_rawkey0 = old_rawkey1 = 0L;
+       saltbits = 0L;
+       old_salt = 0L;
+       //      bits24 = (bits28 = bits32 + 4) + 4;
+
+       /*
+        * Invert the S-boxes, reordering the input bits.
+        */
+       for (i = 0; i < 8; i++)
+               for (j = 0; j < 64; j++) {
+                       b = (j & 0x20) | ((j & 1) << 4) | ((j >> 1) & 0xf);
+                       u_sbox[i][j] = sbox[i][b];
+               }
+
+       /*
+        * Convert the inverted S-boxes into 4 arrays of 8 bits.
+        * Each will handle 12 bits of the S-box input.
+        */
+       for (b = 0; b < 4; b++)
+               for (i = 0; i < 64; i++)
+                       for (j = 0; j < 64; j++)
+                               m_sbox[b][(i << 6) | j] =
+                                       (my_u_char_t)((u_sbox[(b << 1)][i] << 4) |
+                                       u_sbox[(b << 1) + 1][j]);
+
+       /*
+        * Set up the initial & final permutations into a useful form, and
+        * initialise the inverted key permutation.
+        */
+       for (i = 0; i < 64; i++) {
+               init_perm[final_perm[i] = IP[i] - 1] = (my_u_char_t)i;
+               inv_key_perm[i] = 255;
+       }
+
+       /*
+        * Invert the key permutation and initialise the inverted key
+        * compression permutation.
+        */
+       for (i = 0; i < 56; i++) {
+               inv_key_perm[key_perm[i] - 1] = (my_u_char_t)i;
+               inv_comp_perm[i] = 255;
+       }
+
+       /*
+        * Invert the key compression permutation.
+        */
+       for (i = 0; i < 48; i++) {
+               inv_comp_perm[comp_perm[i] - 1] = (my_u_char_t)i;
+       }
+
+       /*
+        * Set up the OR-mask arrays for the initial and final permutations,
+        * and for the key initial and compression permutations.
+        */
+
+#ifndef LOWSPACE       
+       for (k = 0; k < 8; k++) {
+               for (i = 0; i < 256; i++) {
+                       *(il = &ip_maskl[k][i]) = 0L;
+                       *(ir = &ip_maskr[k][i]) = 0L;
+                       *(fl = &fp_maskl[k][i]) = 0L;
+                       *(fr = &fp_maskr[k][i]) = 0L;
+                       for (j = 0; j < 8; j++) {
+                               inbit = 8 * k + j;
+                               if (i & bits8[j]) {
+                                       if ((obit = init_perm[inbit]) < 32)
+                                               *il |= bits32[obit];
+                                       else
+                                               *ir |= bits32[obit-32];
+                                       if ((obit = final_perm[inbit]) < 32)
+                                               *fl |= bits32[obit];
+                                       else
+                                               *fr |= bits32[obit - 32];
+                               }
+                       }
+               }
+               for (i = 0; i < 128; i++) {
+                       *(il = &key_perm_maskl[k][i]) = 0L;
+                       *(ir = &key_perm_maskr[k][i]) = 0L;
+                       for (j = 0; j < 7; j++) {
+                               inbit = 8 * k + j;
+                               if (i & bits8[j + 1]) {
+                                       if ((obit = inv_key_perm[inbit]) == 255)
+                                               continue;
+                                       if (obit < 28)
+                                               *il |= bits28[obit];
+                                       else
+                                               *ir |= bits28[obit - 28];
+                               }
+                       }
+                       *(il = &comp_maskl[k][i]) = 0L;
+                       *(ir = &comp_maskr[k][i]) = 0L;
+                       for (j = 0; j < 7; j++) {
+                               inbit = 7 * k + j;
+                               if (i & bits8[j + 1]) {
+                                       if ((obit=inv_comp_perm[inbit]) == 255)
+                                               continue;
+                                       if (obit < 24)
+                                               *il |= bits24[obit];
+                                       else
+                                               *ir |= bits24[obit - 24];
+                               }
+                       }
+               }
+       }
+#endif
+
+       /*
+        * Invert the P-box permutation, and convert into OR-masks for
+        * handling the output of the S-box arrays setup above.
+        */
+       for (i = 0; i < 32; i++)
+               un_pbox[pbox[i] - 1] = (my_u_char_t)i;
+
+#ifndef LOWSPACE       
+       for (b = 0; b < 4; b++)
+               for (i = 0; i < 256; i++) {
+                       *(p = &psbox[b][i]) = 0L;
+                       for (j = 0; j < 8; j++) {
+                               if (i & bits8[j])
+                                       *p |= bits32[un_pbox[8 * b + j]];
+                       }
+               }
+#endif
+       des_initialised = 1;
+}
+
+
+#ifdef LOWSPACE
+
+static void
+setup_ip_maskl(void)
+{
+  int          i, j, k, inbit, obit;
+  my_u_int32_t *il;
+     
+  for (k = 0; k < 8; k++) {
+    for (i = 0; i < 256; i++) {
+      *(il = &common[k][i]) = 0L;
+      for (j = 0; j < 8; j++) {
+       inbit = 8 * k + j;
+       if (i & bits8[j]) {
+         if ((obit = init_perm[inbit]) < 32)
+           *il |= bits32[obit];
+       }
+      }
+    }
+  }
+}
+
+static void
+setup_ip_maskr(void)
+{
+  int          i, j, k, inbit, obit;
+  my_u_int32_t *ir;
+     
+  for (k = 0; k < 8; k++) {
+    for (i = 0; i < 256; i++) {
+      *(ir = &common[k][i]) = 0L;
+      for (j = 0; j < 8; j++) {
+       inbit = 8 * k + j;
+       if (i & bits8[j]) {
+         if ((obit = init_perm[inbit]) >= 32)
+           *ir |= bits32[obit-32];
+       }
+      }
+    }
+  }
+}
+
+static void
+setup_fp_maskl(void)
+{
+  int          i, j, k, inbit, obit;
+  my_u_int32_t *fl;
+
+  for (k = 0; k < 8; k++) {
+    for (i = 0; i < 256; i++) {
+      *(fl = &common[k][i]) = 0L;
+      for (j = 0; j < 8; j++) {
+       inbit = 8 * k + j;
+       if (i & bits8[j]) {
+         if ((obit = final_perm[inbit]) < 32)
+           *fl |= bits32[obit];
+       }
+      }
+    }
+  }
+}
+    
+static void
+setup_fp_maskr(void)
+{
+  int          i, j, k, inbit, obit;
+  my_u_int32_t *fr;
+
+  for (k = 0; k < 8; k++) {
+    for (i = 0; i < 256; i++) {
+      *(fr = &common[k][i]) = 0L;
+      for (j = 0; j < 8; j++) {
+       inbit = 8 * k + j;
+       if (i & bits8[j]) {
+         if ((obit = final_perm[inbit]) >= 32)
+           *fr |= bits32[obit - 32];
+       }
+      }
+    }
+  }
+}
+    
+static void
+setup_key_perm_maskl(void)
+{
+  int          i, j, k, inbit, obit;
+  my_u_int32_t *il;
+
+  for (k = 0; k < 8; k++) {
+    for (i = 0; i < 128; i++) {
+      *(il = &common[k][i]) = 0L;
+      for (j = 0; j < 7; j++) {
+       inbit = 8 * k + j;
+       if (i & bits8[j + 1]) {
+         if ((obit = inv_key_perm[inbit]) == 255)
+           continue;
+         if (obit < 28)
+           *il |= bits28[obit];
+       }
+      }
+    }
+  }
+}
+
+static void
+setup_key_perm_maskr(void)
+{
+  int          i, j, k, inbit, obit;
+  my_u_int32_t *ir;
+
+  for (k = 0; k < 8; k++) {
+    for (i = 0; i < 128; i++) {
+      *(ir = &common[k][i]) = 0L;
+      for (j = 0; j < 7; j++) {
+       inbit = 8 * k + j;
+       if (i & bits8[j + 1]) {
+         if ((obit = inv_key_perm[inbit]) == 255)
+           continue;
+         if (obit >= 28)
+           *ir |= bits28[obit - 28];
+       }
+      }
+    }
+  }
+}
+  
+static void
+setup_comp_maskl(void)
+{
+  int          i, j, k, inbit, obit;
+  my_u_int32_t *il;
+
+  for (k = 0; k < 8; k++) {
+    for (i = 0; i < 128; i++) {
+      *(il = &common[k][i]) = 0L;
+      for (j = 0; j < 7; j++) {
+       inbit = 7 * k + j;
+       if (i & bits8[j + 1]) {
+         if ((obit=inv_comp_perm[inbit]) == 255)
+           continue;
+         if (obit < 24)
+           *il |= bits24[obit];
+       }
+      }
+    }
+  }
+}
+
+static void
+setup_comp_maskr(void)
+{
+  int          i, j, k, inbit, obit;
+  my_u_int32_t *ir;
+
+  for (k = 0; k < 8; k++) {
+    for (i = 0; i < 128; i++) {
+      *(ir = &common[k][i]) = 0L;
+      for (j = 0; j < 7; j++) {
+       inbit = 7 * k + j;
+       if (i & bits8[j + 1]) {
+         if ((obit=inv_comp_perm[inbit]) == 255)
+           continue;
+         if (obit >= 24)
+           *ir |= bits24[obit - 24];
+       }
+      }
+    }
+  }
+}
+
+static void
+setup_psbox(void)
+{
+  int          i, j, b;
+  my_u_int32_t *p;
+  
+  for (b = 0; b < 4; b++)
+    for (i = 0; i < 256; i++) {
+      *(p = &common[b][i]) = 0L;
+      for (j = 0; j < 8; j++) {
+       if (i & bits8[j])
+         *p |= bits32[un_pbox[8 * b + j]];
+      }
+    }
+}
+
+#endif
+
+static void
+setup_salt(my_u_int32_t salt)
+{
+       my_u_int32_t    obit, saltbit;
+       int     i;
+
+       if (salt == old_salt)
+               return;
+       old_salt = salt;
+
+       saltbits = 0L;
+       saltbit = 1;
+       obit = 0x800000;
+       for (i = 0; i < 24; i++) {
+               if (salt & saltbit)
+                       saltbits |= obit;
+               saltbit <<= 1;
+               obit >>= 1;
+       }
+}
+
+
+static my_u_int32_t char_to_int(const char *key)
+{
+  my_u_int32_t byte0,byte1,byte2,byte3;
+  byte0 = (my_u_int32_t) (my_u_char_t) key[0];
+  byte1 = (my_u_int32_t) (my_u_char_t) key[1];
+  byte2 = (my_u_int32_t) (my_u_char_t) key[2];
+  byte3 = (my_u_int32_t) (my_u_char_t) key[3];
+
+  return byte0 << 24 |  byte1 << 16 | byte2 << 8 | byte3 ;
+}
+
+
+static int
+des_setkey(const char *key)
+{
+       my_u_int32_t    k0, k1, rawkey0, rawkey1;
+       int             shifts, round;
+
+       des_init();
+
+       /*  rawkey0 = ntohl(*(const my_u_int32_t *) key);
+        *  rawkey1 = ntohl(*(const my_u_int32_t *) (key + 4));
+        */
+
+       rawkey0 = char_to_int(key);
+       rawkey1 = char_to_int(key+4);
+
+       if ((rawkey0 | rawkey1)
+           && rawkey0 == old_rawkey0
+           && rawkey1 == old_rawkey1) {
+               /*
+                * Already setup for this key.
+                * This optimisation fails on a zero key (which is weak and
+                * has bad parity anyway) in order to simplify the starting
+                * conditions.
+                */
+               return(0);
+       }
+       old_rawkey0 = rawkey0;
+       old_rawkey1 = rawkey1;
+
+       /*
+        *      Do key permutation and split into two 28-bit subkeys.
+        */
+
+#ifdef LOWSPACE        
+       setup_key_perm_maskl();
+       k0 = common[0][rawkey0 >> 25]
+          | common[1][(rawkey0 >> 17) & 0x7f]
+          | common[2][(rawkey0 >> 9) & 0x7f]
+          | common[3][(rawkey0 >> 1) & 0x7f]
+          | common[4][rawkey1 >> 25]
+          | common[5][(rawkey1 >> 17) & 0x7f]
+          | common[6][(rawkey1 >> 9) & 0x7f]
+          | common[7][(rawkey1 >> 1) & 0x7f];
+       setup_key_perm_maskr();
+       k1 = common[0][rawkey0 >> 25]
+          | common[1][(rawkey0 >> 17) & 0x7f]
+          | common[2][(rawkey0 >> 9) & 0x7f]
+          | common[3][(rawkey0 >> 1) & 0x7f]
+          | common[4][rawkey1 >> 25]
+          | common[5][(rawkey1 >> 17) & 0x7f]
+          | common[6][(rawkey1 >> 9) & 0x7f]
+          | common[7][(rawkey1 >> 1) & 0x7f];
+#else
+       k0 = key_perm_maskl[0][rawkey0 >> 25]
+          | key_perm_maskl[1][(rawkey0 >> 17) & 0x7f]
+          | key_perm_maskl[2][(rawkey0 >> 9) & 0x7f]
+          | key_perm_maskl[3][(rawkey0 >> 1) & 0x7f]
+          | key_perm_maskl[4][rawkey1 >> 25]
+          | key_perm_maskl[5][(rawkey1 >> 17) & 0x7f]
+          | key_perm_maskl[6][(rawkey1 >> 9) & 0x7f]
+          | key_perm_maskl[7][(rawkey1 >> 1) & 0x7f];
+       k1 = key_perm_maskr[0][rawkey0 >> 25]
+          | key_perm_maskr[1][(rawkey0 >> 17) & 0x7f]
+          | key_perm_maskr[2][(rawkey0 >> 9) & 0x7f]
+          | key_perm_maskr[3][(rawkey0 >> 1) & 0x7f]
+          | key_perm_maskr[4][rawkey1 >> 25]
+          | key_perm_maskr[5][(rawkey1 >> 17) & 0x7f]
+          | key_perm_maskr[6][(rawkey1 >> 9) & 0x7f]
+          | key_perm_maskr[7][(rawkey1 >> 1) & 0x7f];
+#endif
+
+       /*
+        *      Rotate subkeys and do compression permutation.
+        */
+       shifts = 0;
+       for (round = 0; round < 16; round++) {
+               my_u_int32_t    t0, t1;
+
+               shifts += key_shifts[round];
+
+               t0 = (k0 << shifts) | (k0 >> (28 - shifts));
+               t1 = (k1 << shifts) | (k1 >> (28 - shifts));
+
+#ifdef LOWSPACE        
+               setup_comp_maskl();
+               de_keysl[15 - round] =
+               en_keysl[round] = common[0][(t0 >> 21) & 0x7f]
+                               | common[1][(t0 >> 14) & 0x7f]
+                               | common[2][(t0 >> 7) & 0x7f]
+                               | common[3][t0 & 0x7f]
+                               | common[4][(t1 >> 21) & 0x7f]
+                               | common[5][(t1 >> 14) & 0x7f]
+                               | common[6][(t1 >> 7) & 0x7f]
+                               | common[7][t1 & 0x7f];
+
+               setup_comp_maskr();
+               de_keysr[15 - round] =
+               en_keysr[round] = common[0][(t0 >> 21) & 0x7f]
+                               | common[1][(t0 >> 14) & 0x7f]
+                               | common[2][(t0 >> 7) & 0x7f]
+                               | common[3][t0 & 0x7f]
+                               | common[4][(t1 >> 21) & 0x7f]
+                               | common[5][(t1 >> 14) & 0x7f]
+                               | common[6][(t1 >> 7) & 0x7f]
+                               | common[7][t1 & 0x7f];
+#else
+               de_keysl[15 - round] =
+               en_keysl[round] = comp_maskl[0][(t0 >> 21) & 0x7f]
+                               | comp_maskl[1][(t0 >> 14) & 0x7f]
+                               | comp_maskl[2][(t0 >> 7) & 0x7f]
+                               | comp_maskl[3][t0 & 0x7f]
+                               | comp_maskl[4][(t1 >> 21) & 0x7f]
+                               | comp_maskl[5][(t1 >> 14) & 0x7f]
+                               | comp_maskl[6][(t1 >> 7) & 0x7f]
+                               | comp_maskl[7][t1 & 0x7f];
+
+               de_keysr[15 - round] =
+               en_keysr[round] = comp_maskr[0][(t0 >> 21) & 0x7f]
+                               | comp_maskr[1][(t0 >> 14) & 0x7f]
+                               | comp_maskr[2][(t0 >> 7) & 0x7f]
+                               | comp_maskr[3][t0 & 0x7f]
+                               | comp_maskr[4][(t1 >> 21) & 0x7f]
+                               | comp_maskr[5][(t1 >> 14) & 0x7f]
+                               | comp_maskr[6][(t1 >> 7) & 0x7f]
+                               | comp_maskr[7][t1 & 0x7f];
+#endif
+       }
+       return(0);
+}
+
+
+static int
+do_des(        my_u_int32_t l_in, my_u_int32_t r_in, my_u_int32_t *l_out, my_u_int32_t *r_out, int count)
+{
+       /*
+        *      l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
+        */
+       my_u_int32_t    l, r, *kl, *kr, *kl1, *kr1;
+       my_u_int32_t    f, r48l, r48r;
+       int             round;
+
+       if (count == 0) {
+               return(1);
+       } else if (count > 0) {
+               /*
+                * Encrypting
+                */
+               kl1 = en_keysl;
+               kr1 = en_keysr;
+       } else {
+               /*
+                * Decrypting
+                */
+               count = -count;
+               kl1 = de_keysl;
+               kr1 = de_keysr;
+       }
+
+       /*
+        *      Do initial permutation (IP).
+        */
+       
+#ifdef LOWSPACE
+       setup_ip_maskl();
+       l = common[0][l_in >> 24]
+         | common[1][(l_in >> 16) & 0xff]
+         | common[2][(l_in >> 8) & 0xff]
+         | common[3][l_in & 0xff]
+         | common[4][r_in >> 24]
+         | common[5][(r_in >> 16) & 0xff]
+         | common[6][(r_in >> 8) & 0xff]
+         | common[7][r_in & 0xff];
+       setup_ip_maskr();
+       r = common[0][l_in >> 24]
+         | common[1][(l_in >> 16) & 0xff]
+         | common[2][(l_in >> 8) & 0xff]
+         | common[3][l_in & 0xff]
+         | common[4][r_in >> 24]
+         | common[5][(r_in >> 16) & 0xff]
+         | common[6][(r_in >> 8) & 0xff]
+         | common[7][r_in & 0xff];
+#else
+       l = ip_maskl[0][l_in >> 24]
+         | ip_maskl[1][(l_in >> 16) & 0xff]
+         | ip_maskl[2][(l_in >> 8) & 0xff]
+         | ip_maskl[3][l_in & 0xff]
+         | ip_maskl[4][r_in >> 24]
+         | ip_maskl[5][(r_in >> 16) & 0xff]
+         | ip_maskl[6][(r_in >> 8) & 0xff]
+         | ip_maskl[7][r_in & 0xff];
+       r = ip_maskr[0][l_in >> 24]
+         | ip_maskr[1][(l_in >> 16) & 0xff]
+         | ip_maskr[2][(l_in >> 8) & 0xff]
+         | ip_maskr[3][l_in & 0xff]
+         | ip_maskr[4][r_in >> 24]
+         | ip_maskr[5][(r_in >> 16) & 0xff]
+         | ip_maskr[6][(r_in >> 8) & 0xff]
+         | ip_maskr[7][r_in & 0xff];
+#endif
+
+       while (count--) {
+               /*
+                * Do each round.
+                */
+               kl = kl1;
+               kr = kr1;
+               round = 16;
+               while (round--) {
+                       /*
+                        * Expand R to 48 bits (simulate the E-box).
+                        */
+                       r48l    = ((r & 0x00000001) << 23)
+                               | ((r & 0xf8000000) >> 9)
+                               | ((r & 0x1f800000) >> 11)
+                               | ((r & 0x01f80000) >> 13)
+                               | ((r & 0x001f8000) >> 15);
+
+                       r48r    = ((r & 0x0001f800) << 7)
+                               | ((r & 0x00001f80) << 5)
+                               | ((r & 0x000001f8) << 3)
+                               | ((r & 0x0000001f) << 1)
+                               | ((r & 0x80000000) >> 31);
+                       /*
+                        * Do salting for crypt() and friends, and
+                        * XOR with the permuted key.
+                        */
+                       f = (r48l ^ r48r) & saltbits;
+                       r48l ^= f ^ *kl++;
+                       r48r ^= f ^ *kr++;
+                       /*
+                        * Do sbox lookups (which shrink it back to 32 bits)
+                        * and do the pbox permutation at the same time.
+                        */
+
+#ifdef LOWSPACE
+                       setup_psbox();
+                       f = common[0][m_sbox[0][r48l >> 12]]
+                         | common[1][m_sbox[1][r48l & 0xfff]]
+                         | common[2][m_sbox[2][r48r >> 12]]
+                         | common[3][m_sbox[3][r48r & 0xfff]];
+#else
+                       f = psbox[0][m_sbox[0][r48l >> 12]]
+                         | psbox[1][m_sbox[1][r48l & 0xfff]]
+                         | psbox[2][m_sbox[2][r48r >> 12]]
+                         | psbox[3][m_sbox[3][r48r & 0xfff]];
+#endif
+                       /*
+                        * Now that we've permuted things, complete f().
+                        */
+                       f ^= l;
+                       l = r;
+                       r = f;
+               }
+               r = l;
+               l = f;
+       }
+       /*
+        * Do final permutation (inverse of IP).
+        */
+
+#ifdef LOWSPACE
+       setup_fp_maskl();
+       *l_out  = common[0][l >> 24]
+               | common[1][(l >> 16) & 0xff]
+               | common[2][(l >> 8) & 0xff]
+               | common[3][l & 0xff]
+               | common[4][r >> 24]
+               | common[5][(r >> 16) & 0xff]
+               | common[6][(r >> 8) & 0xff]
+               | common[7][r & 0xff];
+       setup_fp_maskr();
+       *r_out  = common[0][l >> 24]
+               | common[1][(l >> 16) & 0xff]
+               | common[2][(l >> 8) & 0xff]
+               | common[3][l & 0xff]
+               | common[4][r >> 24]
+               | common[5][(r >> 16) & 0xff]
+               | common[6][(r >> 8) & 0xff]
+               | common[7][r & 0xff];
+#else
+       *l_out  = fp_maskl[0][l >> 24]
+               | fp_maskl[1][(l >> 16) & 0xff]
+               | fp_maskl[2][(l >> 8) & 0xff]
+               | fp_maskl[3][l & 0xff]
+               | fp_maskl[4][r >> 24]
+               | fp_maskl[5][(r >> 16) & 0xff]
+               | fp_maskl[6][(r >> 8) & 0xff]
+               | fp_maskl[7][r & 0xff];
+       *r_out  = fp_maskr[0][l >> 24]
+               | fp_maskr[1][(l >> 16) & 0xff]
+               | fp_maskr[2][(l >> 8) & 0xff]
+               | fp_maskr[3][l & 0xff]
+               | fp_maskr[4][r >> 24]
+               | fp_maskr[5][(r >> 16) & 0xff]
+               | fp_maskr[6][(r >> 8) & 0xff]
+               | fp_maskr[7][r & 0xff];
+#endif
+       return(0);
+}
+
+
+#if 0
+static int
+des_cipher(const char *in, char *out, my_u_int32_t salt, int count)
+{
+       my_u_int32_t    l_out, r_out, rawl, rawr;
+       int             retval;
+       union {
+               my_u_int32_t    *ui32;
+               const char      *c;
+       } trans;
+
+       des_init();
+
+       setup_salt(salt);
+
+       trans.c = in;
+       rawl = ntohl(*trans.ui32++);
+       rawr = ntohl(*trans.ui32);
+
+       retval = do_des(rawl, rawr, &l_out, &r_out, count);
+
+       trans.c = out;
+       *trans.ui32++ = htonl(l_out);
+       *trans.ui32 = htonl(r_out);
+       return(retval);
+}
+#endif
+
+
+void
+setkey(const char *key)
+{
+       int     i, j;
+       my_u_int32_t    packed_keys[2];
+       my_u_char_t     *p;
+
+       p = (my_u_char_t *) packed_keys;
+
+       for (i = 0; i < 8; i++) {
+               p[i] = 0;
+               for (j = 0; j < 8; j++)
+                       if (*key++ & 1)
+                               p[i] |= bits8[j];
+       }
+       des_setkey(p);
+}
+
+
+void
+encrypt(char *block, int flag)
+{
+       my_u_int32_t    io[2];
+       my_u_char_t     *p;
+       int     i, j;
+
+       des_init();
+
+       setup_salt(0L);
+       p = block;
+       for (i = 0; i < 2; i++) {
+               io[i] = 0L;
+               for (j = 0; j < 32; j++)
+                       if (*p++ & 1)
+                               io[i] |= bits32[j];
+       }
+       do_des(io[0], io[1], io, io + 1, flag ? -1 : 1);
+       for (i = 0; i < 2; i++)
+               for (j = 0; j < 32; j++)
+                       block[(i << 5) | j] = (io[i] & bits32[j]) ? 1 : 0;
+}
+
+char *crypt(const char *key, const char *setting)
+{
+       my_u_int32_t    count, salt, l, r0, r1, keybuf[2];
+       my_u_char_t             *p, *q;
+       static char     output[21];
+
+       des_init();
+
+       /*
+        * Copy the key, shifting each character up by one bit
+        * and padding with zeros.
+        */
+       q = (my_u_char_t *)keybuf;
+       while (q - (my_u_char_t *)keybuf - 8) {
+               *q++ = *key << 1;
+               if (*(q - 1))
+                       key++;
+       }
+       if (des_setkey((char *)keybuf))
+               return(NULL);
+
+#if 0
+       if (*setting == _PASSWORD_EFMT1) {
+               int             i;
+               /*
+                * "new"-style:
+                *      setting - underscore, 4 bytes of count, 4 bytes of salt
+                *      key - unlimited characters
+                */
+               for (i = 1, count = 0L; i < 5; i++)
+                       count |= ascii_to_bin(setting[i]) << ((i - 1) * 6);
+
+               for (i = 5, salt = 0L; i < 9; i++)
+                       salt |= ascii_to_bin(setting[i]) << ((i - 5) * 6);
+
+               while (*key) {
+                       /*
+                        * Encrypt the key with itself.
+                        */
+                       if (des_cipher((char *)keybuf, (char *)keybuf, 0L, 1))
+                               return(NULL);
+                       /*
+                        * And XOR with the next 8 characters of the key.
+                        */
+                       q = (my_u_char_t *)keybuf;
+                       while (q - (my_u_char_t *)keybuf - 8 && *key)
+                               *q++ ^= *key++ << 1;
+
+                       if (des_setkey((char *)keybuf))
+                               return(NULL);
+               }
+               strncpy(output, setting, 9);
+
+               /*
+                * Double check that we weren't given a short setting.
+                * If we were, the above code will probably have created
+                * wierd values for count and salt, but we don't really care.
+                * Just make sure the output string doesn't have an extra
+                * NUL in it.
+                */
+               output[9] = '\0';
+               p = (my_u_char_t *)output + strlen(output);
+       } else 
+#endif
+       {
+               /*
+                * "old"-style:
+                *      setting - 2 bytes of salt
+                *      key - up to 8 characters
+                */
+               count = 25;
+
+               salt = (ascii_to_bin(setting[1]) << 6)
+                    |  ascii_to_bin(setting[0]);
+
+               output[0] = setting[0];
+               /*
+                * If the encrypted password that the salt was extracted from
+                * is only 1 character long, the salt will be corrupted.  We
+                * need to ensure that the output string doesn't have an extra
+                * NUL in it!
+                */
+               output[1] = setting[1] ? setting[1] : output[0];
+
+               p = (my_u_char_t *)output + 2;
+       }
+       setup_salt(salt);
+       /*
+        * Do it.
+        */
+       if (do_des(0L, 0L, &r0, &r1, (int)count))
+               return(NULL);
+       /*
+        * Now encode the result...
+        */
+       l = (r0 >> 8);
+       *p++ = ascii64[(l >> 18) & 0x3f];
+       *p++ = ascii64[(l >> 12) & 0x3f];
+       *p++ = ascii64[(l >> 6) & 0x3f];
+       *p++ = ascii64[l & 0x3f];
+
+       l = (r0 << 16) | ((r1 >> 16) & 0xffff);
+       *p++ = ascii64[(l >> 18) & 0x3f];
+       *p++ = ascii64[(l >> 12) & 0x3f];
+       *p++ = ascii64[(l >> 6) & 0x3f];
+       *p++ = ascii64[l & 0x3f];
+
+       l = r1 << 2;
+       *p++ = ascii64[(l >> 12) & 0x3f];
+       *p++ = ascii64[(l >> 6) & 0x3f];
+       *p++ = ascii64[l & 0x3f];
+       *p = 0;
+
+       return(output);
+}
+
diff --git a/menu/libmenu/des.h b/menu/libmenu/des.h
new file mode 100644 (file)
index 0000000..a03e58a
--- /dev/null
@@ -0,0 +1,9 @@
+
+#ifndef _DES_H_
+#define _DES_H_
+
+// des crypt
+extern char *crypt (const char *key, const char *salt);
+
+#endif
+
diff --git a/menu/libmenu/help.c b/menu/libmenu/help.c
new file mode 100644 (file)
index 0000000..d591156
--- /dev/null
@@ -0,0 +1,84 @@
+/* -*- 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"
+
+char helpbasedir[HELPDIRLEN]; // name of help directory limited to HELPDIRLEN
+
+void showhelp(const char *filename)
+{
+   char nc,nr;
+   FILE *f;
+   char line[512]; // Max length of a line
+
+   nc = getnumcols();
+   nr = getnumrows();
+   cls();
+   drawbox(0,0,nr,nc-1,HELPPAGE,0x07,HELPBOX);
+
+   drawhorizline(2,0,nc-1,HELPPAGE,0x07,HELPBOX,0); // dumb==0
+   if (filename == NULL) { // print file contents
+     gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE);
+     cswprint("Help system not initialized",0x07,HELP_LEFT_MARGIN);
+     return;
+   }
+   
+   f = fopen(filename,"r");
+   if (!f) { // No such file
+      sprintf(line, "File %s not found",filename);
+      gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE);
+      cswprint(line,0x07,HELP_LEFT_MARGIN);
+      return;
+   }
+
+   // Now we have a file just print it.
+   fgets(line,sizeof line,f); // Get first line (TITLE)
+   gotoxy(1,(nc-strlen(line))/2,HELPPAGE);
+   csprint(line,0x07);
+
+   gotoxy(HELP_BODY_ROW,HELP_LEFT_MARGIN,HELPPAGE);
+   while ( fgets(line, sizeof line, f) ) cswprint(line,0x07,HELP_LEFT_MARGIN);
+   fclose(f);
+}
+
+void runhelpsystem(unsigned int helpid)
+{
+   char dp;
+   char scan;
+   char filename[HELPDIRLEN+16];
+
+   dp = getdisppage();
+   if (dp != HELPPAGE) setdisppage(HELPPAGE);
+   if (helpbasedir[0] != 0) {
+      sprintf(filename,"%s/hlp%05d.txt",helpbasedir,helpid);
+      showhelp(filename);
+   }
+   else showhelp (NULL);
+   while (1) {
+     inputc(&scan);
+     if (scan == ESCAPE) break;
+   }
+   if (dp != HELPPAGE) setdisppage(dp);
+}
+
+void init_help(const char *helpdir)
+{
+   if (helpdir != NULL)
+      strcpy(helpbasedir,helpdir);
+   else helpbasedir[0] = 0;
+}
+
+void close_help(void)
+{
+}
diff --git a/menu/libmenu/help.h b/menu/libmenu/help.h
new file mode 100644 (file)
index 0000000..45ef9d6
--- /dev/null
@@ -0,0 +1,39 @@
+/* -*- c -*- ------------------------------------------------------------- *
+ *   
+ *   Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef __HELP_H_
+#define __HELP_H_
+
+#include "menu.h"
+#include "com32io.h"
+#include "tui.h"
+#include <string.h>
+
+// How many rows for the title
+#define HELP_TITLE_HEIGHT 1
+#define HELP_BODY_ROW (HELP_TITLE_HEIGHT+3)
+#define HELP_LEFT_MARGIN 2
+#define HELPBOX BOX_SINSIN
+#define HELPDIRLEN  64
+
+// Display one screen of help information
+void showhelp(const char *filename);
+
+// Start the help system using id helpid
+void runhelpsystem(unsigned int helpid);
+
+// Directory where help files are located
+void init_help(const char *helpdir);
+// Free internal datastructures
+void close_help(void);
+
+#endif
similarity index 59%
rename from menu/menu.c
rename to menu/libmenu/menu.c
index a576952..7d7e76d 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- c -*- ------------------------------------------------------------- *
  *
- *   Copyright 2004 Murali Krishnan Ganapathy - All Rights Reserved
+ *   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
  *
  * ----------------------------------------------------------------------- */
 
-/* This program can be compiled for DOS with the OpenWatcom compiler
- * (http://www.openwatcom.org/):
- *
- * wcl -3 -osx -mt getargs.c
- */
-
-#include "biosio.h"
-#include "string.h"
 #include "menu.h"
-#include "heap.h"
+#include <stdlib.h>
 
 // Local Variables
 static pt_menusystem ms; // Pointer to the menusystem
-static char TITLESTR[] = "COMBOOT Menu System for SYSLINUX developed by Murali Krishnan Ganapathy";
-static char TITLELONG[] = " TITLE too long ";
-static char ITEMLONG[] = " ITEM too long ";
-static char ACTIONLONG[] = " ACTION too long ";
-static char STATUSLONG[] = " STATUS too long ";
-static char EMPTYSTR[] = "";
+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 */
 
@@ -68,10 +71,10 @@ char getch(char *scan)
 
 /* Print a menu item */
 /* attr[0] is non-hilite attr, attr[1] is highlight attr */
-void printmenuitem(const char *str,char* attr)
+void printmenuitem(const char *str,uchar* attr)
 {
-    char page = getdisppage();
-    char row,col;
+    uchar page = getdisppage();
+    uchar row,col;
     int hlite=NOHLITE; // Initially no highlighting
 
     getpos(&row,&col,page);
@@ -114,61 +117,7 @@ void printmenuitem(const char *str,char* attr)
     }
 }
 
-void drawbox(char top, char left, char bot, char right,char attr, char page)
-{
-  char x;
-    
-  // Top border
-  gotoxy(top,left,page);
-  cprint(TOPLEFT,attr,1,page);
-  gotoxy(top,left+1,page);
-  cprint(TOP,attr,right-left,page);
-  gotoxy(top,right,page);
-  cprint(TOPRIGHT,attr,1,page);
-  // Bottom border
-  gotoxy(bot,left,page);
-  cprint(BOTLEFT,attr,1,page);
-  gotoxy(bot,left+1,page);
-  cprint(BOT,attr,right-left,page);
-  gotoxy(bot,right,page);
-  cprint(BOTRIGHT,attr,1,page);
-  // Left & right borders
-  for (x=top+1; x < bot; x++)
-    {
-      gotoxy(x,left,page);
-      cprint(LEFT,attr,1,page);
-      gotoxy(x,right,page);
-      cprint(RIGHT,attr,1,page);
-    }
-}
-
-int next_visible(pt_menu menu, int index) // Return index of next visible
-{
-  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 next 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 find_shortcut(pt_menu menu,char shortcut, int index) 
+int find_shortcut(pt_menu menu,uchar shortcut, int index) 
 // Find the next index with specified shortcut key
 {
   int ans;
@@ -199,35 +148,39 @@ int find_shortcut(pt_menu menu,char shortcut, int index)
   return index; // Sorry not found
 }
 
-void printmenu(pt_menu menu, int curr, char top, char left)
+// print the menu starting from FIRST
+// will print a maximum of menu->menuheight items
+void printmenu(pt_menu menu, int curr, uchar top, uchar left, uchar first)
 {
   int x,row; // x = index, row = position from top
   int numitems,menuwidth;
   char fchar[5],lchar[5]; // The first and last char in for each entry
   const char *str;  // and inbetween the item or a seperator is printed
-  char *attr;  // attribute attr
+  uchar *attr;  // attribute attr
   char sep[MENULEN];// and inbetween the item or a seperator is printed
   pt_menuitem ci;
   
-  calc_visible(menu);
-  numitems = menu->numvisible;
+  numitems = calc_visible(menu,first);
+  if (numitems > menu->menuheight) numitems = menu->menuheight;
+
   menuwidth = menu->menuwidth+3;
   clearwindow(top,left-2, top+numitems+1, left+menuwidth+1,
              ms->menupage, ms->fillchar, ms->shadowattr);
-  drawbox(top-1, left-3, top+numitems, left+menuwidth, 
-         ms->normalattr[NOHLITE], ms->menupage);
-  memset(sep,HORIZ,menuwidth); // String containing the seperator string
+  drawbox(top-1,left-3,top+numitems,left+menuwidth,
+          ms->menupage,ms->normalattr[NOHLITE],ms->menubt);
+  memset(sep,ms->box_horiz,menuwidth); // String containing the seperator string
   sep[menuwidth-1] = 0; 
   // Menu title
   x = (menuwidth - strlen(menu->title) - 1) >> 1;
   gotoxy(top-1,left+x,ms->menupage);
   printmenuitem(menu->title,ms->normalattr);
   row = -1; // 1 less than inital value of x
-  for (x=0; x < menu->numitems; x++)
+  for (x=first; x < menu->numitems; x++)
     {
       ci = menu->items[x];
       if (ci->action == OPT_INVISIBLE) continue;
       row++;
+      if (row >= numitems) break; // Already have enough number of items
       // Setup the defaults now
       lchar[0] = fchar[0] = ' '; 
       lchar[1] = fchar[1] = '\0'; // fchar and lchar are just spaces
@@ -249,8 +202,8 @@ void printmenu(pt_menu menu, int curr, char top, char left)
          lchar[1] = 0;
          break;
        case OPT_SEP:
-         fchar[0] = '\b'; fchar[1] = LTRT; fchar[2] = HORIZ; fchar[3] = HORIZ; fchar[4] = 0;
-         lchar[0] = HORIZ; lchar[1] = RTLT; lchar[2] = 0;
+         fchar[0] = '\b'; fchar[1] = ms->box_ltrt; fchar[2] = ms->box_horiz; fchar[3] = ms->box_horiz; fchar[4] = 0;
+         lchar[0] = ms->box_horiz; lchar[1] = ms->box_rtlt; lchar[2] = 0;
          str = sep;
          break;
        case OPT_EXITMENU:
@@ -268,40 +221,65 @@ void printmenu(pt_menu menu, int curr, char top, char left)
       gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any
       csprint(lchar,attr[NOHLITE]); // Print last part
     }
+  // Check if we need to MOREABOVE and MOREBELOW to be added
+  // reuse x 
+  row = 0;
+  x = next_visible_sep(menu,0); // First item
+  if (! isvisible(menu,first,x)) // There is more above
+  {
+     row = 1;
+     gotoxy(top,left+menuwidth,ms->menupage);
+     cprint(MOREABOVE,ms->normalattr[NOHLITE],1,ms->menupage);
+  }
+  x = prev_visible_sep(menu,menu->numitems); // last item
+  if (! isvisible(menu,first,x)) // There is more above
+  {
+     row = 1;
+     gotoxy(top+numitems-1,left+menuwidth,ms->menupage);
+     cprint(MOREBELOW,ms->normalattr[NOHLITE],1,ms->menupage);
+  }
+  // Add a scroll box
+  x = ((numitems-1)*curr)/(menu->numitems);
+  if ((x>0) && (row==1)) {
+  gotoxy(top+x,left+menuwidth,ms->menupage);
+  cprint(SCROLLBOX,ms->normalattr[NOHLITE],1,ms->menupage);
+  }
   if (ms->handler) ms->handler(ms,menu->items[curr]);
 }
 
 // Difference between this and regular menu, is that only 
 // OPT_INVISIBLE, OPT_SEP are honoured 
-void printradiomenu(pt_menu menu, int curr, char top, char left)
+void printradiomenu(pt_menu menu, int curr, uchar top, uchar left, int first)
 {
   int x,row; // x = index, row = position from top
   int numitems,menuwidth;
   char fchar[5],lchar[5]; // The first and last char in for each entry
   const char *str;  // and inbetween the item or a seperator is printed
-  char *attr;  // all in the attribute attr
+  uchar *attr;  // all in the attribute attr
   char sep[MENULEN];// and inbetween the item or a seperator is printed
   pt_menuitem ci;
   
-  calc_visible(menu);
-  numitems = menu->numvisible;
+  numitems = calc_visible(menu,first);
+  if (numitems > menu->menuheight) numitems = menu->menuheight;
+
   menuwidth = menu->menuwidth+3;
   clearwindow(top,left-2, top+numitems+1, left+menuwidth+1,
              ms->menupage, ms->fillchar, ms->shadowattr);
-  drawbox(top-1, left-3, top+numitems, left+menuwidth, 
-         ms->normalattr[NOHLITE], ms->menupage);
-  memset(sep,HORIZ,menuwidth); // String containing the seperator string
+  drawbox(top-1,left-3,top+numitems,left+menuwidth,
+          ms->menupage,ms->normalattr[NOHLITE],ms->menubt);
+  memset(sep,ms->box_horiz,menuwidth); // String containing the seperator string
   sep[menuwidth-1] = 0; 
   // Menu title
   x = (menuwidth - strlen(menu->title) - 1) >> 1;
   gotoxy(top-1,left+x,ms->menupage);
   printmenuitem(menu->title,ms->normalattr);
   row = -1; // 1 less than inital value of x
-  for (x=0; x < menu->numitems; x++)
+  for (x=first; x < menu->numitems; x++)
     {
       ci = menu->items[x];
       if (ci->action == OPT_INVISIBLE) continue;
       row++;
+      if (row > numitems) break;
       // Setup the defaults now
       fchar[0] = RADIOUNSEL; fchar[1]='\0'; // Unselected ( )
       lchar[0] = '\0'; // Nothing special after 
@@ -314,8 +292,8 @@ void printradiomenu(pt_menu menu, int curr, char top, char left)
          attr = ms->inactattr;
          break;
        case OPT_SEP:
-         fchar[0] = '\b'; fchar[1] = LTRT; fchar[2] = HORIZ; fchar[3] = HORIZ; fchar[4] = 0;
-         lchar[0] = HORIZ; lchar[1] = RTLT; lchar[3] = 0;
+         fchar[0] = '\b'; fchar[1] = ms->box_ltrt; fchar[2] = ms->box_horiz; fchar[3] = ms->box_horiz; fchar[4] = 0;
+         lchar[0] = ms->box_horiz; lchar[1] = ms->box_rtlt; lchar[3] = 0;
          str = sep;
          break;
        default: // To keep the compiler happy
@@ -330,28 +308,52 @@ void printradiomenu(pt_menu menu, int curr, char top, char left)
       gotoxy(top+row,left+menuwidth-1,ms->menupage); // Last char if any
       csprint(lchar,attr[NOHLITE]); // Print last part
     }
+  // Check if we need to MOREABOVE and MOREBELOW to be added
+  // reuse x 
+  row = 0;
+  x = next_visible_sep(menu,0); // First item
+  if (! isvisible(menu,first,x)) // There is more above
+  {
+     row = 1;
+     gotoxy(top,left+menuwidth,ms->menupage);
+     cprint(MOREABOVE,ms->normalattr[NOHLITE],1,ms->menupage);
+  }
+  x = prev_visible_sep(menu,menu->numitems); // last item
+  if (! isvisible(menu,first,x)) // There is more above
+  {
+     row = 1;
+     gotoxy(top+numitems-1,left+menuwidth,ms->menupage);
+     cprint(MOREBELOW,ms->normalattr[NOHLITE],1,ms->menupage);
+  }
+  // Add a scroll box
+  x = ((numitems-1)*curr)/(menu->numitems);
+  if ((x > 0) && (row == 1))
+  {
+     gotoxy(top+x,left+menuwidth,ms->menupage);
+     cprint(SCROLLBOX,ms->normalattr[NOHLITE],1,ms->menupage);
+  }
   if (ms->handler) ms->handler(ms,menu->items[curr]);
 }
 
-void cleanupmenu(pt_menu menu, char top,char left)
+void cleanupmenu(pt_menu menu, uchar top,uchar left,int numitems)
 {
-  clearwindow(top,left-2, top+menu->numvisible+1, left+menu->menuwidth+4,
+  if (numitems > menu->menuheight) numitems = menu->menuheight;
+  clearwindow(top,left-2, top+numitems+1, left+menu->menuwidth+4,
              ms->menupage, ms->fillchar, ms->fillattr); // Clear the shadow
-  clearwindow(top-1, left-3, top+menu->numvisible, left+menu->menuwidth+3,
+  clearwindow(top-1, left-3, top+numitems, left+menu->menuwidth+3,
              ms->menupage, ms->fillchar, ms->fillattr); // main window
 }
 
 /* Handle a radio menu */
-pt_menuitem getradiooption(pt_menu menu, char top, char left, char startopt)
+pt_menuitem getradiooption(pt_menu menu, uchar top, uchar left, uchar startopt)
      // Return item chosen or NULL if ESC was hit.
 {
-  int curr,i;
-  char asc,scan;
-  char numitems;
+  int curr,i,first,tmp;
+  uchar asc,scan;
+  uchar numitems;
   pt_menuitem ci; // Current item
     
-  calc_visible(menu);
-  numitems = menu->numvisible;
+  numitems = calc_visible(menu,0);
   // Setup status line
   gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
   cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage);
@@ -363,9 +365,10 @@ pt_menuitem getradiooption(pt_menu menu, char top, char left, char startopt)
   cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,1);
   gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
   printmenuitem(menu->items[curr]->status,ms->statusattr);
+  first = calc_first_early(menu,curr);
   while (1) // Forever
     {
-      printradiomenu(menu,curr,top,left);
+      printradiomenu(menu,curr,top,left,first);
       ci = menu->items[curr];
       
       asc = getch(&scan);
@@ -373,21 +376,28 @@ pt_menuitem getradiooption(pt_menu menu, char top, char left, char startopt)
         {
        case HOMEKEY:
          curr = next_visible(menu,0);
+          first = calc_first_early(menu,curr);
          break;
        case ENDKEY:
          curr = prev_visible(menu,numitems-1);
+          first = calc_first_late(menu,curr);
          break;
        case PAGEDN:
          for (i=0; i < 5; i++) curr = next_visible(menu,curr+1);
+          first = calc_first_late(menu,curr);
          break;
        case PAGEUP:
          for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1);
+          first = calc_first_early(menu,curr);
          break;
        case UPARROW:
          curr = prev_visible(menu,curr-1);
+          if (curr < first) first = calc_first_early(menu,curr);
          break;
        case DNARROW:
          curr = next_visible(menu,curr+1);
+          if (! isvisible(menu,first,curr)) 
+               first = calc_first_late(menu,curr);
          break;
        case LTARROW:
        case ESCAPE:
@@ -405,7 +415,18 @@ pt_menuitem getradiooption(pt_menu menu, char top, char left, char startopt)
          if (((asc >= 'A') && (asc <= 'Z')) ||
              ((asc >= 'a') && (asc <= 'z')) ||
              ((asc >= '0') && (asc <= '9')))
-           curr = find_shortcut(menu,asc,curr);
+          {
+           tmp = find_shortcut(menu,asc,curr);
+            if ((tmp > curr) && (! isvisible(menu,first,tmp)))
+                  first = calc_first_late(menu,tmp);
+            if (tmp < curr) 
+               first = calc_first_early(menu,tmp);
+            curr = tmp;
+          }
+          else {
+            if (ms->keys_handler) // Call extra keys handler
+               ms->keys_handler(ms,menu->items[curr],(scan << 8) | asc);
+          }
          break;
         }
       // Update status line
@@ -417,16 +438,16 @@ pt_menuitem getradiooption(pt_menu menu, char top, char left, char startopt)
 }
 
 /* Handle one menu */
-pt_menuitem getmenuoption( pt_menu menu, char top, char left, char startopt)
+pt_menuitem getmenuoption(pt_menu menu, uchar top, uchar left, uchar startopt)
      // Return item chosen or NULL if ESC was hit.
 {
-  int curr,i;
-  char asc,scan;
-  char numitems;
+  int curr,i,first,tmp;
+  uchar asc,scan;
+  uchar numitems;
   pt_menuitem ci; // Current item
+  t_handler_return hr; // Return value of handler
     
-  calc_visible(menu);
-  numitems = menu->numvisible;
+  numitems = calc_visible(menu,0);
   // Setup status line
   gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
   cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,ms->menupage);
@@ -438,30 +459,38 @@ pt_menuitem getmenuoption( pt_menu menu, char top, char left, char startopt)
   cprint(ms->spacechar,ms->statusattr[NOHLITE],ms->numcols,1);
   gotoxy(ms->minrow+ms->statline,ms->mincol,ms->menupage);
   printmenuitem(menu->items[curr]->status,ms->statusattr);
+  first = calc_first_early(menu,curr);
   while (1) // Forever
     {
-      printmenu(menu,curr,top,left);
+      printmenu(menu,curr,top,left,first);
       ci = menu->items[curr];
       asc = getch(&scan);
       switch (scan)
         {
        case HOMEKEY:
          curr = next_visible(menu,0);
+          first = calc_first_early(menu,curr);
          break;
        case ENDKEY:
          curr = prev_visible(menu,numitems-1);
+          first = calc_first_late(menu,curr);
          break;
        case PAGEDN:
          for (i=0; i < 5; i++) curr = next_visible(menu,curr+1);
+          first = calc_first_late(menu,curr);
          break;
        case PAGEUP:
          for (i=0; i < 5; i++) curr = prev_visible(menu,curr-1);
+          first = calc_first_early(menu,curr);
          break;
        case UPARROW:
          curr = prev_visible(menu,curr-1);
+          if (curr < first) first = calc_first_early(menu,curr);
          break;
        case DNARROW:
          curr = next_visible(menu,curr+1);
+          if (! isvisible(menu,first,curr)) 
+               first = calc_first_late(menu,curr);
          break;
        case LTARROW:
        case ESCAPE:
@@ -474,20 +503,58 @@ pt_menuitem getmenuoption( pt_menu menu, char top, char left, char startopt)
          if (ci->action == OPT_CHECKBOX) break;
          if (ci->action == OPT_SEP) break;
          if (ci->action == OPT_EXITMENU) return NULL; // As if we hit Esc
-         return ci;
+          // If we are going into a radio menu, dont call handler, return ci
+          if (ci->action == OPT_RADIOMENU) return ci;
+          if (ci->handler != NULL) // Do we have a handler
+          {
+             hr = ci->handler(ms,ci);  
+             if (hr.refresh) // Do we need to refresh
+             {
+                // Cleanup menu using old number of items
+                cleanupmenu(menu,top,left,numitems); 
+                // Recalculate the number of items
+                numitems = calc_visible(menu,0);
+                // Reprint the menu
+                printmenu(menu,curr,top,left,first);
+             }
+             if (hr.valid) return ci; 
+          }
+          else return ci;
          break;
        case SPACEKEY:
-         if (ci->action != OPT_CHECKBOX) break;
-         ci->itemdata.checked = !ci->itemdata.checked;
-         // Call handler to see it anything needs to be done
-         if (ci->handler != NULL) ci->handler(ms,ci); 
-         break;
+          if (ci->action != OPT_CHECKBOX) break;
+          ci->itemdata.checked = !ci->itemdata.checked;
+          if (ci->handler != NULL) // Do we have a handler
+          {
+             hr = ci->handler(ms,ci);  
+             if (hr.refresh) // Do we need to refresh
+             {
+                // Cleanup menu using old number of items
+                cleanupmenu(menu,top,left,numitems); 
+                // Recalculate the number of items
+                numitems = calc_visible(menu,0);
+                // Reprint the menu
+                printmenu(menu,curr,top,left,first);
+             }
+          }
+          break;
        default:
          // Check if this is a shortcut key
          if (((asc >= 'A') && (asc <= 'Z')) ||
              ((asc >= 'a') && (asc <= 'z')) ||
              ((asc >= '0') && (asc <= '9')))
-           curr = find_shortcut(menu,asc,curr);
+          {
+           tmp = find_shortcut(menu,asc,curr);
+            if ((tmp > curr) && (! isvisible(menu,first,tmp)))
+                  first = calc_first_late(menu,tmp);
+            if (tmp < curr) 
+               first = calc_first_early(menu,tmp);
+            curr = tmp;
+          }
+          else {
+            if (ms->keys_handler) // Call extra keys handler
+               ms->keys_handler(ms,menu->items[curr],(scan << 8) | asc);
+          }
          break;
         }
       // Update status line
@@ -499,7 +566,7 @@ pt_menuitem getmenuoption( pt_menu menu, char top, char left, char startopt)
 }
 
 /* Handle the entire system of menu's. */
-pt_menuitem runmenusystem(char top, char left, pt_menu cmenu, char startopt, char menutype)
+pt_menuitem runmenusystem(uchar top, uchar left, pt_menu cmenu, uchar startopt, uchar menutype)
      /*
       * cmenu
       *    Which menu should be currently displayed
@@ -515,11 +582,15 @@ pt_menuitem runmenusystem(char top, char left, pt_menu cmenu, char startopt, cha
       */
 {
   pt_menuitem opt,choice;
-  char startat,mt;
-  char row,col;
+  uchar startat,mt;
+  uchar row,col;
 
   if (cmenu == NULL) return NULL;
  startover:
+  // Set the menu height
+  cmenu->menuheight = ms->maxrow - top-3;
+  if (cmenu->menuheight > ms->maxmenuheight) 
+     cmenu->menuheight = ms->maxmenuheight;
   if (menutype == NORMALMENU)
     opt = getmenuoption(cmenu,top,left,startopt);
   else // menutype == RADIOMENU
@@ -528,13 +599,13 @@ pt_menuitem runmenusystem(char top, char left, pt_menu cmenu, char startopt, cha
   if (opt == NULL)
     {
       // User hit Esc
-      cleanupmenu(cmenu,top,left);
+      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);
+      cleanupmenu(cmenu,top,left,calc_visible(cmenu,0));
       return opt; // parent cleanup other menus
     }
   // Either radiomenu or submenu
@@ -544,7 +615,7 @@ pt_menuitem runmenusystem(char top, char left, pt_menu cmenu, char startopt, cha
     {
       gotoxy(12,12,ms->menupage); // Middle of screen
       csprint("ERROR: Invalid submenu requested.",0x07);
-      cleanupmenu(cmenu,top,left);
+      cleanupmenu(cmenu,top,left,calc_visible(cmenu,0));
       return NULL; // Pretend user hit esc
     }
   // Call recursively for submenu
@@ -565,7 +636,7 @@ pt_menuitem runmenusystem(char top, char left, pt_menu cmenu, char startopt, cha
   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); // Call handler
+      if (opt->handler != NULL) opt->handler(ms,opt);  
       choice = NULL; // Pretend user hit esc
     }
   if (choice==NULL) // User hit Esc in submenu
@@ -576,17 +647,17 @@ pt_menuitem runmenusystem(char top, char left, pt_menu cmenu, char startopt, cha
     }
   else
     {
-      cleanupmenu(cmenu,top,left);
+      cleanupmenu(cmenu,top,left,calc_visible(cmenu,0));
       return choice;
     }
 }
 
 /* User Callable functions */
 
-pt_menuitem showmenus(char startmenu)
+pt_menuitem showmenus(uchar startmenu)
 {
   pt_menuitem rv;
-  char oldpage,tpos;
+  uchar oldpage,tpos;
 
   // Setup screen for menusystem
   oldpage = getdisppage();
@@ -614,20 +685,21 @@ pt_menuitem showmenus(char startmenu)
   return rv;
 }
 
-void init_menusystem(const char *title)
+pt_menusystem init_menusystem(const char *title)
 {
   int i;
     
   ms = NULL;
   ms = (pt_menusystem) malloc(sizeof(t_menusystem));
-  if (ms == NULL) return;
+  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)
-    ms->title = TITLESTR; // Copy pointers
-  else ms->title = title;
+    strcpy(ms->title,TITLESTR); // Copy string
+  else strcpy(ms->title,title);
 
   // Timeout settings
   ms->tm_stepsize = TIMEOUTSTEPSIZE;
@@ -658,9 +730,18 @@ void init_menusystem(const char *title)
   ms->shadowattr = SHADOWATTR;
 
   ms->menupage = MENUPAGE; // Usually no need to change this at all
-  ms->handler = NULL; // No handler function
+
+  // Initialise all handlers
+  ms->handler = NULL;
+  ms->keys_handler = NULL; 
   ms->ontimeout=NULL; // No timeout handler
 
+  // Setup ACTION_{,IN}VALID
+  ACTION_VALID.valid=1;
+  ACTION_VALID.refresh=0;
+  ACTION_INVALID.valid = 0;
+  ACTION_INVALID.refresh = 0;
+
   // Figure out the size of the screen we are in now.
   // By default we use the whole screen for our menu
   ms->minrow = ms->mincol = 0;
@@ -668,9 +749,18 @@ void init_menusystem(const char *title)
   ms->numrows = getnumrows();
   ms->maxcol = ms->numcols - 1;
   ms->maxrow = ms->numrows - 1;
+
+  // How many entries per menu can we display at a time
+  ms->maxmenuheight = ms->maxrow - ms->minrow - 3;
+  if (ms->maxmenuheight > MAXMENUHEIGHT) 
+      ms->maxmenuheight= MAXMENUHEIGHT; 
+
+  // Set up the look of the box
+  set_box_type(MENUBOXTYPE);
+  return ms;
 }
 
-void set_normal_attr(char normal, char selected, char inactivenormal, char inactiveselected)
+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;
@@ -678,7 +768,7 @@ void set_normal_attr(char normal, char selected, char inactivenormal, char inact
   if (inactiveselected != 0xFF) ms->revinactattr[0] = inactiveselected;
 }
 
-void set_normal_hlite(char normal, char selected, char inactivenormal, char 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;
@@ -686,8 +776,7 @@ void set_normal_hlite(char normal, char selected, char inactivenormal, char inac
   if (inactiveselected != 0xFF) ms->revinactattr[1] = inactiveselected;
 }
 
-
-void set_status_info(char statusattr, char statushlite, char statline)
+void set_status_info(uchar statusattr, uchar statushlite, uchar statline)
 {
   if (statusattr != 0xFF) ms->statusattr[NOHLITE] = statusattr;
   if (statushlite!= 0xFF) ms->statusattr[HLITE] = statushlite;
@@ -696,13 +785,13 @@ void set_status_info(char statusattr, char statushlite, char statline)
   ms->statline = statline; // relative to ms->minrow, 0 based
 }
 
-void set_title_info(char tfillchar, char titleattr)
+void set_title_info(uchar tfillchar, uchar titleattr)
 {
   if (tfillchar  != 0xFF) ms->tfillchar  = tfillchar;
   if (titleattr  != 0xFF) ms->titleattr  = titleattr;
 }
 
-void set_misc_info(char fillchar, char fillattr,char spacechar, char shadowattr)
+void set_misc_info(uchar fillchar, uchar fillattr,uchar spacechar, uchar shadowattr)
 {
   if (fillchar  != 0xFF) ms->fillchar  = fillchar;
   if (fillattr  != 0xFF) ms->fillattr  = fillattr;
@@ -710,10 +799,26 @@ void set_misc_info(char fillchar, char fillattr,char spacechar, char shadowattr)
   if (shadowattr!= 0xFF) ms->shadowattr= shadowattr;
 }
 
-void set_window_size(char top, char left, char bot, char right) // Set the window which menusystem should use
+void set_box_type(boxtype bt)
+{
+  uchar *bxc;
+  ms->menubt = bt;
+  bxc = getboxchars(bt);
+  ms->box_horiz = bxc[BOX_HORIZ]; // The char used to draw top line
+  ms->box_ltrt = bxc[BOX_LTRT]; 
+  ms->box_rtlt = bxc[BOX_RTLT]; 
+}
+
+void set_menu_options(uchar maxmenuheight) 
+{
+  if (maxmenuheight != 0xFF) ms->maxmenuheight = maxmenuheight;
+}
+
+// Set the window which menusystem should use
+void set_window_size(uchar top, uchar left, uchar bot, uchar right) 
 {
     
-  char nr,nc;
+  uchar nr,nc;
   if ((top > bot) || (left > right)) return; // Sorry no change will happen here
   nr = getnumrows();
   nc = getnumcols();
@@ -728,14 +833,29 @@ void set_window_size(char top, char left, char bot, char right) // Set the windo
   if (ms->statline >= ms->numrows) ms->statline = ms->numrows - 1; // Clip statline if need be
 }
 
-void reg_handler( t_menusystem_handler handler)
+void reg_handler( t_handler htype, void * handler)
 {
-  ms->handler = 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()
+void unreg_handler(t_handler htype)
 {
-  ms->handler = NULL;
+  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)
@@ -750,19 +870,108 @@ void unreg_ontimeout()
   ms->ontimeout = 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;
+}
 
-void calc_visible(pt_menu menu)
+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;  
+  if (menu == NULL) return 0;  
   ans = 0;
-  for (i=0; i < menu->numitems; i++)
+  for (i=first; i < menu->numitems; i++)
     if (menu->items[i]->action != OPT_INVISIBLE) ans++;
-  menu->numvisible = ans;
+  return ans;
 }
 
-char add_menu(const char *title) // Create a new menu and return its position
+// 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;
@@ -776,21 +985,26 @@ char add_menu(const char *title) // Create a new menu and return its position
   m->numitems = 0;
   m->row = 0xFF;
   m->col = 0xFF;
-  for (i=0; i < MAXMENUSIZE; i++) m->items[i] = NULL;
+  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)
-       m->title = TITLELONG;
-      else m->title = title
+       strcpy(m->title,TITLELONG);
+      else strcpy(m->title,title)
     }
-  else m->title = EMPTYSTR
+  else strcpy(m->title,EMPTYSTR)
   m ->menuwidth = strlen(m->title);
   ms->nummenus ++;
   return ms->nummenus - 1;
 }
 
-void set_menu_pos(char row,char col) // Set the position of this menu.
+void set_menu_pos(uchar row,uchar col) // Set the position of this menu.
 {
   pt_menu m;
 
@@ -810,22 +1024,23 @@ pt_menuitem add_sep() // Add a separator to current menu
   if (mi == NULL) return NULL;
   m->items[(unsigned int)m->numitems] = mi;
   mi->handler = NULL; // No handler
-  mi->item = mi->status = mi->data = EMPTYSTR;
+  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, char itemdata) 
+                    const char *data, uchar itemdata) 
 {
   pt_menuitem mi;
   pt_menu m;
   const char *str;
-  char inhlite=0; // Are we inside hlite area
+  uchar inhlite=0; // Are we inside hlite area
 
   m = (ms->menus[ms->nummenus-1]);
   mi = NULL;
@@ -833,26 +1048,33 @@ pt_menuitem add_item(const char *item, const char *status, t_action action,
   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 - 2) {
-      mi->item = ITEMLONG
+    if (strlen(item) > MENULEN) {
+      strcpy(mi->item,ITEMLONG)
     } else {
-      mi->item = item; 
-      if (strlen(item) > m->menuwidth) m->menuwidth = strlen(item);
+      strcpy(mi->item,item); 
     }
-  } else mi->item = EMPTYSTR; 
+    if (strlen(mi->item) > m->menuwidth) m->menuwidth = strlen(mi->item);
+  } else strcpy(mi->item,EMPTYSTR); 
 
   if (status) {
-    if (strlen(status) > STATLEN - 2) {
-      mi->status = STATUSLONG
+    if (strlen(status) > STATLEN) {
+      strcpy(mi->status,STATUSLONG)
     } else {
-      mi->status = status
+      strcpy(mi->status,status)
     }
-  } else mi->status = EMPTYSTR
+  } else strcpy(mi->status,EMPTYSTR)
     
-  mi->action = action;
+  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)
@@ -879,12 +1101,12 @@ pt_menuitem add_item(const char *item, const char *status, t_action action,
     mi->shortcut = mi->shortcut -'A'+'a';
 
   if (data) {
-    if (strlen(data) > ACTIONLEN - 2) {
-      mi->data = ACTIONLONG
+    if (strlen(data) > ACTIONLEN) {
+      strcpy(mi->data,ACTIONLONG)
     } else {
-      mi->data = data
+      strcpy(mi->data,data)
     }
-  } else mi->data = EMPTYSTR;
+  } else strcpy(mi->data,EMPTYSTR);
 
   switch (action)
     {
@@ -907,7 +1129,7 @@ pt_menuitem add_item(const char *item, const char *status, t_action action,
 }
 
 // Set the shortcut key for the current item
-void set_shortcut(char shortcut)
+void set_item_options(uchar shortcut,int helpid)
 {
   pt_menuitem mi;
   pt_menu m;
@@ -915,5 +1137,12 @@ void set_shortcut(char shortcut)
   m = (ms->menus[ms->nummenus-1]); 
   if (m->numitems <= 0) return;
   mi = m->items[(unsigned int) m->numitems-1];
-  mi->shortcut = shortcut;
+
+  if (shortcut != 0xFF) mi->shortcut = shortcut;
+  if (helpid != 0xFFFF) mi->helpid = helpid;
+}
+
+// Free internal datasutructures
+void close_menusystem(void)
+{
 }
similarity index 54%
rename from menu/menu.h
rename to menu/libmenu/menu.h
index fe03d79..1e0a619 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- c -*- ------------------------------------------------------------- *
  *
- *   Copyright 2004 Murali Krishnan Ganapathy - All Rights Reserved
+ *   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
 #ifndef __MENU_H__
 #define __MENU_H__
 
-#include "biosio.h"
-#include "string.h"
+#include "com32io.h"
+#include "tui.h"
+#include "syslnx.h"
+#include "scancodes.h"
+#include <string.h>
 
 // TIMEOUT PARAMETERS
 /* If no key is pressed within TIMEOUTNUMSTEPS * TIMEOUTSTEPSIZE milliseconds
 #define TIMEOUTSTEPSIZE 10  
 #define TIMEOUTNUMSTEPS 30000L
 
-// Scancodes of some keys
-#define ESCAPE     1
-#define ENTERA    28
-#define ENTERB   224
-
-#define HOMEKEY  71
-#define UPARROW  72
-#define PAGEUP   73
-#define LTARROW  75
-#define RTARROW  77
-#define ENDKEY   79
-#define DNARROW  80
-#define PAGEDN   81
-#define SPACEKEY 57 // Scan code for SPACE
-
 // Attributes
 #define NORMALATTR    0x17
 #define NORMALHLITE   0x1F // Normal Highlight attribute
 #define NOHLITE       0   // The offset into attrib array for non-hilite
 #define HLITE         1   // The offset for Hlite attrib
 
-// Single line Box drawing Chars
-
-#define TOPLEFT  218
-#define BOTLEFT  192
-#define TOPRIGHT 191
-#define BOTRIGHT 217
-#define TOP      196
-#define BOT      196
-#define LEFT     179
-#define RIGHT    179
-#define HORIZ    196
-#define LTRT     195 // The |- char
-#define RTLT     180 // The -| char
-
-// Double line Box Drawing Chars
-/*
-#define TOPLEFT  201
-#define BOTLEFT  200
-#define TOPRIGHT 187
-#define BOTRIGHT 188
-#define TOP      205
-#define BOT      205
-#define LEFT     186
-#define RIGHT    186
-#define HORIZ    205
-#define LTRT     199 // The ||- char
-#define RTLT     182 // The -|| char
-*/
+#define MOREABOVE    24 // char to print when more menu items available above
+#define MOREBELOW    25 // more items available below
+#define SCROLLBOX    176 // Filled char to display
 
 // Attributes of the menu system
-#define MAXMENUS      8 // Maximum number of menu's allowed
-#define MAXMENUSIZE   12 // Maximum number of entries in each menu
+#define MAXMENUS      10 // Maximum number of menu's allowed
+#define MAXMENUSIZE   30 // Default value for max num of entries in each menu
+#define MAXMENUHEIGHT 14 // Maximum number of entries displayed
+#define MENUBOXTYPE   BOX_SINSIN // Default box type Look at tui.h for other values
 
 // Upper bounds on lengths
-// Now that the onus of allocating space is with the user, these numbers
-// are only for sanity checks. You may increase these values without
-// affecting the memory footprint of this program
-#define MENULEN       30 // Each menu entry is atmost MENULEN chars
+// We copy the given string, so user can reuse the space used to store incoming arguments.
+#define MENULEN       40 // Each menu entry is atmost MENULEN chars
 #define STATLEN       80 // Maximum length of status string
-#define ACTIONLEN     80 // Maximum length of an action string
+#define TITLELEN       80 // 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      23 // Line number where status line starts (relative to window)
+#define HELPPAGE      2  // Use this page for any additional information
+#define STATLINE      24 // Line number where status line starts (relative to window)
+
+// Used for printing debugging messages
+#define DEBUGLINE     23  // debugging info goes here
 
 // Other Chars
 #define SUBMENUCHAR   175 // This is >> symbol
 #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
@@ -149,17 +119,31 @@ typedef enum {OPT_INACTIVE, OPT_SUBMENU, OPT_RUN, OPT_EXITMENU, OPT_CHECKBOX,
              OPT_RADIOITEM} t_action;
 
 typedef union {
-  char submenunum; // For submenu's
-  char checked; // For check boxes
-  char radiomenunum; // Item mapping to a radio menu
+  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 void (*t_item_handler)(struct s_menusystem *, struct s_menuitem *);
+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
@@ -167,56 +151,66 @@ typedef enum {CODE_WAIT, CODE_ENTER, CODE_ESCAPE } TIMEOUTCODE;
 typedef TIMEOUTCODE (*t_timeout_handler)(void);
 
 typedef struct s_menuitem {
-  const char *item;
-  const char *status;
-  const char *data; // string containing kernel to run.. but... 
+  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)
   void * extra_data; // Any other data user can point to
   t_item_handler handler; // Pointer to function of type menufn
   t_action action;
   t_itemdata itemdata; // Data depends on action value
-  char shortcut; // one of [A-Za-z0-9] shortcut for this menu item
-  char index; // Index within the menu array
-  char parindex; // Index of the menu in which this item appears. 
+  unsigned int helpid; // context sensitive help system ID
+  uchar shortcut; // one of [A-Za-z0-9] shortcut for this menu item
+  uchar index; // Index within the menu array
+  uchar parindex; // Index of the menu in which this item appears. 
 } t_menuitem;
 
 typedef t_menuitem *pt_menuitem; // Pointer to type menuitem
 
 typedef struct s_menu {
-  pt_menuitem items[MAXMENUSIZE];
-  const char *title;
-  char numitems;
-  char numvisible;
-  char menuwidth;
-  char row,col; // Position where this menu should be displayed
+  pt_menuitem *items; // pointer to array of pointer to menuitems
+  char *title;
+  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];
-  const char *title; 
-  t_menusystem_handler handler; // Handler function called every time a menu is re-printed.
+  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)
-  unsigned long tm_numsteps; // Time to wait for key press=numsteps * stepsize milliseconds
-
-  char nummenus;
-  char normalattr[2]; // [0] is non-hlite attr, [1] is hlite attr
-  char reverseattr[2];
-  char inactattr[2];
-  char revinactattr[2];
-  char statusattr[2];
-  char fillchar;
-  char fillattr;
-  char spacechar;
-  char tfillchar;
-  char titleattr;
-  char shadowattr;
-  char statline;
-  char menupage;
-  char maxrow,minrow,numrows; // Number of rows in the window 
-  char maxcol,mincol,numcols; // Number of columns in the window
+
+  int maxmenuheight;
+  uchar nummenus;
+  uchar normalattr[2]; // [0] is non-hlite attr, [1] is hlite attr
+  uchar reverseattr[2];
+  uchar inactattr[2];
+  uchar revinactattr[2];
+  uchar statusattr[2];
+  uchar fillchar;
+  uchar fillattr;
+  uchar spacechar;
+  uchar tfillchar;
+  uchar titleattr;
+  uchar shadowattr;
+  uchar statline;
+  uchar menupage;
+  uchar maxrow,minrow,numrows; // Number of rows in the window 
+  uchar maxcol,mincol,numcols; // Number of columns in the window
+
+  // Menu box look
+  boxtype menubt; // What type of boxes should be drawn 
+  char box_horiz,box_ltrt,box_rtlt; // Some chars of the box, for redrawing portions of the box
+
 } t_menusystem;
 
 typedef t_menusystem *pt_menusystem; // Pointer to type menusystem
@@ -237,25 +231,30 @@ typedef t_menusystem *pt_menusystem; // Pointer to type menusystem
  ***************************************************************************
  */
 
-pt_menuitem showmenus(char startmenu);
+pt_menuitem showmenus(uchar startmenu);
 
-void init_menusystem(const char *title); // This pointer value is stored internally
+pt_menusystem init_menusystem(const char *title); 
+void close_menusystem(); // Deallocate memory used
 
-void set_normal_attr(char normal, char selected, char inactivenormal, char inactiveselected);
+void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected);
 
-void set_normal_hlite(char normal, char selected, char inactivenormal, char inactiveselected);
+void set_normal_hlite(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected);
 
-void set_status_info(char statusattr, char statushlite, char statline);
+void set_status_info(uchar statusattr, uchar statushlite, uchar statline);
 
-void set_title_info(char tfillchar, char titleattr);
+void set_title_info(uchar tfillchar, uchar titleattr);
 
-void set_misc_info(char fillchar, char fillattr,char spacechar, char shadowattr);
+void set_misc_info(uchar fillchar, uchar fillattr,uchar spacechar, uchar shadowattr);
+void set_box_type(boxtype bt);
 
-void set_window_size(char top, char left, char bot, char right); // Set the window which menusystem should use
+void set_window_size(uchar top, uchar left, uchar bot, uchar right); // Set the window which menusystem should use
 
-void reg_handler( t_menusystem_handler handler); // Register handler
+void set_menu_options(uchar maxmenuheight); 
+// maximum height of a menu
 
-void unreg_handler(); 
+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.
@@ -263,21 +262,25 @@ void reg_ontimeout(t_timeout_handler, unsigned int numsteps, unsigned int stepsi
 void unreg_ontimeout();
 
 // Create a new menu and return its position
-char add_menu(const char *title); // This pointer value is stored internally
+uchar add_menu(const char *title, int maxmenusize); 
+
+void set_menu_pos(uchar row,uchar col); // Set the position of this menu.
 
-void set_menu_pos(char row,char 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);
 
-// Add item to the "current" menu // pointer values are stored internally
-pt_menuitem add_item(const char *item, const char *status, t_action action, const char *data, char itemdata);
+// Set shortcut key and help id
+void set_item_options(uchar shortcut,int helpid);
 
-void set_shortcut(char shortcut); // Set the shortcut key for the current item
+// 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();
 
-// Calculate the number of visible items
-void calc_visible(pt_menu menu);
-
 // Main function for the user's config file
 int menumain(char *cmdline);
 
diff --git a/menu/libmenu/passwords.c b/menu/libmenu/passwords.c
new file mode 100644 (file)
index 0000000..d7ada29
--- /dev/null
@@ -0,0 +1,140 @@
+/* -*- c -*- ------------------------------------------------------------- *
+ *   
+ *   Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Bostom MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include "passwords.h"
+#include "des.h"
+#include "string.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "tui.h"
+
+#define MAX_LINE 512 
+// Max line length in a pwdfile
+p_pwdentry userdb[MAX_USERS]; // Array of pointers
+int numusers; // Actual number of users
+
+// returns true or false, i.e. 1 or 0
+char authenticate_user(const char * username, const char* pwd)
+{
+  char salt[12];
+  int  i, password_ok;
+
+  password_ok=0;
+
+  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 (strcmp(username,GUEST_USER) == 0) return 0;
+  dperm = (char *) malloc(strlen(perm)+3);
+  strcpy(dperm+1,perm);
+  dperm[0] = ':';
+  dperm[strlen(perm)+1]=':';
+  dperm[strlen(perm)+2]=0;
+  // Now dperm = ":perm:"
+  for (i=0; i < numusers; i++) {
+     if (strcmp(userdb[i]->username,username)==0) // Found the user
+     {
+        if (userdb[i]->perms == NULL) return 0; // No permission
+        tmp = strstr(userdb[i]->perms,dperm); // Search for permission
+        free (dperm); // Release memory
+        if (tmp == NULL) return 0; else return 1;
+     }
+  }
+  // User not found return 0
+  free (dperm);
+  return 0;
+}
+
+// Initialise the list of of user passwords permissions from file
+void init_passwords(const char *filename)
+{
+  int i;
+  char line[MAX_LINE], *p,*user,*pwdhash,*perms;
+  FILE *f;
+
+  for (i=0; i < MAX_USERS; i++) userdb[i] = NULL;
+  numusers = 0;
+  if ( !filename ) return; // No filename specified
+
+  f = fopen(filename,"r");
+  if ( !f ) return; // File does not exist
+
+  // Process each line
+  while ( fgets(line, sizeof line, f) ) {
+    // Replace EOLN with \0
+    p = strchr(line, '\r');
+    if ( p ) *p = '\0';
+    p = strchr(line, '\n');
+    if ( p ) *p = '\0';
+
+    // If comment line or empty ignore line
+    p = line;
+    while (*p==' ') p++; // skip initial spaces
+    if ( (*p == '#') || (*p == '\0')) continue; // Skip comment lines
+
+    user = p; // This is where username starts
+    p = strchr(user,':');
+    if (p == NULL) continue; // Malformed line skip
+    *p = '\0';
+    pwdhash = p+1;
+    if (*pwdhash == 0) continue; // Malformed line (no password specified)
+    p = strchr(pwdhash,':'); 
+    if (p == NULL) { // No perms specified
+       perms = NULL;
+    } else {
+       *p = '\0';
+       perms = p+1;
+       if (*perms == 0) perms = NULL;
+    }
+    // At this point we have user,pwdhash and perms setup 
+    userdb[numusers] = (p_pwdentry)malloc(sizeof(pwdentry));
+    strcpy(userdb[numusers]->username,user);
+    strcpy(userdb[numusers]->pwdhash,pwdhash);
+    if (perms == NULL)
+      userdb[numusers]->perms = NULL;
+    else {
+      userdb[numusers]->perms = (char *)malloc(strlen(perms)+3);
+      (userdb[numusers]->perms)[0] = ':';
+      strcpy(userdb[numusers]->perms + 1,perms);
+      (userdb[numusers]->perms)[strlen(perms)+1] = ':';
+      (userdb[numusers]->perms)[strlen(perms)+2] = 0;
+      // Now perms field points to ":perms:"
+    }
+    numusers++;
+  }
+  fclose(f);
+}
+
+void close_passwords()
+{
+  int i;
+
+  for (i=0; i < numusers; i++)
+    if (userdb[i] != NULL) free(userdb[i]);
+  numusers = 0;
+}
diff --git a/menu/libmenu/passwords.h b/menu/libmenu/passwords.h
new file mode 100644 (file)
index 0000000..1e68e3e
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _PASSWORDS_H_
+#define _PASSWORDS_H_
+    
+char authenticate_user(const char * username, const char* pwd);
+
+char isallowed(const char *username, const char * perm);
+
+// Initialise the list of of user passwords permissions from file
+void init_passwords(const char *filename);
+// Free all space used for internal data structures
+void close_passwords();
+
+#define MAX_USERS 128       // Maximum number of users
+#define USERNAME_LENGTH 12  // Max length of user name
+#define PWDHASH_LENGTH  40  // Max lenght of pwd hash
+
+typedef struct {
+  char username[USERNAME_LENGTH+1];
+  char pwdhash[PWDHASH_LENGTH+1]; 
+  char *perms; // pointer to string containing ":" delimited permissions
+} pwdentry;
+
+typedef pwdentry *p_pwdentry;
+
+#define GUEST_USER "guest"
+
+#endif
diff --git a/menu/libmenu/scancodes.h b/menu/libmenu/scancodes.h
new file mode 100644 (file)
index 0000000..8331884
--- /dev/null
@@ -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 __SCANCODES_H__
+#define __SCANCODES_H__
+
+// Scancodes of some keys
+#define ESCAPE     1
+#define ENTERA    28
+#define ENTERB   224
+
+#define HOMEKEY  71
+#define UPARROW  72
+#define PAGEUP   73
+#define LTARROW  75
+#define RTARROW  77
+#define ENDKEY   79
+#define DNARROW  80
+#define PAGEDN   81
+#define INSERT   82
+#define DELETE   83
+#define SPACEKEY 57 // Scan code for SPACE
+
+#define CTRLLT 0x73
+#define CTRLRT 0x74
+
+#define F1  0x3B
+#define F2  0x3C
+#define F3  0x3D
+#define F4  0x3E
+#define F5  0x3F
+#define F6  0x40
+#define F7  0x41
+#define F8  0x42
+#define F9  0x43
+#define F10 0x44
+#define F11 0x85
+#define F12 0x86
+
+#define CTRLF1  0x5E
+#define CTRLF2  0x5F
+#define CTRLF3  0x60
+#define CTRLF4  0x61
+#define CTRLF5  0x62
+#define CTRLF6  0x63
+#define CTRLF7  0x64
+#define CTRLF8  0x65
+#define CTRLF9  0x66
+#define CTRLF10 0x67
+#define CTRLF11 0x89
+#define CTRLF12 0x8A
+
+#define ALTF1   0x68
+#define ALTF2   0x69
+#define ALTF3   0x6A
+#define ALTF4   0x6B
+#define ALTF5   0x6C
+#define ALTF6   0x6D
+#define ALTF7   0x6E
+#define ALTF8   0x6F
+#define ALTF9   0x70
+#define ALTF10  0x71
+#define ALTF11  0x8B
+#define ALTF12  0x8C
+
+#endif
diff --git a/menu/libmenu/syslnx.c b/menu/libmenu/syslnx.c
new file mode 100644 (file)
index 0000000..66a11ae
--- /dev/null
@@ -0,0 +1,44 @@
+/* -*- c -*- ------------------------------------------------------------- *
+ *   
+ *   Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <string.h>
+#include <com32.h>
+#include "syslnx.h"
+
+com32sys_t inreg,outreg; // Global registers for this module
+
+char issyslinux(void)
+{
+  REG_EAX(inreg) = 0x00003000;
+  REG_EBX(inreg) = REG_ECX(inreg) = REG_EDX(inreg) = 0xFFFFFFFF;
+  __intcall(0x21,&inreg,&outreg);
+  return (REG_EAX(outreg) == 0x59530000) && 
+         (REG_EBX(outreg) == 0x4c530000) &&
+         (REG_ECX(outreg) == 0x4e490000) && 
+         (REG_EDX(outreg) == 0x58550000);
+}
+
+void runsyslinuxcmd(const char *cmd)
+{
+  strcpy(__com32.cs_bounce, cmd);
+  REG_AX(inreg) = 0x0003; // Run command
+  REG_BX(inreg) = OFFS(__com32.cs_bounce);
+  inreg.es = SEG(__com32.cs_bounce);
+  __intcall(0x22, &inreg, &outreg);
+}
+
+void gototxtmode(void)
+{
+  REG_AX(inreg) = 0x0005;
+  __intcall(0x22,&inreg,&outreg);
+}
+
diff --git a/menu/libmenu/syslnx.h b/menu/libmenu/syslnx.h
new file mode 100644 (file)
index 0000000..7d0281b
--- /dev/null
@@ -0,0 +1,47 @@
+/* -*- 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)
+
+char issyslinux(void);         /* Check if syslinux is running */
+
+void runsyslinuxcmd(const char *cmd); /* Run specified command */
+
+void gototxtmode(void); /* Change mode to text mode */
+
+#endif
diff --git a/menu/libmenu/tui.c b/menu/libmenu/tui.c
new file mode 100644 (file)
index 0000000..ad19f46
--- /dev/null
@@ -0,0 +1,360 @@
+/* -*- 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 "tui.h"
+#include "syslnx.h"
+#include "com32io.h"
+#include "scancodes.h"
+#include <stdlib.h>
+
+com32sys_t inreg,outreg; // Global register sets for use
+
+char bkspstr[] = " \b$";
+char eolstr[] = "\n$";
+#define GETSTRATTR 0x07
+
+// Reads a line of input from stdin. Replace CR with NUL byte
+// password <> 0 implies not echoed on screen
+// showoldvalue <> 0 implies currentvalue displayed first
+// If showoldvalue <> 0 then caller responsibility to ensure that
+// str is NULL terminated.
+void getuserinput(char *stra, unsigned int size, unsigned int password, 
+  unsigned int showoldvalue)
+{
+    unsigned char c,scan;
+    char *p,*q; // p = current char of string, q = tmp
+    char *last; // The current last char of string
+    char *str; // pointer to string which is going to be allocated
+    char page;
+    char row,col;
+    char start,end; // Cursor shape
+    char fudge; // How many chars should be removed from output
+    char insmode; // Are we in insert or overwrite
+
+    page = getdisppage();
+    getpos(&row,&col,page); // Get current position
+    getcursorshape(&start,&end);
+    insmode = 1;
+
+    str = (char *)malloc(size+1); // Allocate memory to store user input
+    memset(str,0,size+1); // Zero it out
+    if (password != 0) showoldvalue = 0; // Password's never displayed
+
+    if (showoldvalue != 0) strcpy(str,stra); // If show old value copy current value
+
+    last = str;
+    while (*last) {last++;} // Find the terminating null byte
+    p = str+ strlen(str);
+
+    if (insmode == 0)
+       setcursorshape(1,7); // Block cursor
+    else setcursorshape(6,7); // Normal cursor
+
+    // Invariants: p is the current char
+    // col is the corresponding column on the screen
+    if (password == 0) // Not a password, print initial value
+    { 
+       gotoxy(row,col,page);
+       csprint(str,GETSTRATTR);
+    }
+    while (1) { // Do forever
+      c = inputc(&scan);
+      if (c == '\r') break; // User hit Enter getout of loop
+      if (scan == ESCAPE) // User hit escape getout and nullify string
+      { *str = 0;
+        break;
+      }
+      fudge = 0;
+        // if scan code is regognized do something 
+        // else if char code is recognized do something
+        // else ignore
+      switch(scan) {
+        case HOMEKEY:
+             p = str;
+             break;
+        case ENDKEY:
+             p = last;
+             break;
+        case LTARROW:
+             if (p > str) p--;
+             break;
+        case CTRLLT: 
+             if (p==str) break;
+             if (*p == ' ') 
+                while ((p > str) && (*p == ' ')) p--;
+             else {
+                if (*(p-1) == ' ') {
+                   p--; 
+                   while ((p > str) && (*p == ' ')) p--;
+                }
+             }
+             while ((p > str) && ((*p == ' ') || (*(p-1) != ' '))) p--;
+             break;
+        case RTARROW:
+             if (p < last) p++;
+             break;
+        case CTRLRT: 
+             if (*p==0) break; // At end of string
+             if (*p != ' ') 
+                while ((*p!=0) && (*p != ' ')) p++;
+             while ((*p!=0) && ((*p == ' ') && (*(p+1) != ' '))) p++;
+             if (*p==' ') p++;
+             break;
+        case DELETE:
+             q = p;
+             while (*(q+1)) {*q = *(q+1); q++; }
+             if (last > str) last--;
+             fudge = 1;
+             break;
+        case INSERT:
+           insmode = 1-insmode; // Switch mode
+           if (insmode == 0)
+              setcursorshape(1,7); // Block cursor
+           else setcursorshape(6,7); // Normal cursor
+           break;
+
+        default: // Unrecognized scan code, look at the ascii value
+         switch (c) {
+         case '\b': // Move over by one
+              q=p;
+             while ( q <= last ) { *(q-1)=*q; q++;}
+              if (last > str) last--;
+              if (p > str) p--;
+              fudge = 1;
+             break;
+         case '\x15':          /* Ctrl-U: kill input */
+              fudge = last-str;
+             while ( p > str ) *p--=0;
+              p = str; *p=0; last = str;
+             break;
+         default: // Handle insert and overwrite mode
+             if ((c >= ' ') && (c < 128) && 
+                  ((unsigned int)(p-str) < size-1) ) {
+                if (insmode == 0) { // Overwrite mode
+                  if (p==last) last++;
+                  *last = 0;
+                 *p++ = c;
+                } else {  // Insert mode
+                  if (p==last) { // last char
+                     last++;
+                     *last=0;
+                     *p++=c;
+                  } else { // Non-last char
+                     q=last++;
+                     while (q >= p) { *q=*(q-1); q--;}
+                     *p++=c;
+                  }
+                }
+              }
+              else beep();
+         }
+         break;
+       }
+        // Now the string has been modified, print it
+        if (password == 0) {
+          gotoxy(row,col,page);
+          csprint(str,GETSTRATTR);
+          if (fudge > 0) cprint(' ',GETSTRATTR,fudge,page);
+          gotoxy(row,col+(p-str),page);
+        }
+      }
+    *p = '\0';
+    if (password == 0) csprint("\r\n",GETSTRATTR);
+    setcursorshape(start,end); // Block cursor
+    // If user hit ESCAPE so return without any changes
+    if (scan != ESCAPE) strcpy(stra,str);
+    free(str);
+}
+
+/* Print a C string (NUL-terminated) */
+void cswprint(const char *str,char attr,char left)
+{
+    char page = getdisppage();
+    char newattr=0,cha,chb;
+    char row,col;
+    char nr,nc;
+
+    nr = getnumrows();
+    nc = getnumcols();
+    getpos(&row,&col,page);
+    while ( *str ) {
+      switch (*str) 
+       {
+       case '\b':
+         --col;
+         break;
+       case '\n':
+         ++row;
+          col = left;
+         break;
+       case '\r':
+         //col=left;
+         break;
+       case BELL: // Bell Char
+         beep();
+         break;
+       case CHRELATTR: // change attribute (relatively)
+       case CHABSATTR: // change attribute (absolute)
+         cha = *(str+1);
+         chb = *(str+2);
+         if ((((cha >= '0') && (cha <= '9')) || 
+              ((cha >= 'A') && (cha <= 'F'))) &&
+             (((chb >= '0') && (chb <= '9')) || 
+              ((chb >= 'A') && (chb <= 'F')))) // Next two chars are legal
+           {
+             if ((cha >= 'A') && (cha <= 'F'))
+               cha = cha - 'A'+10;
+             else cha = cha - '0';
+             if ((chb >= 'A') && (chb <= 'F'))
+               chb = chb - 'A'+10;
+             else chb = chb - '0';
+             newattr = (cha << 4) + chb;
+             attr = (*str == CHABSATTR ? newattr : attr ^ newattr);
+             str += 2; // Will be incremented again later
+           }
+         break;
+       default:
+         putch(*str, attr, page);
+         ++col;
+       }
+      if (col >= nc)
+       {
+         ++row;
+         col=left;
+       }
+      if (row > nr)
+       {
+         scrollup();
+         row= nr;
+       }
+      gotoxy(row,col,page);
+      str++;
+    }
+}
+
+void clearwindow(char top, char left, char bot, char right, char page, char fillchar, char fillattr)
+{
+    char x;
+    for (x=top; x < bot+1; x++)
+    {
+        gotoxy(x,left,page);
+        cprint(fillchar,fillattr,right-left+1,page);
+    }
+}
+
+void cls(void)
+{
+  unsigned char dp = getdisppage();
+  gotoxy(0,0,dp);
+  cprint(' ',GETSTRATTR,(1+getnumrows())*getnumcols(),dp);
+}
+
+//////////////////////////////Box Stuff
+
+// This order of numbers must match
+// the values of BOX_TOPLEFT,... in the header file
+
+unsigned char SINSIN_CHARS[] = {218,192,191,217, //Corners
+                              196,179, // Horiz and Vertical
+                              195,180,194,193,197}; // Connectors & Middle
+
+unsigned char DBLDBL_CHARS[] = {201,200,187,188,  // Corners
+                              205,186, // Horiz and Vertical
+                              199,182,203,202,206}; // Connectors & Middle
+
+unsigned char SINDBL_CHARS[] =  {214,211,183,189, // Corners
+                                 196,186, // Horiz & Vert
+                                 199,182,210,208,215}; // Connectors & Middle
+
+unsigned char DBLSIN_CHARS[] = {213,212,184,190, // Corners
+                                205,179, // Horiz & Vert
+                                198,181,209,207,216}; // Connectors & Middle
+
+unsigned char * getboxchars(boxtype bt)
+{
+   switch (bt)
+   {
+     case BOX_SINSIN: 
+          return SINSIN_CHARS;
+          break;
+     case BOX_DBLDBL:
+          return DBLDBL_CHARS;
+          break;
+     case BOX_SINDBL:
+          return SINDBL_CHARS;
+          break;
+     case BOX_DBLSIN:
+          return DBLSIN_CHARS;
+          break;
+     default:
+          return SINSIN_CHARS;
+          break;
+   }
+   return SINSIN_CHARS;
+}
+
+// Draw box and lines
+void drawbox(char top,char left,char bot, char right, 
+             char page, char attr,boxtype bt)
+{
+   unsigned char *box_chars; // pointer to array of box chars
+   unsigned char x;
+    
+  box_chars = getboxchars(bt);
+  // Top border
+  gotoxy(top,left,page);
+  cprint(box_chars[BOX_TOPLEFT],attr,1,page);
+  gotoxy(top,left+1,page);
+  cprint(box_chars[BOX_TOP],attr,right-left,page);
+  gotoxy(top,right,page);
+  cprint(box_chars[BOX_TOPRIGHT],attr,1,page);
+  // Bottom border
+  gotoxy(bot,left,page);
+  cprint(box_chars[BOX_BOTLEFT],attr,1,page);
+  gotoxy(bot,left+1,page);
+  cprint(box_chars[BOX_BOT],attr,right-left,page);
+  gotoxy(bot,right,page);
+  cprint(box_chars[BOX_BOTRIGHT],attr,1,page);
+  // Left & right borders
+  for (x=top+1; x < bot; x++)
+    {
+      gotoxy(x,left,page);
+      cprint(box_chars[BOX_LEFT],attr,1,page);
+      gotoxy(x,right,page);
+      cprint(box_chars[BOX_RIGHT],attr,1,page);
+    }
+}
+
+void drawhorizline(char top, char left, char right, char page, char attr, 
+                   boxtype bt, char dumb)
+{
+  unsigned char start,end;
+  unsigned char *box_chars = getboxchars(bt);
+  if (dumb==0) {
+    start = left+1;
+    end = right-1;
+  } else {
+    start = left;
+    end = right;
+  }
+  gotoxy(top,start,page);
+  cprint(box_chars[BOX_HORIZ],attr,end-start+1,page);
+  if (dumb == 0)
+  {
+    gotoxy(top,left,page);
+    cprint(box_chars[BOX_LTRT],attr,1,page);
+    gotoxy(top,right,page); 
+    cprint(box_chars[BOX_RTLT],attr,1,page);
+  }
+}
diff --git a/menu/libmenu/tui.h b/menu/libmenu/tui.h
new file mode 100644 (file)
index 0000000..07020ad
--- /dev/null
@@ -0,0 +1,85 @@
+/* -*- 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 "com32io.h"
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define BELL 0x07
+// CHRELATTR = ^N, CHABSATTR = ^O
+#define CHABSATTR 15 
+#define CHRELATTR 14
+
+void clearwindow(char top, char left, char bot, char right, 
+                char page, char fillchar, char fillattr);
+
+void cls(void);        /* Clears the entire current screen page */
+
+// Generic user input, 
+// password = 0 iff chars echoed on screen
+// showoldvalue <> 0 iff current displayed for editing
+void getuserinput(char *str, unsigned int size, 
+     unsigned int password, unsigned int showoldvalue);
+
+static inline void getstring(char *str, unsigned int size) 
+{
+   getuserinput(str,size,0,0);
+}
+
+static inline void editstring(char *str, unsigned int size)
+{
+   getuserinput(str,size,0,1);
+}
+
+static inline void getpwd(char * str, unsigned int size)
+{
+   getuserinput(str,size,1,0);
+}
+
+// Box drawing Chars offsets into array
+#define BOX_TOPLEFT  0x0
+#define BOX_BOTLEFT  0x1
+#define BOX_TOPRIGHT 0x2
+#define BOX_BOTRIGHT 0x3
+#define BOX_TOP      0x4 // TOP = BOT = HORIZ
+#define BOX_BOT      0x4
+#define BOX_HORIZ    0x4
+#define BOX_LEFT     0x5
+#define BOX_RIGHT    0x5
+#define BOX_VERT     0x5 // LEFT=RIGHT=VERT
+#define BOX_LTRT     0x6 
+#define BOX_RTLT     0x7 
+#define BOX_TOPBOT   0x8
+#define BOX_BOTTOP   0x9
+#define BOX_MIDDLE   0xA
+
+typedef enum {BOX_SINSIN,BOX_DBLDBL, BOX_SINDBL, BOX_DBLSIN} boxtype;
+
+unsigned char * getboxchars(boxtype bt);
+
+void drawbox(char top,char left,char bot, char right, 
+             char page, char attr,boxtype bt);
+
+// Draw a horizontal line
+// dumb == 1, means just draw the line
+// dumb == 0 means check the first and last positions and depending on what is
+//    currently on the screen make it a LTRT and/or RTLT appropriately.
+void drawhorizline(char top, char left, char right, char page, char attr,
+                   boxtype bt, char dumb);
+
+#endif
diff --git a/menu/main.c b/menu/main.c
deleted file mode 100644 (file)
index c09476c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- c -*- ------------------------------------------------------------- *
- *   
- *   Copyright 2004 Murali Krishnan Ganapathy - All Rights Reserved
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
- *   Boston MA 02111-1307, USA; either version 2 of the License, or
- *   (at your option) any later version; incorporated herein by reference.
- *
- * ----------------------------------------------------------------------- */
-
-#ifndef NULL
-#define NULL ((void *) 0)
-#endif
-
-#include "menu.h"
-#include "biosio.h"
-#include "string.h"
-#include "syslinux.h"
-#include "heap.h"
-
-int syslinux;
-
-int _cstart(char *cmdline)
-{
-  int rv;
-
-  syslinux = issyslinux();      /* Find if syslinux is running */
-  if (syslinux) gototxtmode();  /* (else assume we are running in DOS) */
-
-  rv = menumain(cmdline);      /* Run the actual menu system */
-
-  return rv;
-}
-
diff --git a/menu/password b/menu/password
new file mode 100644 (file)
index 0000000..00fc7cb
--- /dev/null
@@ -0,0 +1,19 @@
+# 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 a20274c..2458909 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- c -*- ------------------------------------------------------------- *
  *   
- *   Copyright 2004 Murali Krishnan Ganapathy - All Rights Reserved
+ *   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
 #endif
 
 #include "menu.h"
-#include "biosio.h"
-#include "string.h"
-#include "syslinux.h"
+#include "com32io.h"
+#include <string.h>
 
-int menumain(char *cmdline)
+int main(void)
 {
   t_menuitem * curr;
 
   char TESTING,RESCUE,MAIN;    /* The menus we're going to declare */
-  (void)cmdline;               /* Not used */
 
   // Change the video mode here
   // setvideomode(0)
@@ -40,7 +38,7 @@ int menumain(char *cmdline)
   //set_title_info  (-1,-1); 
   //set_misc_info(-1,-1,-1,-1);
   
-  // menuindex = add_menu(" Menu Title ");
+  // menuindex = add_menu(" 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" not used by the menu system, useful for storing kernel names
@@ -48,18 +46,18 @@ int menumain(char *cmdline)
   //         0/1 default checked state if OPT_CHECKBOX
   //         unused otherwise.
 
-  TESTING = add_menu(" Testing ");
+  TESTING = add_menu(" Testing ",-1);
   add_item("Self Loop","Go to testing",OPT_SUBMENU,NULL,TESTING);
   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);
 
-  RESCUE = add_menu(" Rescue Options ");
+  RESCUE = add_menu(" 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);
 
-  MAIN = add_menu(" Main Menu ");  
+  MAIN = add_menu(" Main Menu ",-1);  
   add_item("Prepare","prep",OPT_RUN,"prep",0);
   add_item("Rescue options...","Troubleshoot a system",OPT_SUBMENU,NULL,RESCUE);
   add_item("Testing...","Options to test hardware",OPT_SUBMENU,NULL,TESTING);
@@ -70,7 +68,7 @@ int menumain(char *cmdline)
   {
         if (curr->action == OPT_RUN)
         {
-            if (syslinux) runcommand(curr->data);
+            if (issyslinux()) runsyslinuxcmd(curr->data);
             else csprint(curr->data,0x07);
             return 1;
         }
diff --git a/menu/startup.S16 b/menu/startup.S16
deleted file mode 100644 (file)
index ccdc776..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-       .code16gcc
-
-       .globl _start
-_start:
-       /* Make sure stack pointer is normalized */
-       movzwl %sp,%esp
-
-       /* Zero .bss */
-       movw $__bss_start,%di
-       xorl %eax,%eax
-       movw $(_end+3),%cx
-       subw %di,%cx
-       shrw $2,%cx
-       cld
-       rep ; stosl
-
-       /* Normalize the command line.  At startup 0x80 = length and
-          the command line starts at 0x81, but with whitespace */
-       movl $0x81,%esi
-       movzbw (0x80),%bx
-       movb $0,(%bx,%si)               /* Null-terminate the string */
-1:
-       lodsb
-       dec %al                         /* Stop on null */
-       cmp $31,%al                     /* Whitespace? */
-       jbe 1b
-       dec %si                         /* Unskip first character */
-
-       /* Invoke _cstart */
-       pushl %esi                      /* Pointer to command line */
-       calll _cstart
-
-       /* Terminate program (with error code in %al) */
-       movb $0x4c,%ah
-       int $0x21
-       hlt
-
diff --git a/menu/string.c b/menu/string.c
deleted file mode 100644 (file)
index 6206fdf..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- c -*- ------------------------------------------------------------- *
- *
- *   Copyright 2004 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"
-
-/* String routines */
-void *memset(void *buf, int chr, unsigned int len)
-{
-  asm("cld ; rep ; stosb" : "+D" (buf), "+c" (len) : "a" (chr));
-  return buf;
-}
-
-char *strcpy(char *dst, const char *src)
-{
-  char *r = dst;
-  char c;
-
-  do { 
-    c = *src++;
-    *dst++ = c;
-  } while ( c );
-
-  return r;
-}
-
-char *strcat(char *dst, const char * src)
-{
-  char *r = dst;
-
-  while (*dst++); // Find end of string
-  dst--;
-  while (*src) *dst++ = *src++; // Append
-  *dst = '\0'; // Terminate string
-
-  return r;
-}
-
-int strcmp(const char *a, const char*b)
-{
-    while (*a)
-    {
-        if (*a < *b) return -1;
-        if (*a++ > *b++) return 1;
-    }
-    if (*b) return 1; else return 0;
-}
-
-int strlen(const char *a)
-{
-  int ans = 0;
-  
-  while (*a++) ans++;
-  return ans;
-}
-
diff --git a/menu/string.h b/menu/string.h
deleted file mode 100644 (file)
index 359e15b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-
-#ifndef __STRING_H__
-#define __STRING_H__
-
-/* String routines */
-
-void *memset(void *buf, int chr, unsigned int len);
-
-char *strcpy(char *dst, const char *src);
-
-char *strcat(char *dst, const char * src);
-
-int strcmp(const char *a,const char*b);
-
-int strlen(const char *a);
-
-#endif
diff --git a/menu/syslinux.c b/menu/syslinux.c
deleted file mode 100644 (file)
index 232f2f4..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- c -*- ------------------------------------------------------------- *
- *
- *   Copyright 2004 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 "syslinux.h"
-#include "biosio.h"
-
-static inline int asm_issyslinux(void)
-{
-  unsigned long eax, ebx, ecx, edx;
-
-  eax = 0x00003000;
-  ebx = ecx = edx = 0xFFFFFFFF;
-
-  asm("int $0x21"
-      : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx));
-
-  return (eax == 0x59530000) && (ebx == 0x4c530000) &&
-    (ecx == 0x4e490000) && (edx == 0x58550000);
-}
-
-int issyslinux(void)
-{
-   return asm_issyslinux();
-}
-
-static inline void asm_runcommand(const char *cmd)
-{
-  asm volatile("int $0x22" : : "a" (0x0003), "b" (cmd));
-}
-
-void runcommand(const char *cmd)
-{
-   asm_runcommand(cmd); 
-}
-
-static inline void asm_gototxtmode(void)
-{
-  asm volatile("int $0x22" : : "a" (0x0005));
-}
-   
-void gototxtmode()
-{
-   asm_gototxtmode();
-}
-
diff --git a/menu/syslinux.h b/menu/syslinux.h
deleted file mode 100644 (file)
index ef73d3a..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-
-#ifndef _SYSLINUX_H_
-#define _SYSLINUX_H_
-
-extern int syslinux;           /* Syslinux flag */
-
-int issyslinux(void);          /* Check if syslinux is running */
-
-void runcommand(const char *cmd); /* Run specified command */
-
-void gototxtmode(void);                /* Change mode to text mode */
-
-#endif