aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--menu/CHANGES10
-rw-r--r--menu/MENU_FORMAT68
-rw-r--r--menu/TODO9
-rw-r--r--menu/menugen.py241
-rw-r--r--menu/test.menu61
5 files changed, 379 insertions, 10 deletions
diff --git a/menu/CHANGES b/menu/CHANGES
index da7fc90f..ede6a4fc 100644
--- a/menu/CHANGES
+++ b/menu/CHANGES
@@ -1,10 +1,10 @@
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
+* 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 files to C source code
+ See MENU_FORMAT for the format of .menu files
Changes in v1.1
---------------
diff --git a/menu/MENU_FORMAT b/menu/MENU_FORMAT
new file mode 100644
index 00000000..e34ebf4e
--- /dev/null
+++ b/menu/MENU_FORMAT
@@ -0,0 +1,68 @@
+A .menu file can be used to describe basic menu structures which can be converted into
+C code which can then be compiled into a .c32 file for use with SYSLINUX. The format
+of a .menu file is similar to an ini file, but with important differences.
+
+COMMENTS and Blank lines
+------------------------
+Lines starting with # and ; are treated as comments.
+Blank lines are used to separate the attributes of one menu item
+from another. Multiple blank lines are equivalent to a single one.
+In other contexts Blank lines are not significant.
+
+Menus
+-----
+Each menu declaration starts with a line containing the name of menu in [ ].
+This name is used for internal purposes only and is not visible to the user of
+the system.
+
+The menu declaration is followed by lines which set the attributes of the menu.
+This is followed by a blank line and followed by declaration of menu items in
+that menu.
+
+Currently supported menu attributes are
+title: the title of this menu
+row,col: position where menu should be displayed (defaults to system choosing optimal place)
+
+
+Global Settings
+---------------
+All lines which occur before the first menu declaration is considered as
+a global declaration. Currently supported global settings are
+
+title: the title of the whole menu system
+top,left,bot,right: limits of the window in which menu system should use to display
+ menu. Defaults to 1,1,23,78
+
+Menu item
+---------
+Each menu item is declared by setting the following attributes
+
+item: The string displayed to the user
+info: Additional information displayed in the status bar
+type: exitmenu,submenu or run indicating whether this item represents
+ an entry which exits this menu, goes to a sub menu or
+ executes something in SYSLINUX
+data: In case of exitmenu, this has no meaning
+ In case of submenu, this is the name of the submenu
+ In case of run, this is string to be passed to SYSLINUX for execution
+
+--------------------------------------------------------
+
+GLOBAL SETTINGS
+
+[menuname1]
+
+MENUSETTINGS
+
+ITEMATTR
+
+...
+
+[menuname2]
+
+MENUSETTINGS
+
+ITEMATTR
+
+ITEMATTR
+
diff --git a/menu/TODO b/menu/TODO
index 59e653ce..5509ca18 100644
--- a/menu/TODO
+++ b/menu/TODO
@@ -1,8 +1,7 @@
-* 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
+* Write COMBOOT code to read .menu files and parse them directly
+ - take the name of menu file to parse from commandline
+* menugen.py is still useful as user can see what the C code will
+ be and modify that as required.
* Help support
- Beef up help.c so that the text file can be larger than one page, and
user can scroll down page to view extra text.
diff --git a/menu/menugen.py b/menu/menugen.py
new file mode 100644
index 00000000..a868d2a3
--- /dev/null
+++ b/menu/menugen.py
@@ -0,0 +1,241 @@
+#!/usr/bin/env python
+
+import sys, string
+
+TEMPLATE_HEADER="""
+/* -*- c -*- ------------------------------------------------------------- *
+ *
+ * Copyright 2004-2005 Murali Krishnan Ganapathy - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#include "menu.h"
+#include "com32io.h"
+#include <string.h>
+
+int main(void)
+{
+ t_menuitem * curr;
+
+ // Change the video mode here
+ // setvideomode(0)
+
+ // Set the title and window size
+
+"""
+
+
+TEMPLATE_FOOTER="""
+ curr = showmenus(find_menu_num("main")); // Initial menu is the one called "main"
+
+ if (curr)
+ {
+ if (curr->action == OPT_RUN)
+ {
+ if (issyslinux()) runsyslinuxcmd(curr->data);
+ else csprint(curr->data,0x07);
+ return 1;
+ }
+ csprint("Error in programming!",0x07);
+ }
+ return 0;
+}
+"""
+
+class Menusystem:
+ def __init__(self):
+ self.menus = []
+ self.types = {"run" : "OPT_RUN","exitmenu":"OPT_EXITMENU","submenu":"OPT_SUBMENU"}
+ self.init_entry()
+ self.init_menu()
+ self.init_system()
+ self.vtypes = string.join(self.types.keys()," OR ")
+ self.vattrs = string.join(filter(lambda x: x[0] != "_", self.entry.keys())," OR ")
+ self.mattrs = string.join(filter(lambda x: x[0] != "_", self.menu.keys())," OR ")
+ self.itemtemplate = ' add_item("%(item)s","%(info)s",%(type)s,"%(data)s",0);\n'
+ self.menutemplate = '\n add_named_menu("%(name)s","%(title)s",-1);\n'
+ self.systemplate = '\n init_menusystem(%(title)s);\n set_window_size(%(top)s,%(left)s,%(bot)s,%(right)s);\n'
+
+ def init_entry(self):
+ self.entry = { "item" : "",
+ "info" : "",
+ "data" : "",
+ "_updated" : None, # has this dictionary been updated
+ "type" : "run" }
+
+ def init_menu(self):
+ self.menu = {"title" : "",
+ "row" : "0xFF", # let system decide position
+ "col" : "0xFF",
+ "_updated" : None,
+ "name" : "" }
+
+ def init_system(self):
+ self.system = { "title" : "",
+ "top" : "1", "left" : "1" , "bot" : "23", "right":"79" }
+
+ def add_menu(self,name):
+ self.add_item()
+ self.init_menu()
+ self.menu["name"] = name
+ self.menu["_updated"] = 1
+ self.menus.append( (self.menu,[]) )
+
+ def add_item(self):
+ if self.menu["_updated"]: # menu details have changed
+ self.menus[-1][0].update(self.menu)
+ self.init_menu()
+ if self.entry["_updated"]:
+ if not self.entry["info"]:
+ self.entry["info"] = self.entry["data"]
+ if not self.menus:
+ print "Error before line %d" % self.lineno
+ print "REASON: menu must be declared before a menu item is declared"
+ sys.exit(1)
+ self.menus[-1][1].append(self.entry)
+ self.init_entry()
+
+ # remove quotes if reqd
+ def rm_quote(self,str):
+ str = str .strip()
+ if (str[0] == str[-1]) and (str[0] in ['"',"'"]): # remove quotes
+ str = str[1:-1]
+ return str
+
+ def set_item(self,name,value):
+ if not self.entry.has_key(name):
+ msg = ["Unknown attribute %s in line %d" % (name,self.lineno)]
+ msg.append("REASON: Attribute must be one of %s" % self.vattrs)
+ return string.join(msg,"\n")
+ if name=="type" and not self.types.has_key(value):
+ msg = [ "Unrecognized type %s in line %d" % (value,self.lineno)]
+ msg.append("REASON: Valid types are %s" % self.vtypes)
+ return string.join(msg,"\n")
+ self.entry[name] = self.rm_quote(value)
+ self.entry["_updated"] = 1
+ return ""
+
+ def set_menu(self,name,value):
+ # no current menu yet. We are probably in global section
+ if not self.menus: return "Error"
+ if not self.menu.has_key(name):
+ return "Error"
+ self.menu[name] = self.rm_quote(value)
+ self.menu["_updated"] = 1
+ return ""
+
+ def set_system(self,name,value):
+ if not self.system.has_key(name):
+ return "Error"
+ self.system[name] = self.rm_quote(value)
+
+ def set(self,name,value):
+ msg = self.set_item(name,value)
+ # if valid item attrbute done
+ if not msg: return
+
+ # check if attr is of menu
+ err = self.set_menu(name,value)
+ if not err: return
+
+ # check if global attribute
+ err = self.set_system(name,value)
+ if not err: return
+
+ # all errors so return item's error message
+ print msg
+ sys.exit(1)
+
+ def print_entry(self,entry,fd):
+ entry["type"] = self.types[entry["type"]]
+ fd.write(self.itemtemplate % entry)
+
+ def print_menu(self,menu,fd):
+ if menu["name"] == "main": self.foundmain = 1
+ fd.write(self.menutemplate % menu)
+ if (menu["row"] != "0xFF") or (menu["col"] != "0xFF"):
+ fd.write(' set_menu_pos(%(row)s,%(col)s);\n' % menu)
+
+ # parts of C code which set attrs for entire menu system
+ def print_system(self,fd):
+ if self.system["title"]:
+ self.system["title"] = '"%s"' % self.system["title"]
+ else: self.system["title"] = "NULL"
+ fd.write(self.systemplate % self.system)
+
+ def output(self,filename):
+ fd = open(filename,"w")
+ self.foundmain = None
+ fd.write(TEMPLATE_HEADER)
+ self.print_system(fd)
+ for (menu,items) in self.menus:
+ self.print_menu(menu,fd)
+ for entry in items: self.print_entry(entry,fd)
+ fd.write(TEMPLATE_FOOTER)
+ fd.close()
+ if not self.foundmain:
+ print "main menu not found"
+ sys.exit(1)
+
+ def input(self,filename):
+ fd = open(filename,"r")
+ self.lineno = 0
+ for line in fd.readlines():
+ self.lineno = self.lineno + 1
+ if line and line[-1] in ["\r","\n"]: line = line[:-1]
+ if line and line[-1] in ["\r","\n"]: line = line[:-1]
+ if line and line[0] in ["#",";"]: continue
+
+ try:
+ # blank line -> starting a new entry
+ if not line:
+ self.add_item()
+ continue
+
+ # starting a new section?
+ if line[0] == "[" and line[-1] == "]":
+ self.add_menu(line[1:-1])
+ continue
+
+ # add property of current entry
+ pos = line.find("=") # find the first = in string
+ if pos < 0:
+ print "Syntax error in line %d" % self.lineno
+ print "REASON: non-section lines must be of the form ATTRIBUTE=VALUE"
+ sys.exit(1)
+ attr = line[:pos].strip().lower()
+ value = line[pos+1:].strip()
+ self.set(attr,value)
+ except:
+ print "Error while parsing line %d: %s" % (self.lineno,line)
+ raise
+ fd.close()
+ self.add_item()
+
+
+def usage():
+ print sys.argv[0]," inputfile outputfile"
+ print "inputfile is the ini-like file declaring menu structure"
+ print "outputfile is the C source which can be compiled"
+ sys.exit(1)
+
+def main():
+ if len(sys.argv) <> 3: usage()
+ inst = Menusystem()
+ inst.input(sys.argv[1])
+ inst.output(sys.argv[2])
+
+if __name__ == "__main__":
+ main()
+
+
diff --git a/menu/test.menu b/menu/test.menu
new file mode 100644
index 00000000..66b26584
--- /dev/null
+++ b/menu/test.menu
@@ -0,0 +1,61 @@
+# choose default title
+title = "A test of the test.menu file"
+top = 1
+left = 1
+bot = 23
+right = 78
+
+[testing]
+title = " Testing "
+
+item="Self Loop"
+info="Go to Testing"
+type=submenu
+data=testing
+
+item="Memory Test"
+info="Perform extensive memory testing"
+data="memtest"
+
+item="Exit this menu"
+info="Go one level up"
+type=exitmenu
+
+[rescue]
+title = " Rescue Options "
+row = 10
+col = 10
+
+item="Linux Rescue"
+data="linresc"
+
+item="Dos Rescue"
+data="dosresc"
+
+item="Windows Rescue"
+data="winresc"
+
+item="Exit this menu"
+info="Go one level up"
+type=exitmenu
+
+[main]
+title = " Main Menu "
+
+item="Prepare"
+data="prep"
+
+item="Rescue options..."
+info="Troubleshoot a system"
+type=submenu
+data="rescue"
+
+item="Testing..."
+info="Options to test hardware"
+type=submenu
+data="testing"
+
+item="Exit this menu"
+info="Go one level up"
+type=exitmenu
+