+Changes in v1.2
+---------------
+* Allowed menu's to have names. Submenu's can be referred to by names instead
+ of their index in the menu system. This allows user to refer to submenus
+ which are not yet part of the menusystem.
+* menugen.py: Python script for converting menu's specified in a given format
+ to corresponding C source code
+
Changes in v1.1
---------------
* Additional handler type: Keys handler
CHECKED = 1;
add_item("option1","Status 1",OPT_RUN,"kernel1 arg1=val1",0);
add_item("selfloop","Status 2",OPT_SUBMENU,NULL,MAINMENU);
+ add_item("othermenu","Status 3",OPT_SUBMENU,"menuname",0);
add_sep();
add_item("checkbox,"Checkbox Info",OPT_CHECKBOX,NULL,CHECKED);
add_item("Exit ","Status String",OPT_EXITMENU,NULL,0);
- // "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
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.
+to run the system.
+
+If you do not want to keep track of the return values, you can also use
+the following variant of add_menu
+
+<code>
+add_named_menu("main"," Menu Title ",-1)
+</code>
+
+This creates a new menu as before and gives it a name "main". When using named
+menus, you get an alternate way for adding submenu's. See below for details.
The call to add_item has five arguments.
The first argument is the text which appears in the menu itself.
* 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 fourth argument is the value of the data field always a string.
+Usually this string is just copied and nothing is done with it. Two
+cases, where it is used.
+
+In case of a radiomenu the input string is ignored and the "data" field
+points to the menuitem chosen (Dont forget to typecast this pointer to
+(t_menuitem *) when reading this info).
+
+In case of a submenu, this string if non-trivial is interpreted as the
+name of the submenu which should be linked there. This interpretation
+happens when the menu is first run and not when the menu system is being
+created. This allows the user to create the menusystem in an arbitrary
+order.
+
The fifth argument is a number whose meaning depends on the type of the
item. For a CHECKBOX it should be 0/1 setting the initial state of the
checkbox. For a SUBMENU it should be the index of the menu which should
-be displayed if this option is chosen. For a RADIOMENU it should be the
+be displayed if this option is chosen. Incase the data field is non-trivial,
+this number is ignored and computed later. For a RADIOMENU it should be the
index of the menu which contains all the options (All items in that menu
-should not of type RADIOITEM are ignored). For all other types, this
+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
<code>
choice = showmenus(MAIN); // Initial menu is the one with index MAIN
+ // or choice = showmenus(find_menu_num("main")); // Initial menu is the one named "main"
</code>
1.4 Processing the result
LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \
libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o
-MENUS = $(patsubst %.c,%.c32,$(wildcard *.c))
+CMENUS = $(patsubst %.c,%.c32,$(wildcard *.c))
+IMENUS = $(patsubst %.menu,%.c32,$(wildcard *.menu))
-.SUFFIXES: .S .c .o .elf .c32
+MENUS = $(CMENUS) $(IMENUS)
+
+.SUFFIXES: .S .c .o .elf .c32 .menu
+
+.PRECIOUS: %.c
+%.c: %.menu
+ python menugen.py $< $@
.PRECIOUS: %.o
%.o: %.S
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 .c32
-extension to the MENUS list in the Makefile.
+for your own menu configuration file; If your menu system is only going
+to have entries corresponding to things which can be executed directly,
+then you can create a file in ".menu" format instead of the C code.
+
+NOTE: ".menu" files can only describe the very basic type of menus
+See MENU_FORMAT for the syntax of .menu files
The resulting code is a 32-bit COMBOOT code, and hence can be executed
only under syslinux. You can use tools like bochs to help debug your
}
}
+// Finds the indexof the menu with given name
+uchar find_menu_num(const char *name)
+{
+ int i;
+ pt_menu m;
+
+ if (name == NULL) return (uchar)(-1);
+ for (i=0; i < ms->nummenus; i++)
+ {
+ m = ms->menus[i];
+ if ((m->name) && (strcmp(m->name,name)==0)) return i;
+ }
+ return (uchar)(-1);
+}
+
+// Run through all items and if they are submenus
+// with a non-trivial "action" and trivial submenunum
+// replace submenunum with the menu with name "action"
+void fix_submenus()
+{
+ int i,j;
+ pt_menu m;
+ pt_menuitem mi;
+
+ i = 0;
+ for (i=0; i < ms->nummenus; i++)
+ {
+ m = ms->menus[i];
+ for (j=0; j < m->numitems; j++)
+ {
+ mi = m->items[j];
+ // if submenu with non-trivial data string
+ if ( (mi->action == OPT_SUBMENU) && (mi->data) )
+ mi->itemdata.submenunum = find_menu_num (mi->data);
+ }
+ }
+}
+
/* User Callable functions */
pt_menuitem showmenus(uchar startmenu)
pt_menuitem rv;
uchar oldpage,tpos;
+ fix_submenus(); // Fix submenu numbers incase nick names were used
+
// Setup screen for menusystem
oldpage = getdisppage();
setdisppage(ms->menupage);
cursoroff(); // Doesn't seem to work?
+
// Go, main menu cannot be a radio menu
rv = runmenusystem(ms->minrow+MENUROW, ms->mincol+MENUCOL,
ms->menus[(unsigned int)startmenu], 0, NORMALMENU);
if (m == NULL) return -1;
ms->menus[num] = m;
m->numitems = 0;
+ m->name = NULL;
m->row = 0xFF;
m->col = 0xFF;
if (maxmenusize < 1)
return ms->nummenus - 1;
}
+void set_menu_name(const char *name) // Set the "name" of this menu
+{
+ pt_menu m;
+
+ m = ms->menus[ms->nummenus-1];
+ if (m->name) // Free up previous name
+ {
+ free(m->name);
+ m -> name = NULL;
+ }
+
+ if (name)
+ {
+ m->name = (char *)malloc(strlen(name)+1);
+ strcpy(m->name,name);
+ }
+}
+
+// Create a new named menu and return its position
+uchar add_named_menu(const char * name, const char *title, int maxmenusize)
+{
+ add_menu(title,maxmenusize);
+ set_menu_name(name);
+ return ms->nummenus - 1;
+}
+
void set_menu_pos(uchar row,uchar col) // Set the position of this menu.
{
pt_menu m;
break;
case OPT_RADIOMENU:
mi->itemdata.radiomenunum = itemdata;
+ if (mi->data) free(mi->data);
mi->data = NULL; // No selection made
break;
default: // to keep the compiler happy
void close_menusystem(void)
{
}
+
char *status;
char *data; // string containing kernel to run.. but...
// for radio menu's this is a pointer to the item selected or NULL (initially)
+ // for submenu's this string could be name of menu
void * extra_data; // Any other data user can point to
t_item_handler handler; // Pointer to function of type menufn
t_action action;
typedef struct s_menu {
pt_menuitem *items; // pointer to array of pointer to menuitems
- char *title;
+ char *title; // Title string for menu
+ char *name; // menu can be referred to by this string
int maxmenusize; // the size of array allocated
uchar numitems; // how many items do we actually have
uchar menuwidth;
typedef t_menusystem *pt_menusystem; // Pointer to type menusystem
-/************************************************************************
- * IMPORTANT INFORMATION
- *
- * All functions which take a string as argument store the pointer
- * for later use. So if you have alloc'ed a space for the string
- * and are passing it to any of these functions, DO NOT deallocate it.
- *
- * If they are constant strings, you may receive warning from the compiler
- * about "converting from char const * to char *". Ignore these errors.
- *
- * This hack/trick of storing these pointers will help in reducing the size
- * of the internal structures by a lot.
- *
- ***************************************************************************
- */
-
pt_menuitem showmenus(uchar startmenu);
pt_menusystem init_menusystem(const char *title);
+
void close_menusystem(); // Deallocate memory used
void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal, uchar inactiveselected);
// So stepsize=0 means numsteps is measured in centiseconds.
void unreg_ontimeout();
+// Find the number of the menu given the name
+// Returns -1 if not found
+uchar find_menu_num(const char *name);
+
// Create a new menu and return its position
uchar add_menu(const char *title, int maxmenusize);
+// Create a named menu and return its position
+uchar add_named_menu(const char *name, const char *title, int maxmenusize);
+
void set_menu_pos(uchar row,uchar col); // Set the position of this menu.
// Add item to the "current" menu
{
t_menuitem * curr;
- char TESTING,RESCUE,MAIN; /* The menus we're going to declare */
-
// Change the video mode here
// setvideomode(0)
//set_title_info (-1,-1);
//set_misc_info(-1,-1,-1,-1);
- // menuindex = add_menu(" Menu Title ",-1);
+ // menuindex = add_named_menu("name"," Menu Title ",-1);
// add_item("Item string","Status String",TYPE,"any string",NUM)
// TYPE = OPT_RUN | OPT_EXITMENU | OPT_SUBMENU | OPT_CHECKBOX | OPT_INACTIVE
- // "any string" not used by the menu system, useful for storing kernel names
+ // "any string" useful for storing kernel names
+ // In case of OPT_SUBMENU, "any string" can be set to "name" of menu to be linked
+ // in which case value NUM is ignored
// NUM = index of submenu if OPT_SUBMENU,
// 0/1 default checked state if OPT_CHECKBOX
// unused otherwise.
- TESTING = add_menu(" Testing ",-1);
- add_item("Self Loop","Go to testing",OPT_SUBMENU,NULL,TESTING);
+ add_named_menu("testing"," Testing ",-1);
+ add_item("Self Loop","Go to testing",OPT_SUBMENU,"testing",0);
add_item("Memory Test","Perform extensive memory testing",OPT_RUN, "memtest",0);
add_item("Exit this menu","Go one level up",OPT_EXITMENU,"exit",0);
- RESCUE = add_menu(" Rescue Options ",-1);
+ add_named_menu("rescue"," Rescue Options ",-1);
add_item("Linux Rescue","linresc",OPT_RUN,"linresc",0);
add_item("Dos Rescue","dosresc",OPT_RUN,"dosresc",0);
add_item("Windows Rescue","winresc",OPT_RUN,"winresc",0);
add_item("Exit this menu","Go one level up",OPT_EXITMENU,"exit",0);
- MAIN = add_menu(" Main Menu ",-1);
+ add_named_menu("main"," 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);
+ add_item("Rescue options...","Troubleshoot a system",OPT_SUBMENU,"rescue",0);
+ add_item("Testing...","Options to test hardware",OPT_SUBMENU,"testing",0);
add_item("Exit to prompt", "Exit the menu system", OPT_EXITMENU, "exit", 0);
- curr = showmenus(MAIN); // Initial menu is the one with index MAIN
+ curr = showmenus(find_menu_num("main")); // Initial menu is the one called "main"
+
if (curr)
{
if (curr->action == OPT_RUN)