syslinux/com32/cmenu/menugen.py
<<
>>
Prefs
   1#!/usr/bin/env python
   2
   3import sys, re, getopt
   4
   5class Menusystem:
   6
   7   types = {"run"      : "OPT_RUN",
   8            "inactive" : "OPT_INACTIVE",
   9            "checkbox" : "OPT_CHECKBOX",
  10            "radiomenu": "OPT_RADIOMENU",
  11            "sep"      : "OPT_SEP",
  12            "invisible": "OPT_INVISIBLE",
  13            "radioitem": "OPT_RADIOITEM",
  14            "exitmenu" : "OPT_EXITMENU",
  15            "login"    : "login", # special type
  16            "submenu"  : "OPT_SUBMENU"}
  17
  18   entry_init = { "item" : "",
  19                  "info" : "",
  20                  "data" : "",
  21                  "ipappend" : 0, # flag to send in case of PXELINUX
  22                  "helpid" : 65535, # 0xFFFF
  23                  "shortcut":"-1",
  24                  "state"  : 0, # initial state of checkboxes
  25                  "argsmenu": "", # name of menu containing arguments
  26                  "perms"  : "", # permission required to execute this entry
  27                  "_updated" : None, # has this dictionary been updated
  28                  "type" : "run" }
  29
  30   menu_init = {  "title" : "",
  31                  "row" : "0xFF", # let system decide position
  32                  "col" : "0xFF",
  33                  "_updated" : None,
  34                  "name" : "" }
  35
  36   system_init ={ "videomode" : "0xFF",
  37                  "title" : "Menu System",
  38                  "top" : "1",
  39                  "left" : "1" ,
  40                  "bot" : "21",
  41                  "right":"79",
  42                  "helpdir" : "/isolinux/help",
  43                  "pwdfile" : "",
  44                  "pwdrow"  : "23",
  45                  "editrow" : "23",
  46                  "skipcondn"  : "0",
  47                  "skipcmd" : ".exit",
  48                  "startfile": "",
  49                  "onerrorcmd":".repeat",
  50                  "exitcmd"  : ".exit",
  51                  "exitcmdroot"  : "",
  52                  "timeout"  : "600",
  53                  "timeoutcmd":".beep",
  54                  "totaltimeout" : "0",
  55                  "totaltimeoutcmd" : ".wait"
  56                 }
  57
  58   shift_flags = { "alt"  : "ALT_PRESSED",
  59                   "ctrl" : "CTRL_PRESSED",
  60                   "shift": "SHIFT_PRESSED",
  61                   "caps" : "CAPSLOCK_ON",
  62                   "num"  : "NUMLOCK_ON",
  63                   "ins"  : "INSERT_ON"
  64                 }
  65
  66   reqd_templates = ["item","login","menu","system"]
  67
  68   def __init__(self,template):
  69       self.state = "system"
  70       self.code_template_filename = template
  71       self.menus = []
  72       self.init_entry()
  73       self.init_menu()
  74       self.init_system()
  75       self.vtypes = " OR ".join(self.types.keys())
  76       self.vattrs = " OR ".join(filter(lambda x: x[0] != "_", self.entry.keys()))
  77       self.mattrs = " OR ".join(filter(lambda x: x[0] != "_", self.menu.keys()))
  78
  79   def init_entry(self):
  80       self.entry = self.entry_init.copy()
  81
  82   def init_menu(self):
  83       self.menu = self.menu_init.copy()
  84
  85   def init_system(self):
  86       self.system = self.system_init.copy()
  87
  88   def add_menu(self,name):
  89       self.add_item()
  90       self.init_menu()
  91       self.menu["name"] = name
  92       self.menu["_updated"] = 1
  93       self.menus.append( (self.menu,[]) )
  94
  95   def add_item(self):
  96       if self.menu["_updated"]: # menu details have changed
  97          self.menus[-1][0].update(self.menu)
  98          self.init_menu()
  99       if self.entry["_updated"]:
 100          if not self.entry["info"]:
 101             self.entry["info"] = self.entry["data"]
 102          if not self.menus:
 103             print "Error before line %d" % self.lineno
 104             print "REASON: menu must be declared before a menu item is declared"
 105             sys.exit(1)
 106          self.menus[-1][1].append(self.entry)
 107       self.init_entry()
 108
 109   def set_item(self,name,value):
 110       if not self.entry.has_key(name):
 111          msg = ["Unknown attribute %s in line %d" % (name,self.lineno)]
 112          msg.append("REASON: Attribute must be one of %s" % self.vattrs)
 113          return "\n".join(msg)
 114       if name=="type" and not self.types.has_key(value):
 115          msg = [ "Unrecognized type %s in line %d" % (value,self.lineno)]
 116          msg.append("REASON: Valid types are %s" % self.vtypes)
 117          return "\n".join(msg)
 118       if name=="shortcut":
 119          if (value <> "-1") and not re.match("^[A-Za-z0-9]$",value):
 120             msg = [ "Invalid shortcut char '%s' in line %d" % (value,self.lineno) ]
 121             msg.append("REASON: Valid values are [A-Za-z0-9]")
 122             return "\n".join(msg)
 123          elif value <> "-1": value = "'%s'" % value
 124       elif name in ["state","helpid","ipappend"]:
 125          try:
 126              value = int(value)
 127          except:
 128              return "Value of %s in line %d must be an integer" % (name,self.lineno)
 129       self.entry[name] = value
 130       self.entry["_updated"] = 1
 131       return ""
 132
 133   def set_menu(self,name,value):
 134       if not self.menu.has_key(name):
 135          return "Error: Unknown keyword %s" % name
 136       self.menu[name] = value
 137       self.menu["_updated"] = 1
 138       return ""
 139
 140   def set_system(self,name,value):
 141       if not self.system.has_key(name):
 142          return "Error: Unknown keyword %s" % name
 143       if name == "skipcondn":
 144          try: # is skipcondn a number?
 145             a = int(value)
 146          except: # it is a "-" delimited sequence
 147             value = value.lower()
 148             parts = [ self.shift_flags.get(x.strip(),None) for x in value.split("-") ]
 149             self.system["skipcondn"] = " | ".join(filter(None, parts))
 150       else:
 151          self.system[name] = value
 152
 153   def set(self,name,value):
 154       # remove quotes if given
 155       if (value[0] == value[-1]) and (value[0] in ['"',"'"]): # remove quotes
 156          value = value[1:-1]
 157       if self.state == "system":
 158          err = self.set_system(name,value)
 159          if not err: return
 160       if self.state == "menu":
 161          err = self.set_menu(name,value)
 162          # change state to entry it menu returns error
 163          if err:
 164             err = None
 165             self.state = "item"
 166       if self.state == "item":
 167          err = self.set_item(name,value)
 168
 169       if not err: return
 170
 171       # all errors so return item's error message
 172       print err
 173       sys.exit(1)
 174
 175   def print_entry(self,entry,fd):
 176       entry["type"] = self.types[entry["type"]]
 177       if entry["type"] == "login": #special type
 178          fd.write(self.templates["login"] % entry)
 179       else:
 180          fd.write(self.templates["item"] % entry)
 181
 182   def print_menu(self,menu,fd):
 183       if menu["name"] == "main": self.foundmain = 1
 184       fd.write(self.templates["menu"] % menu)
 185       if (menu["row"] != "0xFF") or (menu["col"] != "0xFF"):
 186          fd.write('  set_menu_pos(%(row)s,%(col)s);\n' % menu)
 187
 188
 189   def output(self,filename):
 190       curr_template = None
 191       contents = []
 192       self.templates = {}
 193       regbeg = re.compile(r"^--(?P<name>[a-z]+) BEGINS?--\n$")
 194       regend = re.compile(r"^--[a-z]+ ENDS?--\n$")
 195       ifd = open(self.code_template_filename,"r")
 196       for line in ifd.readlines():
 197           b = regbeg.match(line)
 198           e = regend.match(line)
 199           if e: # end of template
 200              if curr_template:
 201                 self.templates[curr_template] = "".join(contents)
 202              curr_template = None
 203              continue
 204           if b:
 205              curr_template = b.group("name")
 206              contents = []
 207              continue
 208           if not curr_template: continue # lines between templates are ignored
 209           contents.append(line)
 210       ifd.close()
 211
 212       missing = None
 213       for x in self.reqd_templates:
 214           if not self.templates.has_key(x): missing = x
 215       if missing:
 216           print "Template %s required but not defined in %s" % (missing,self.code_template_filename)
 217
 218       if filename == "-":
 219          fd = sys.stdout
 220       else: fd = open(filename,"w")
 221       self.foundmain = None
 222       fd.write(self.templates["header"])
 223       fd.write(self.templates["system"] % self.system)
 224       for (menu,items) in self.menus:
 225           self.print_menu(menu,fd)
 226           for entry in items: self.print_entry(entry,fd)
 227       fd.write(self.templates["footer"])
 228       fd.close()
 229       if not self.foundmain:
 230          print "main menu not found"
 231          print self.menus
 232          sys.exit(1)
 233
 234   def input(self,filename):
 235       if filename == "-":
 236          fd = sys.stdin
 237       else: fd = open(filename,"r")
 238       self.lineno = 0
 239       self.state = "system"
 240       for line in fd.readlines():
 241         self.lineno = self.lineno + 1
 242         if line and line[-1] in ["\r","\n"]: line = line[:-1]
 243         if line and line[-1] in ["\r","\n"]: line = line[:-1]
 244         line = line.strip()
 245         if line and line[0] in ["#",";"]: continue
 246
 247         try:
 248           # blank line -> starting a new entry
 249           if not line:
 250              if self.state == "item": self.add_item()
 251              continue
 252
 253           # starting a new section?
 254           if line[0] == "[" and line[-1] == "]":
 255              self.state = "menu"
 256              self.add_menu(line[1:-1])
 257              continue
 258
 259           # add property of current entry
 260           pos = line.find("=") # find the first = in string
 261           if pos < 0:
 262              print "Syntax error in line %d" % self.lineno
 263              print "REASON: non-section lines must be of the form ATTRIBUTE=VALUE"
 264              sys.exit(1)
 265           attr = line[:pos].strip().lower()
 266           value = line[pos+1:].strip()
 267           self.set(attr,value)
 268         except:
 269            print "Error while parsing line %d: %s" % (self.lineno,line)
 270            raise
 271       fd.close()
 272       self.add_item()
 273
 274def usage():
 275    print sys.argv[0]," [options]"
 276    print "--input=<file>    is the name of the .menu file declaring the menu structure"
 277    print "--output=<file>   is the name of generated C source"
 278    print "--template=<file> is the name of template to be used"
 279    print
 280    print "input and output default to - (stdin and stdout respectively)"
 281    print "template defaults to adv_menu.tpl"
 282    sys.exit(1)
 283
 284def main():
 285    tfile = "adv_menu.tpl"
 286    ifile = "-"
 287    ofile = "-"
 288    opts,args = getopt.getopt(sys.argv[1:], "hi:o:t:",["input=","output=","template=","help"])
 289    if args:
 290       print "Unknown options %s" % args
 291       usage()
 292    for o,a in opts:
 293        if o in ["-i","--input"]:
 294           ifile = a
 295        elif o in ["-o", "--output"]:
 296           ofile = a
 297        elif o in ["-t","--template"]:
 298           tfile = a
 299        elif o in ["-h","--help"]:
 300           usage()
 301
 302    inst = Menusystem(tfile)
 303    inst.input(ifile)
 304    inst.output(ofile)
 305
 306if __name__ == "__main__":
 307   main()
 308
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.