Add missing files to menu subdirectory
authorMurali Krishnan Ganapathy <gmurali@cs.uchicago.edu>
Sun, 8 Jan 2006 21:29:11 +0000 (15:29 -0600)
committerH. Peter Anvin <hpa@zytor.com>
Mon, 9 Jan 2006 19:21:51 +0000 (11:21 -0800)
Just realised that the patch I sent before did not contain the new files added. I am attaching the new files (to be put in "menu" subdirectory).

- Murali

menu/CHANGES
menu/MENU_FORMAT [new file with mode: 0644]
menu/TODO
menu/menugen.py [new file with mode: 0644]
menu/test.menu [new file with mode: 0644]

index da7fc90..ede6a4f 100644 (file)
@@ -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 (file)
index 0000000..e34ebf4
--- /dev/null
@@ -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
+
index 59e653c..5509ca1 100644 (file)
--- 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 (file)
index 0000000..a868d2a
--- /dev/null
@@ -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 (file)
index 0000000..66b2658
--- /dev/null
@@ -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
+