2 gensuitemodule - Generate an AE suite module from an aete/aeut resource
6 Reading and understanding this code is left as an exercise to the reader.
17 from Carbon
.Res
import *
20 fss
, ok
= macfs
.PromptGetFile('Select file with aeut/aete resource:')
23 processfile(fss
.as_pathname())
25 def processfile(fullname
):
26 """Process all resources in a single file"""
29 rf
= OpenRFPerm(fullname
, 0, 1)
33 for i
in range(Count1Resources('aete')):
34 res
= Get1IndResource('aete', 1+i
)
36 for i
in range(Count1Resources('aeut')):
37 res
= Get1IndResource('aeut', 1+i
)
39 print "\nLISTING aete+aeut RESOURCES IN", `fullname`
42 print "decoding", res
.GetResInfo(), "..."
45 aetelist
.append((aete
, res
.GetResInfo()))
50 # switch back (needed for dialogs in Python)
52 compileaetelist(aetelist
, fullname
)
54 def compileaetelist(aetelist
, fullname
):
55 for aete
, resinfo
in aetelist
:
56 compileaete(aete
, resinfo
, fullname
)
59 """Decode a resource into a python data structure"""
60 f
= StringIO
.StringIO(data
)
61 aete
= generic(getaete
, f
)
64 unprocessed
= len(f
.read())
67 sys
.stderr
.write("%d processed + %d unprocessed = %d total\n" %
68 (processed
, unprocessed
, total
))
72 """Recursively replace singleton tuples by their constituent item"""
73 if type(item
) is types
.ListType
:
74 return map(simplify
, item
)
75 elif type(item
) == types
.TupleType
and len(item
) == 2:
76 return simplify(item
[1])
81 # Here follows the aete resource decoder.
82 # It is presented bottom-up instead of top-down because there are direct
83 # references to the lower-level part-decoders from the high-level part-decoders.
85 def getbyte(f
, *args
):
88 raise EOFError, 'in getbyte' + str(args
)
91 def getword(f
, *args
):
95 raise EOFError, 'in getword' + str(args
)
96 return (ord(s
[0])<<8) |
ord(s
[1])
98 def getlong(f
, *args
):
102 raise EOFError, 'in getlong' + str(args
)
103 return (ord(s
[0])<<24) |
(ord(s
[1])<<16) |
(ord(s
[2])<<8) |
ord(s
[3])
105 def getostype(f
, *args
):
109 raise EOFError, 'in getostype' + str(args
)
112 def getpstr(f
, *args
):
115 raise EOFError, 'in getpstr[1]' + str(args
)
117 if nbytes
== 0: return ''
120 raise EOFError, 'in getpstr[2]' + str(args
)
127 ## print 'align:', `c`
129 def getlist(f
, description
, getitem
):
132 for i
in range(count
):
133 list.append(generic(getitem
, f
))
137 def alt_generic(what
, f
, *args
):
138 print "generic", `what`
, args
139 res
= vageneric(what
, f
, args
)
143 def generic(what
, f
, *args
):
144 if type(what
) == types
.FunctionType
:
145 return apply(what
, (f
,) + args
)
146 if type(what
) == types
.ListType
:
149 item
= apply(generic
, thing
[:1] + (f
,) + thing
[1:])
150 record
.append((thing
[1], item
))
152 return "BAD GENERIC ARGS: %s" % `what`
156 (getpstr
, "description"),
161 (getostype
, "keyword"),
166 (getpstr
, "description"),
167 (getostype
, "suite code"),
168 (getostype
, "event code"),
169 (getdata
, "returns"),
170 (getdata
, "accepts"),
171 (getlist
, "optional arguments", getargument
)
180 (getlist
, "keyform", getostype
)
184 (getostype
, "class code"),
185 (getpstr
, "description"),
186 (getlist
, "properties", getproperty
),
187 (getlist
, "elements", getelement
)
190 (getpstr
, "operator name"),
191 (getostype
, "operator ID"),
192 (getpstr
, "operator comment"),
195 (getpstr
, "enumerator name"),
196 (getostype
, "enumerator ID"),
197 (getpstr
, "enumerator comment")
200 (getostype
, "enumeration ID"),
201 (getlist
, "enumerator", getenumerator
)
204 (getpstr
, "suite name"),
205 (getpstr
, "suite description"),
206 (getostype
, "suite ID"),
207 (getword
, "suite level"),
208 (getword
, "suite version"),
209 (getlist
, "events", getevent
),
210 (getlist
, "classes", getclass
),
211 (getlist
, "comparisons", getcomparison
),
212 (getlist
, "enumerations", getenumeration
)
215 (getword
, "major/minor version in BCD"),
216 (getword
, "language code"),
217 (getword
, "script code"),
218 (getlist
, "suites", getsuite
)
221 def compileaete(aete
, resinfo
, fname
):
222 """Generate code for a full aete resource. fname passed for doc purposes"""
223 [version
, language
, script
, suites
] = aete
224 major
, minor
= divmod(version
, 256)
225 fss
= macfs
.FSSpec(fname
)
226 creatorsignature
, dummy
= fss
.GetCreatorType()
227 packagename
= identify(os
.path
.basename(fname
))
229 packagename
= packagename
+'_lang%d'%language
231 packagename
= packagename
+'_script%d'%script
232 if len(packagename
) > 27:
233 packagename
= packagename
[:27]
234 macfs
.SetFolder(os
.path
.join(sys
.prefix
, ':Mac:Lib:lib-scriptpackages'))
235 fss
, ok
= macfs
.GetDirectory('Package folder for %s'%packagename
)
238 pathname
= fss
.as_pathname()
239 packagename
= os
.path
.split(os
.path
.normpath(pathname
))[1]
240 fss
, ok
= macfs
.GetDirectory('Package folder for base suite (usually StdSuites)')
242 dirname
, basepkgname
= os
.path
.split(os
.path
.normpath(fss
.as_pathname()))
243 if not dirname
in sys
.path
:
244 sys
.path
.insert(0, dirname
)
245 basepackage
= __import__(basepkgname
)
248 macfs
.SetFolder(pathname
)
253 code
, suite
, fss
, modname
, precompinfo
= precompilesuite(suite
, basepackage
)
256 allprecompinfo
= allprecompinfo
+ precompinfo
257 suiteinfo
= suite
, fss
, modname
258 suitelist
.append((code
, modname
))
259 allsuites
.append(suiteinfo
)
260 for suiteinfo
in allsuites
:
261 compilesuite(suiteinfo
, major
, minor
, language
, script
, fname
, basepackage
, allprecompinfo
)
262 fss
, ok
= macfs
.StandardPutFile('Package module', '__init__.py')
265 fp
= open(fss
.as_pathname(), 'w')
266 fss
.SetCreatorType('Pyth', 'TEXT')
268 fp
.write("Package generated from %s\n"%fname
)
269 fp
.write("Resource %s resid %d %s\n"%(resinfo
[1], resinfo
[0], resinfo
[2]))
271 fp
.write('import aetools\n')
272 fp
.write('Error = aetools.Error\n')
273 for code
, modname
in suitelist
:
274 fp
.write("import %s\n" % modname
)
275 fp
.write("\n\n_code_to_module = {\n")
276 for code
, modname
in suitelist
:
277 fp
.write("\t'%s' : %s,\n"%(code
, modname
))
279 fp
.write("\n\n_code_to_fullname = {\n")
280 for code
, modname
in suitelist
:
281 fp
.write("\t'%s' : ('%s.%s', '%s'),\n"%(code
, packagename
, modname
, modname
))
283 for code
, modname
in suitelist
:
284 fp
.write("from %s import *\n"%modname
)
286 fp
.write("\n\nclass %s(%s_Events"%(packagename
, suitelist
[0][1]))
287 for code
, modname
in suitelist
[1:]:
288 fp
.write(",\n\t\t%s_Events"%modname
)
289 fp
.write(",\n\t\taetools.TalkTo):\n")
290 fp
.write("\t_signature = '%s'\n\n"%creatorsignature
)
293 def precompilesuite(suite
, basepackage
=None):
294 """Parse a single suite without generating the output. This step is needed
295 so we can resolve recursive references by suites to enums/comps/etc declared
297 [name
, desc
, code
, level
, version
, events
, classes
, comps
, enums
] = suite
299 modname
= identify(name
)
300 if len(modname
) > 28:
301 modname
= modname
[:27]
302 fss
, ok
= macfs
.StandardPutFile('Python output file', modname
+'.py')
304 return None, None, None, None, None
306 pathname
= fss
.as_pathname()
307 modname
= os
.path
.splitext(os
.path
.split(pathname
)[1])[0]
309 if basepackage
and basepackage
._code
_to
_module
.has_key(code
):
310 # We are an extension of a baseclass (usually an application extending
311 # Standard_Suite or so). Import everything from our base module
312 basemodule
= basepackage
._code
_to
_module
[code
]
314 # We are not an extension.
319 findenumsinevent(event
, enumsneeded
)
321 objc
= ObjectCompiler(None, basemodule
)
323 objc
.compileclass(cls
)
325 objc
.fillclasspropsandelems(cls
)
327 objc
.compilecomparison(comp
)
329 objc
.compileenumeration(enum
)
331 for enum
in enumsneeded
.keys():
332 objc
.checkforenum(enum
)
336 precompinfo
= objc
.getprecompinfo(modname
)
338 return code
, suite
, fss
, modname
, precompinfo
340 def compilesuite((suite
, fss
, modname
), major
, minor
, language
, script
, fname
, basepackage
, precompinfo
):
341 """Generate code for a single suite"""
342 [name
, desc
, code
, level
, version
, events
, classes
, comps
, enums
] = suite
344 pathname
= fss
.as_pathname()
345 fp
= open(fss
.as_pathname(), 'w')
346 fss
.SetCreatorType('Pyth', 'TEXT')
348 fp
.write('"""Suite %s: %s\n' % (name
, desc
))
349 fp
.write("Level %d, version %d\n\n" % (level
, version
))
350 fp
.write("Generated from %s\n"%fname
)
351 fp
.write("AETE/AEUT resource version %d/%d, language %d, script %d\n" % \
352 (major
, minor
, language
, script
))
355 fp
.write('import aetools\n')
356 fp
.write('import MacOS\n\n')
357 fp
.write("_code = %s\n\n"% `code`
)
358 if basepackage
and basepackage
._code
_to
_module
.has_key(code
):
359 # We are an extension of a baseclass (usually an application extending
360 # Standard_Suite or so). Import everything from our base module
361 fp
.write('from %s import *\n'%basepackage
._code
_to
_fullname
[code
][0])
362 basemodule
= basepackage
._code
_to
_module
[code
]
364 # We are not an extension.
366 compileclassheader(fp
, modname
, basemodule
)
371 compileevent(fp
, event
, enumsneeded
)
373 fp
.write("\tpass\n\n")
375 objc
= ObjectCompiler(fp
, basemodule
, precompinfo
)
377 objc
.compileclass(cls
)
379 objc
.fillclasspropsandelems(cls
)
381 objc
.compilecomparison(comp
)
383 objc
.compileenumeration(enum
)
385 for enum
in enumsneeded
.keys():
386 objc
.checkforenum(enum
)
392 def compileclassheader(fp
, name
, module
=None):
393 """Generate class boilerplate"""
394 classname
= '%s_Events'%name
396 modshortname
= string
.split(module
.__name
__, '.')[-1]
397 baseclassname
= '%s_Events'%modshortname
398 fp
.write("class %s(%s):\n\n"%(classname
, baseclassname
))
400 fp
.write("class %s:\n\n"%classname
)
402 def compileevent(fp
, event
, enumsneeded
):
403 """Generate code for a single event"""
404 [name
, desc
, code
, subcode
, returns
, accepts
, arguments
] = event
405 funcname
= identify(name
)
407 # generate name->keyword map
410 fp
.write("\t_argmap_%s = {\n"%funcname
)
412 fp
.write("\t\t%s : %s,\n"%(`
identify(a
[0])`
, `a
[1]`
))
416 # Generate function header
418 has_arg
= (not is_null(accepts
))
419 opt_arg
= (has_arg
and is_optional(accepts
))
421 fp
.write("\tdef %s(self, "%funcname
)
424 fp
.write("_object, ") # Include direct object, if it has one
426 fp
.write("_object=None, ") # Also include if it is optional
428 fp
.write("_no_object=None, ") # For argument checking
429 fp
.write("_attributes={}, **_arguments):\n") # include attribute dict and args
431 # Generate doc string (important, since it may be the only
432 # available documentation, due to our name-remaping)
434 fp
.write('\t\t"""%s: %s\n'%(name
, desc
))
436 fp
.write("\t\tRequired argument: %s\n"%getdatadoc
(accepts
))
438 fp
.write("\t\tOptional argument: %s\n"%getdatadoc
(accepts
))
439 for arg
in arguments
:
440 fp
.write("\t\tKeyword argument %s: %s\n"%(identify(arg
[0]),
442 fp
.write("\t\tKeyword argument _attributes: AppleEvent attribute dictionary\n")
443 if not is_null(returns
):
444 fp
.write("\t\tReturns: %s\n"%getdatadoc
(returns
))
445 fp
.write('\t\t"""\n')
447 # Fiddle the args so everything ends up in 'arguments' dictionary
449 fp
.write("\t\t_code = %s\n"% `code`
)
450 fp
.write("\t\t_subcode = %s\n\n"% `subcode`
)
452 # Do keyword name substitution
455 fp
.write("\t\taetools.keysubst(_arguments, self._argmap_%s)\n"%funcname
)
457 fp
.write("\t\tif _arguments: raise TypeError, 'No optional args expected'\n")
459 # Stuff required arg (if there is one) into arguments
462 fp
.write("\t\t_arguments['----'] = _object\n")
464 fp
.write("\t\tif _object:\n")
465 fp
.write("\t\t\t_arguments['----'] = _object\n")
467 fp
.write("\t\tif _no_object != None: raise TypeError, 'No direct arg expected'\n")
470 # Do enum-name substitution
477 fp
.write("\t\taetools.enumsubst(_arguments, %s, _Enum_%s)\n" %
478 (`kname`
, identify(ename
)))
479 enumsneeded
[ename
] = 1
484 fp
.write("\t\t_reply, _arguments, _attributes = self.send(_code, _subcode,\n")
485 fp
.write("\t\t\t\t_arguments, _attributes)\n")
489 fp
.write("\t\tif _arguments.has_key('errn'):\n")
490 fp
.write("\t\t\traise aetools.Error, aetools.decodeerror(_arguments)\n")
491 fp
.write("\t\t# XXXX Optionally decode result\n")
495 fp
.write("\t\tif _arguments.has_key('----'):\n")
497 fp
.write("\t\t\t# XXXX Should do enum remapping here...\n")
498 fp
.write("\t\t\treturn _arguments['----']\n")
501 # print "\n# Command %s -- %s (%s, %s)" % (`name`, `desc`, `code`, `subcode`)
502 # print "# returns", compiledata(returns)
503 # print "# accepts", compiledata(accepts)
504 # for arg in arguments:
505 # compileargument(arg)
507 def compileargument(arg
):
508 [name
, keyword
, what
] = arg
509 print "# %s (%s)" % (name
, `keyword`
), compiledata(what
)
511 def findenumsinevent(event
, enumsneeded
):
512 """Find all enums for a single event"""
513 [name
, desc
, code
, subcode
, returns
, accepts
, arguments
] = event
518 enumsneeded
[ename
] = 1
521 # This class stores the code<->name translations for a single module. It is used
522 # to keep the information while we're compiling the module, but we also keep these objects
523 # around so if one suite refers to, say, an enum in another suite we know where to
524 # find it. Finally, if we really can't find a code, the user can add modules by
527 class CodeNameMapper
:
542 self
.modulename
= None
543 self
.star_imported
= 0
545 def addnamecode(self
, type, name
, code
):
546 self
.name2code
[type][name
] = code
547 if not self
.code2name
[type].has_key(code
):
548 self
.code2name
[type][code
] = name
550 def hasname(self
, type, name
):
551 return self
.name2code
[type].has_key(name
)
553 def hascode(self
, type, code
):
554 return self
.code2name
[type].has_key(code
)
556 def findcodename(self
, type, code
):
557 if not self
.hascode(type, code
):
558 return None, None, None
559 name
= self
.code2name
[type][code
]
560 if self
.modulename
and not self
.star_imported
:
561 qualname
= '%s.%s'%(self
.modulename
, name
)
564 return name
, qualname
, self
.modulename
566 def getall(self
, type):
567 return self
.code2name
[type].items()
569 def addmodule(self
, module
, name
, star_imported
):
570 self
.modulename
= name
571 self
.star_imported
= star_imported
572 for code
, name
in module
._propdeclarations
.items():
573 self
.addnamecode('property', name
, code
)
574 for code
, name
in module
._classdeclarations
.items():
575 self
.addnamecode('class', name
, code
)
576 for code
in module
._enumdeclarations
.keys():
577 self
.addnamecode('enum', '_Enum_'+identify(code
), code
)
578 for code
, name
in module
._compdeclarations
.items():
579 self
.addnamecode('comparison', name
, code
)
581 def prepareforexport(self
, name
=None):
582 if not self
.modulename
:
583 self
.modulename
= name
586 class ObjectCompiler
:
587 def __init__(self
, fp
, basesuite
=None, othernamemappers
=None):
589 self
.basesuite
= basesuite
590 self
.namemappers
= [CodeNameMapper()]
592 self
.othernamemappers
= othernamemappers
[:]
594 self
.othernamemappers
= []
596 basemapper
= CodeNameMapper()
597 basemapper
.addmodule(basesuite
, '', 1)
598 self
.namemappers
.append(basemapper
)
600 def getprecompinfo(self
, modname
):
602 for mapper
in self
.namemappers
:
603 emapper
= mapper
.prepareforexport(modname
)
608 def findcodename(self
, type, code
):
610 # First try: check whether we already know about this code.
611 for mapper
in self
.namemappers
:
612 if mapper
.hascode(type, code
):
613 return mapper
.findcodename(type, code
)
614 # Second try: maybe one of the other modules knows about it.
615 for mapper
in self
.othernamemappers
:
616 if mapper
.hascode(type, code
):
617 self
.othernamemappers
.remove(mapper
)
618 self
.namemappers
.append(mapper
)
620 self
.fp
.write("import %s\n"%mapper
.modulename
)
623 # If all this has failed we ask the user for a guess on where it could
626 m
= self
.askdefinitionmodule(type, code
)
629 if not m
: return None, None, None
630 mapper
= CodeNameMapper()
631 mapper
.addmodule(m
, m
.__name
__, 0)
632 self
.namemappers
.append(mapper
)
634 def askdefinitionmodule(self
, type, code
):
635 fss
, ok
= macfs
.PromptGetFile('Where is %s %s declared?'%(type, code
))
637 path
, file = os
.path
.split(fss
.as_pathname())
638 modname
= os
.path
.splitext(file)[0]
639 if not path
in sys
.path
:
640 sys
.path
.insert(0, path
)
641 m
= __import__(modname
)
642 self
.fp
.write("import %s\n"%modname
)
645 def compileclass(self
, cls
):
646 [name
, code
, desc
, properties
, elements
] = cls
647 pname
= identify(name
)
648 if self
.namemappers
[0].hascode('class', code
):
649 # plural forms and such
650 othername
, dummy
, dummy
= self
.namemappers
[0].findcodename('class', code
)
652 self
.fp
.write("\n%s = %s\n"%(pname
, othername
))
655 self
.fp
.write('\nclass %s(aetools.ComponentItem):\n' % pname
)
656 self
.fp
.write('\t"""%s - %s """\n' % (name
, desc
))
657 self
.fp
.write('\twant = %s\n' % `code`
)
658 self
.namemappers
[0].addnamecode('class', pname
, code
)
659 for prop
in properties
:
660 self
.compileproperty(prop
)
661 for elem
in elements
:
662 self
.compileelement(elem
)
664 def compileproperty(self
, prop
):
665 [name
, code
, what
] = prop
667 # Something silly with plurals. Skip it.
669 pname
= identify(name
)
670 if self
.namemappers
[0].hascode('property', code
):
671 # plural forms and such
672 othername
, dummy
, dummy
= self
.namemappers
[0].findcodename('property', code
)
673 if pname
== othername
:
676 self
.fp
.write("\n%s = %s\n"%(pname
, othername
))
679 self
.fp
.write("class %s(aetools.NProperty):\n" % pname
)
680 self
.fp
.write('\t"""%s - %s """\n' % (name
, what
[1]))
681 self
.fp
.write("\twhich = %s\n" % `code`
)
682 self
.fp
.write("\twant = %s\n" % `what
[0]`
)
683 self
.namemappers
[0].addnamecode('property', pname
, code
)
685 def compileelement(self
, elem
):
686 [code
, keyform
] = elem
688 self
.fp
.write("# element %s as %s\n" % (`code`
, keyform
))
690 def fillclasspropsandelems(self
, cls
):
691 [name
, code
, desc
, properties
, elements
] = cls
692 cname
= identify(name
)
693 if self
.namemappers
[0].hascode('class', code
) and \
694 self
.namemappers
[0].findcodename('class', code
)[0] != cname
:
695 # This is an other name (plural or so) for something else. Skip.
699 for prop
in properties
:
700 [pname
, pcode
, what
] = prop
703 pname
= identify(pname
)
705 for elem
in elements
:
706 [ecode
, keyform
] = elem
709 name
, ename
, module
= self
.findcodename('class', ecode
)
712 self
.fp
.write("# XXXX %s element %s not found!!\n"%(cname
, `ecode`
))
714 elist
.append((name
, ename
))
717 self
.fp
.write("%s._propdict = {\n"%cname
)
719 self
.fp
.write("\t'%s' : %s,\n"%(n
, n
))
721 self
.fp
.write("%s._elemdict = {\n"%cname
)
722 for n
, fulln
in elist
:
723 self
.fp
.write("\t'%s' : %s,\n"%(n
, fulln
))
726 def compilecomparison(self
, comp
):
727 [name
, code
, comment
] = comp
728 iname
= identify(name
)
729 self
.namemappers
[0].addnamecode('comparison', iname
, code
)
731 self
.fp
.write("class %s(aetools.NComparison):\n" % iname
)
732 self
.fp
.write('\t"""%s - %s """\n' % (name
, comment
))
734 def compileenumeration(self
, enum
):
736 name
= "_Enum_%s" % identify(code
)
738 self
.fp
.write("%s = {\n" % name
)
740 self
.compileenumerator(item
)
741 self
.fp
.write("}\n\n")
742 self
.namemappers
[0].addnamecode('enum', name
, code
)
745 def compileenumerator(self
, item
):
746 [name
, code
, desc
] = item
747 self
.fp
.write("\t%s : %s,\t# %s\n" % (`name`
, `code`
, desc
))
749 def checkforenum(self
, enum
):
750 """This enum code is used by an event. Make sure it's available"""
751 name
, fullname
, module
= self
.findcodename('enum', enum
)
754 self
.fp
.write("_Enum_%s = None # XXXX enum %s not found!!\n"%(identify(enum
), enum
))
758 self
.fp
.write("from %s import %s\n"%(module
, name
))
763 self
.fp
.write("\n#\n# Indices of types declared in this module\n#\n")
764 self
.fp
.write("_classdeclarations = {\n")
765 for k
, v
in self
.namemappers
[0].getall('class'):
766 self
.fp
.write("\t%s : %s,\n" % (`k`
, v
))
768 self
.fp
.write("\n_propdeclarations = {\n")
769 for k
, v
in self
.namemappers
[0].getall('property'):
770 self
.fp
.write("\t%s : %s,\n" % (`k`
, v
))
772 self
.fp
.write("\n_compdeclarations = {\n")
773 for k
, v
in self
.namemappers
[0].getall('comparison'):
774 self
.fp
.write("\t%s : %s,\n" % (`k`
, v
))
776 self
.fp
.write("\n_enumdeclarations = {\n")
777 for k
, v
in self
.namemappers
[0].getall('enum'):
778 self
.fp
.write("\t%s : %s,\n" % (`k`
, v
))
781 def compiledata(data
):
782 [type, description
, flags
] = data
783 return "%s -- %s %s" % (`
type`
, `description`
, compiledataflags(flags
))
786 return data
[0] == 'null'
788 def is_optional(data
):
789 return (data
[2] & 0x8000)
792 return (data
[2] & 0x2000)
794 def getdatadoc(data
):
795 [type, descr
, flags
] = data
801 return 'an AE object reference'
802 return "undocumented, typecode %s"%`
type`
804 dataflagdict
= {15: "optional", 14: "list", 13: "enum", 12: "mutable"}
805 def compiledataflags(flags
):
809 if i
in dataflagdict
.keys():
810 bits
.append(dataflagdict
[i
])
813 return '[%s]' % string
.join(bits
)
815 # XXXX Do we have a set of python keywords somewhere?
816 illegal_ids
= [ "for", "in", "from", "and", "or", "not", "print", "class", "return",
820 """Turn any string into an identifier:
822 - replace other illegal chars by _xx_ (hex code)
823 - prepend _ if the result is a python keyword
826 return "_empty_ae_name"
828 ok
= string
.ascii_letters
+ '_'
829 ok2
= ok
+ string
.digits
836 rv
= rv
+ '_%02.2x_'%ord(c
)
838 if rv
in illegal_ids
:
842 # Call the main program
844 if __name__
== '__main__':