7 types
= {"run" : "OPT_RUN",
8 "inactive" : "OPT_INACTIVE",
9 "checkbox" : "OPT_CHECKBOX",
10 "radiomenu": "OPT_RADIOMENU",
12 "invisible": "OPT_INVISIBLE",
13 "radioitem": "OPT_RADIOITEM",
14 "exitmenu" : "OPT_EXITMENU",
15 "login" : "login", # special type
16 "submenu" : "OPT_SUBMENU"}
18 entry_init
= { "item" : "",
21 "ipappend" : 0, # flag to send in case of PXELINUX
22 "helpid" : 65535, # 0xFFFF
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
30 menu_init
= { "title" : "",
31 "row" : "0xFF", # let system decide position
36 system_init
={ "videomode" : "0xFF",
37 "title" : "Menu System",
42 "helpdir" : "/isolinux/help",
49 "onerrorcmd":".repeat",
55 "totaltimeoutcmd" : ".wait"
58 shift_flags
= { "alt" : "ALT_PRESSED",
59 "ctrl" : "CTRL_PRESSED",
60 "shift": "SHIFT_PRESSED",
61 "caps" : "CAPSLOCK_ON",
66 reqd_templates
= ["item","login","menu","system"]
68 def __init__(self
,template
):
70 self
.code_template_filename
= template
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()))
80 self
.entry
= self
.entry_init
.copy()
83 self
.menu
= self
.menu_init
.copy()
85 def init_system(self
):
86 self
.system
= self
.system_init
.copy()
88 def add_menu(self
,name
):
91 self
.menu
["name"] = name
92 self
.menu
["_updated"] = 1
93 self
.menus
.append( (self
.menu
,[]) )
96 if self
.menu
["_updated"]: # menu details have changed
97 self
.menus
[-1][0].update(self
.menu
)
99 if self
.entry
["_updated"]:
100 if not self
.entry
["info"]:
101 self
.entry
["info"] = self
.entry
["data"]
103 print "Error before line %d" % self
.lineno
104 print "REASON: menu must be declared before a menu item is declared"
106 self
.menus
[-1][1].append(self
.entry
)
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
)
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"]:
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
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
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?
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
))
151 self
.system
[name
] = value
153 def set(self
,name
,value
):
154 # remove quotes if given
155 if (value
[0] == value
[-1]) and (value
[0] in ['"',"'"]): # remove quotes
157 if self
.state
== "system":
158 err
= self
.set_system(name
,value
)
160 if self
.state
== "menu":
161 err
= self
.set_menu(name
,value
)
162 # change state to entry it menu returns error
166 if self
.state
== "item":
167 err
= self
.set_item(name
,value
)
171 # all errors so return item's error message
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
)
180 fd
.write(self
.templates
["item"] % entry
)
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
)
189 def output(self
,filename
):
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
201 self
.templates
[curr_template
] = "".join(contents
)
205 curr_template
= b
.group("name")
208 if not curr_template
: continue # lines between templates are ignored
209 contents
.append(line
)
213 for x
in self
.reqd_templates
:
214 if not self
.templates
.has_key(x
): missing
= x
216 print "Template %s required but not defined in %s" % (missing
,self
.code_template_filename
)
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"])
229 if not self
.foundmain
:
230 print "main menu not found"
234 def input(self
,filename
):
237 else: fd
= open(filename
,"r")
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]
245 if line
and line
[0] in ["#",";"]: continue
248 # blank line -> starting a new entry
250 if self
.state
== "item": self
.add_item()
253 # starting a new section?
254 if line
[0] == "[" and line
[-1] == "]":
256 self
.add_menu(line
[1:-1])
259 # add property of current entry
260 pos
= line
.find("=") # find the first = in string
262 print "Syntax error in line %d" % self
.lineno
263 print "REASON: non-section lines must be of the form ATTRIBUTE=VALUE"
265 attr
= line
[:pos
].strip().lower()
266 value
= line
[pos
+1:].strip()
269 print "Error while parsing line %d: %s" % (self
.lineno
,line
)
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"
280 print "input and output default to - (stdin and stdout respectively)"
281 print "template defaults to adv_menu.tpl"
285 tfile
= "adv_menu.tpl"
288 opts
,args
= getopt
.getopt(sys
.argv
[1:], "hi:o:t:",["input=","output=","template=","help"])
290 print "Unknown options %s" % args
293 if o
in ["-i","--input"]:
295 elif o
in ["-o", "--output"]:
297 elif o
in ["-t","--template"]:
299 elif o
in ["-h","--help"]:
302 inst
= Menusystem(tfile
)
306 if __name__
== "__main__":