#!/usr/bin/python # pcfconf.py : A utility to convert mathetmatical formulas # from one language to another. it currently only supports # Microsoft PowerToy Calculator save files for reading, # and Python for writing. But it can be easily extended # to handle other file formats; see SOURCE DOC below # for details. # TODO: Set default data type (short, int, long, double, float) # it currently defaults to int or float, depending on # what's in the file # Implement some sanity checking on function arguments, to # make sure only arguments present in the arg list or the # parent object's body, are referenced. Currently, there # are no such checks. ################# SOURCE DOC ############################################## ############## (read here if you want to extend this program) ############# # The actual conversion is done by XXXXConverter classes that # do the actual conversion. They are passed a generic list of the following # form: # # [ [TYPE, NAME, VALUE] ] # # where TYPE is either "VAR" or "FUNC". If TYPE is "VAR", then the rest of # the values are obvious (the name and value of the variable). If TYPE is # "FUNC", then VALUE is actually another list of the form: # # [ARGS, CODE] # # where ARGS is yet another list containing the names of the function's arguments, # and CODE is the original PowerToyCalc code for the function. # # To extend this program with a new filetype, scan down to the "PROCESSOR CLASSES" # comment. At this point there is no programmatic reason to inherit your classes # from GenericProcessor, but GenericProcessor is to be considered the base class # for all new file processors; if GenericProcessor has a method, your class # must have it as well. Use the PythonProcessor class as a guide to how the existing # code works, if you need to. But as long as the converter winds up printing usable # code to the output file, and errors to sys.__stderr__ (via the *err functions), then # you're doing it right. Once you've done that, add it to the "PROCESSORS" dictionary # in the global variables section. The format of the dictionary is obvious. # # To extend this program with a new target language, scan down to the "GENERATOR # CLASSES" comment. The general process for processor classes applies here; if it's # in the base class, it needs to be in your new subclass. Use the PythonConverter # class as a guide to how to write your own converter, if necessary. The converter just # needs to return usable output to the processor class, which prints it to whatever # output file has been specified. Once you've done that, add it to the "CONVERTERS" # dictionary in the global variables section. The format of the dictionary is obvious. # # Got it? easy. import sys import getopt import math # Functions that will be used throughout the module. def syntaxerr (linenum, line, err): sys.__stderr__.write("%d : %s : %s\n" % (linenum, err, line)) def generalerr (err): sys.__stderr__.write("%s\n" % err) def debugmsg (err): global DEBUG if ( DEBUG ) : sys.__stderr__.write("DEBUG: %s\n" % err) def cloneList (list1): list2 = [] for item in list1: list2.append(item) return list2 ################## CONVERTER CLASSES ####################### class GenericConverter: def __init__ (self, langopts, contextName=""): """contextname is the name of the class, context, or namespace that should be generated for the incoming data. langopts is a dictionary containing the language specific options that the processor should follow.""" return def convertFile (self, data): """data is the data to interpret to your native language""" generalerr("convertFile is not implemented in GenericConverter") return 1 def convertCalls (self, code): """For the given block of code, translate any calls to things like atan() and acos() to functions that exist in your language's internal math library.""" global MATHSYMS ourlist = cloneList(MATHSYMS) ourlist.append(",") ourlist.append(" ") ourlist.append("\t") # we do our best here to ensure we don't change someone's defined function that # happens to have the name of one of ours inside of it. For example, if someone # makes a function MYacos(), then a replace on "acos" with "math.acos" would result # in the code being MYmath.acos(), which is guaranteed to do nothing but explode. # So we try to make sure that we're only replacing exact matches, by checking that # it follows any of the items in MATHSYMS, a comma(,), " ", or \t. The downside # to this is that it winds up being pretty slow. for call in self.__subs__.keys(): for symbol in ourlist : toreplace = "%s%s" % (symbol, call) replacer = "%s%s" % (symbol, self.__subs__[call]) if ( toreplace in code ): debugmsg("Replacing %s with %s in code line %s" % (toreplace, replacer, code)) code = code.replace(toreplace, replacer) return code def supportedTranslations (self): """return a string that lists all of the translations your language's converter supports""" generalerr("supportedTranslations is not implemetned in GenericConverter") class CPPConverter: class CPPVariable: def __init__ (self, name, initValue, baseType, namespace): self.__name__ = name self.__value__ = initValue self.__vartype__ = baseType self.__namespace__ = namespace def __str__ (self, defonly = False): retStr = "" if ( isinstance(self.__value__, list) or isinstance(self.__value__, tuple) ): if ( defonly ): return "%s %s[%d];" % (self.__vartype__, self.__name__, len(self.__value__)) # if we're not doing definitions, then assignments only occur in the constructor for i in range(0, len(self.__value__)-1): retStr += "\tthis->%s[%d] = %s;\n" % (self.__name__, i, self.__value__[i]) else: if ( defonly ): return "%s %s;" % (self.__vartype__, self.__name__) retStr = "\tthis->%s = %s;" % (self.__name__, self.__value__) return retStr class CPPFunction: def __init__ (self, namespace, argtype, rettype, name, arguments, code): self.__rettype__ = rettype self.__argtype__ = argtype self.__name__ = name self.__namespace__ = namespace self.__args__ = arguments self.__code__ = code def replaceVars (self, varlist): """Find any instance of a variable in our code that is not in our argument list, and is a member variable of our parent class""" codeCopy = self.__code__ ourlist = cloneList(MATHSYMS) ourlist.append(",") ourlist.append(" ") for var in varlist : if ( var.__name__ in self.__args__ ): continue for symbol in ourlist: toreplace = "%s%s" % (symbol, var.__name__) replacer = "this->%s" % (var.__name__) debugmsg("Searching for \" %s\" in code block %s" % (toreplace, codeCopy)) if ( toreplace in codeCopy ): debugmsg("Replacing \"%s\" with \"%s\" in %s" % (toreplace, replacer, codeCopy)) codeCopy = codeCopy.replace(toreplace, replacer) self.__code__ = codeCopy def __str__ (self, defonly=False): if ( defonly ): str = "%s %s (" % (self.__rettype__, self.__name__) else: str = "%s %s::%s (" % (self.__rettype__, self.__namespace__, self.__name__) argcnt = 0 for item in self.__args__: if ( argcnt > 0 ): str += ", " str += "%s %s" % (self.__argtype__, item) argcnt += 1 str += ")" if ( defonly ): return str+";" str += "\n{\n\treturn (%s);\n}\n" % (self.__code__) return str class CPPClass: def __init__ (self, namespace, variables, functions, langopts): self.__namespace__ = namespace self.__vars__ = variables self.__funcs__ = functions self.__langopts__ = langopts def toASCII (self): hdrstr = "" impstr = "" # generate definition hdrstr = "#ifndef __%s__\n" % self.__namespace__ hdrstr += "#define __%s__\n" % self.__namespace__ hdrstr += "#include \n\n" hdrstr += "class %s {\n" % self.__namespace__ hdrstr += "public:\n" hdrstr += "\t%s::%s(void);\n" % (self.__namespace__, self.__namespace__) for func in self.__funcs__: hdrstr += "\t%s\n" % func.__str__(True) hdrstr += "protected:\n" for var in self.__vars__ : hdrstr += "\t%s\n" % (var.__str__(True)) hdrstr += "}\n" hdrstr += "#endif /* __%s__ */\n" % self.__namespace__ # generate implementation if ( self.__langopts__["writefiles"].lower() == "true" ): impstr = "#include \"%s.h\"\n\n" % self.__namespace__ impstr += "\n" # generate the constructor impstr += "void %s::%s(void)\n{\n" % (self.__namespace__, self.__namespace__) # assignments happen in the constructor, not the class def for var in self.__vars__ : impstr += "%s\n" % str(var) impstr += "}\n" for func in self.__funcs__: impstr += "%s\n" % str(func) if ( self.__langopts__["writefiles"].lower() == "true" ): # write the definition to the header file ofile = open(("%s.h" % self.__namespace__), "w") ofile.write(hdrstr) ofile.close() # write the implementation to the C file ofile = open(("%s.c" % self.__namespace__), "w") ofile.write(impstr) ofile.close() return "" return hdrstr+"\n"+impstr def __init__ (self, langopts, namespace="PTC"): self.__namespace__ = namespace self.__langopts__ = { "deftype" : "double", "defrettype" : "double", "writefiles" : "false" } self.__funclist__ = [] self.__varlist__ = [] self.__subs__ = {} for key in langopts.keys(): self.__langopts__[key] = langopts[key] return def convertFile (self, data): for item in data: debugmsg("Processing item %s" % (item)) if ( item[0] == "VAR" ): self.__varlist__.append( CPPConverter.CPPVariable(item[1], item[2], self.__langopts__["deftype"], self.__namespace__ )) else: self.__funclist__.append( CPPConverter.CPPFunction(self.__namespace__, self.__langopts__["deftype"], self.__langopts__["defrettype"], item[1], item[2][0], item[2][1])) for func in self.__funclist__ : func.replaceVars(self.__varlist__) defclass = CPPConverter.CPPClass(self.__namespace__, self.__varlist__, self.__funclist__, self.__langopts__) return defclass.toASCII() def supportedTranslations (self): return "The entire C++ math.h library is supported. You are almost guaranteed 100% conversion." class CConverter: class CVariable: def __init__ (self, name, initValue, baseType, namespace): self.__name__ = name self.__value__ = initValue self.__vartype__ = baseType self.__namespace__ = namespace def __str__ (self, defonly = False): retStr = "" if ( isinstance(self.__value__, list) or isinstance(self.__value__, tuple) ): if ( defonly ): return "%s %s_%s[%d];" % (self.__vartype__, self.__namespace__, self.__name__, len(self.__value__)) retStr = "%s %s_%s[%d] = {" % (self.__vartype__, self.__namespace__, self.__name__, len(self.__value__)) for i in self.__value__: retStr += "%s, " % i retStr += "};" else: if ( defonly ): return "%s %s_%s;" % (self.__vartype__, self.__namespace__, self.__name__) retStr = "%s %s_%s = %s;" % (self.__vartype__, self.__namespace__, self.__name__, self.__value__) return retStr class CFunction: def __init__ (self, namespace, argtype, rettype, name, arguments, code): self.__rettype__ = rettype self.__argtype__ = argtype self.__name__ = name self.__namespace__ = namespace self.__args__ = arguments self.__code__ = code def replaceVars (self, varlist): """Find any instance of a variable in our code that is not in our argument list, and is a member variable of our parent class""" codeCopy = self.__code__ ourlist = cloneList(MATHSYMS) ourlist.append(",") ourlist.append(" ") for var in varlist : if ( var.__name__ in self.__args__ ): continue for symbol in ourlist: toreplace = "%s%s" % (symbol, var.__name__) replacer = "%s_%s" % (self.__namespace__, var.__name__) debugmsg("Searching for \" %s\" in code block %s" % (toreplace, codeCopy)) if ( toreplace in codeCopy ): debugmsg("Replacing \"%s\" with \"%s\" in %s" % (toreplace, replacer, codeCopy)) codeCopy = codeCopy.replace(toreplace, replacer) self.__code__ = codeCopy def __str__ (self, defonly=False): str = "%s %s_%s (" % (self.__rettype__, self.__namespace__, self.__name__) argcnt = 0 for item in self.__args__: if ( argcnt > 0 ): str += ", " str += "%s %s" % (self.__argtype__, item) argcnt += 1 str += ")" if ( defonly ): return str+";" str += "\n{\n\treturn (%s);\n}\n" % (self.__code__) return str class CInclude: def __init__ (self, namespace, variables, functions): self.__namespace__ = namespace self.__vars__ = variables self.__funcs__ = functions def toASCII (self, writefiles): hdrstr = "" impstr = "" # generate definition hdrstr = "#ifndef __%s__\n" % self.__namespace__ hdrstr += "#define __%s__\n" % self.__namespace__ hdrstr += "#include \n\n" for var in self.__vars__ : hdrstr += "extern %s\n" % (var.__str__(True)) hdrstr += "\n" for func in self.__funcs__: hdrstr += "extern %s\n" % func.__str__(True) hdrstr += "#endif /* __%s__ */" % self.__namespace__ # generate implementation if ( writefiles.lower() == "true" ): impstr = "#include \"%s.h\"\n\n" % self.__namespace__ for var in self.__vars__ : impstr += "%s\n" % (str(var)) impstr += "\n" for func in self.__funcs__: impstr += "%s\n" % str(func) if ( writefiles.lower() == "true" ): # write the definition to the header file ofile = open(("%s.h" % self.__namespace__), "w") ofile.write(hdrstr) ofile.close() # write the implementation to the C file ofile = open(("%s.c" % self.__namespace__), "w") ofile.write(impstr) ofile.close() return "" return hdrstr+"\n"+impstr def __init__ (self, langopts, namespace="PTC"): self.__namespace__ = namespace self.__langopts__ = { "deftype" : "double", "defrettype" : "double", "writefiles" : "false" } self.__funclist__ = [] self.__varlist__ = [] # thankfully C doesn't require any substitutions; we just include math.h and # everything is groovy. self.__subs__ = {} for key in langopts.keys(): self.__langopts__[key] = langopts[key] return def convertFile (self, data): # forcibly process all the variables first, then do the functions. # We do it in this specific order so we can do some variable replacement. for item in data: debugmsg("Processing item %s" % (item)) if ( item[0] == "VAR" ): self.__varlist__.append( CConverter.CVariable(item[1], item[2], self.__langopts__["deftype"], self.__namespace__ )) else: self.__funclist__.append( CConverter.CFunction(self.__namespace__, self.__langopts__["deftype"], self.__langopts__["defrettype"], item[1], item[2][0], item[2][1])) for func in self.__funclist__ : func.replaceVars(self.__varlist__) defclass = CConverter.CInclude(self.__namespace__, self.__varlist__, self.__funclist__) return defclass.toASCII(self.__langopts__["writefiles"]) def supportedTranslations (self): return "The entire C math.h library is supported. You are almost guaranteed 100% conversion." class PythonConverter: # what the class needs to know: # - the name of the class being generated. All data found in the .pcf file is # placed into a generated class of the given name. Variables are listed as # instance variables, and functions are of course generated as member functions. # - list of functions # - list of variables class PythonVariable: def __init__ (self, name, initValue, baseType): # note that initValue can be a list when the baseType constructor # requires more than one argument self.__name__ = name self.__value__ = initValue self.__vartype__ = baseType def __str__ (self): retStr = "" if ( isinstance(self.__value__, list) or isinstance(self.__value__, tuple) ): retStr = "%s = %s(" % (self.__name__, self.__vartype__) for i in self.__value__: retStr += "%s, " % i retStr += ")" else: retStr = "__%s__ = %s(%s)" % (self.__name__, self.__vartype__, self.__value__) return retStr class PythonFunction: def __init__ (self, name, arguments, code): self.__name__ = name self.__args__ = arguments self.__code__ = code def replaceVars (self, varlist): """Find any instance of a variable in our code that is not in our argument list, and is a member variable of our parent class""" codeCopy = self.__code__ ourlist = cloneList(MATHSYMS) ourlist.append(",") ourlist.append(" ") for var in varlist : if ( var.__name__ in self.__args__ ): continue for symbol in ourlist: toreplace = "%s%s" % (symbol, var.__name__) replacer = "self.__%s__" % (var.__name__) debugmsg("Searching for \" %s\" in code block %s" % (toreplace, codeCopy)) if ( toreplace in codeCopy ): debugmsg("Replacing \"%s\" with \"%s\" in %s" % (toreplace, replacer, codeCopy)) codeCopy = codeCopy.replace(toreplace, replacer) self.__code__ = codeCopy def __str__ (self): str = "def %s (self, " % (self.__name__) argcnt = 0 for item in self.__args__: if ( argcnt > 0 ): str += ", " str += "%s" % (item) argcnt += 1 str += "): return (%s)" % (self.__code__) return str class PythonClass: def __init__ (self, name, variables, functions): self.__name__ = name self.__vars__ = variables self.__funcs__ = functions def toASCII (self, tabstop): # return all elements in a string suitable for printing to stdout # "tabstop" specifies the tabstop to use. Pass "\t" or "" with a number of # spaces per tabstop. There will be one additional space per tabstop # because it makes it easier for me to write that way. retstr = "import math\n" retstr += "class %s:\n" % self.__name__ retstr += "%s def __init__(self):\n" % (tabstop) for var in self.__vars__ : retstr += "%s self.%s\n" % ((tabstop*2), str(var)) retstr += "%s return\n" % ((tabstop *2)) for func in self.__funcs__: retstr += "%s %s\n" % (tabstop, str(func)) return retstr def __init__ (self, langopts, className="PowerToyCapsule"): self.__className__ = className self.__langopts__ = langopts self.__funclist__ = [] self.__varlist__ = [] self.__subs__ = {} for item in dir(math): if ( "__" in item ): continue self.__subs__[item] = "math.%s" % item return def convertFile (self, data): # forcibly process all the variables first, then do the functions. # We do it in this specific order so we can do some variable replacement. for item in data: debugmsg("Processing item %s" % (item)) if ( item[0] == "VAR" ): if ( "." in item[2] ): self.__varlist__.append( PythonConverter.PythonVariable(item[1], item[2], "float") ) else: self.__varlist__.append( PythonConverter.PythonVariable(item[1], item[2], "int") ) else: self.__funclist__.append( PythonConverter.PythonFunction(item[1], item[2][0], item[2][1]) ) for func in self.__funclist__ : func.replaceVars(self.__varlist__) defclass = PythonConverter.PythonClass(self.__className__, self.__varlist__, self.__funclist__) return defclass.toASCII(" ") def supportedTranslations (self): retstr = "" for call in self.__subs__.keys(): retstr += "%s " % call return retstr ############################# PROCESSOR CLASSES ################### class GenericProcessor: def __init__ (self, converters): # "converters" is a dictionary of language types and the corresponding classes that # convert for that type self.__converters__ = converters def convertFile (self, filename, outfile, language, ignoreErrors, recovery, translate, langopts): debugmsg("convertFile is not implemented in the GenericConverter base class.") return 1 class MSPowerToyProcessor(GenericProcessor): def convertFile (self, filename, outfile, language, ignoreErrors, recovery, translate, langopts): global MATHSYMS # get the right converter for our language type convclass = self.__converters__[language] converter = convclass(langopts) data = [] if ( filename == "-" ): ifile = sys.__stdin__ else: ifile = open(filename, "rb") if ( not ifile ): generalerr("Unable to open input file %s, aborting." % filename) linenum = 1 line = ifile.readline() while ( line and (len(line) != 0) and line != "\x00"): debugmsg("Operating on line %d with length %d : %s" % (linenum, len(line), line)) dataTYPE = "" dataNAME = "" dataVALUELITERAL = 0 dataVALUELIST = [[], ""] # if there are parenthesis present on the LEFT side of the =, then the line is a function # replace the BS nulls that PowerToyCalc puts into these files for some reason line = line.replace("\x00", "").replace("\r", "").replace("\n", "") # strip out the parts parts = line.split("=") debugmsg("Operating on parts %s" % parts) # strip out all arithmetic operators and spaces, and drop the bare contents into a # temporary string if ( len(parts) > 1 ): temp = parts[1] for oper in MATHSYMS: temp = temp.replace(oper, "") # this final string will be used to test if any of the data in it is non-constant # e.g., are there just numbers, or are there alphanumerics in there too? temp = temp.replace(" ", "") else: sys.__stderr__.write("%s : %d : syntax error : no value in variable assignment : %s\n" \ % (filename, linenum, line)) if ( ignoreErrors ): sys.__stderr__.write("%s : %d : defaulting value to 0 to continue\n" % (filename, linenum)) temp = "0" else: if ( ifile != sys.__stdin__ ): ifile.close() return 1 # if they are present on the right side of the equals, it's a variable # If the variable has non-constant values to the right of =, then define that as a # function with no arguments that returns the contents of the right side of the # equals if ( temp.isdigit() ): # it's a variable, regardless of the presence of (), because it's just digits dataTYPE = "VAR" dataNAME = parts[0].replace(" ", "") dataVALUELITERAL = parts[1].replace(" ", "") elif ( "(" in parts[0] and ")" in parts[0] ): # it's a function (though it may have been defined as a variable with non-constant # values, such as the results of other functions, in PowerToyCalc. We define such # variables as funtions in the converter because they may have data in them # that needs to be re-calculated every time they are used, and a function is the # only way to do that. We're actually beyond PowerToyCalc in that, because # the user has to manually change a variable in PowerToyCalc to update it, we # don't.) dataTYPE = "FUNC" dataNAME = parts[0].split("(")[0].split(")")[0].replace(" ", "") dataVALUELIST[0] = parts[0].replace(" ", "").split("(")[1].replace(")", "").split(",") if ( translate ): dataVALUELIST[1] = converter.convertCalls(parts[1]) else: dataVALUELIST[1] = parts[1] else: # if it didn't fit into the two top categories, I dunno WTF it is sys.__stderr__.write("%s : %d : syntax error, no value in variable assignment : %s\n" % (filename, linenum, line)) # unless we're ignoring all errors, stop processing! if ( ignoreErrors ): if ( recovery ): sys.__stderr__.write("%s : %d : defaulting value to 0 to continue\n" % (filename, linenum)) dataTYPE = "VAR" dataNAME = parts[0].replace(" ", "") dataVALUELITERAL = "0" else: line = ifile.readline() continue else: if ( ifile != sys.__stdin__ ): ifile.close() return 1 if ( dataTYPE == "FUNC" ): newlist=[dataTYPE, dataNAME, dataVALUELIST] else: newlist=[dataTYPE, dataNAME, dataVALUELITERAL] debugmsg("Adding new list : %s" % newlist) data.append(newlist) line = ifile.readline() linenum += 1 # out of the main conversion loop if ( ifile != sys.__stdin__ ): ifile.close() if ( outfile == "-" ): sys.__stdout__.write(converter.convertFile(data)) else: try: ofile = file(outfile, "w") ofile.write(converter.convertFile(data)) ofile.close() except IOError, e: sys.__stderr__.write("Failed to open output file %s : %s" % (outfile, e)) return 1 return 0 ################ GLOBALS ######################## DEBUG=False MATHSYMS=["*", "+", "-", "=", "/", ">>", "<<", "%", "(", ")"] CONVERTERS = { "python" : PythonConverter, "C" : CConverter, "C++" : CPPConverter } PROCESSORS = { "mspcf" : [MSPowerToyProcessor, "MS Powertoy Calculator variable / function save data"]} SHORTOPTS = "hf:l:t:o:erTSdO:" LONGOPTS = ["help", "filename=", "language=", "filetype=", "outfile=", "ignore-err", "recovery", "translate", "supp-trans", "debug", "langopts="] USAGE = \ """Interpret mathematical formulae from various formats (such as MS PowerToy Calculator saves) to usable source code for one of a number of languages. usage: pcfconv.py (opts) options: -h | --help : print this help -f | --filename : filename to read from. If unspecified, stdin is read by default. -o | --outfile : filename to write to. If unspecified, the text is written to stdout. -t | --filetype : type of file being processed. If unspecified, MS Powertoy Calculator is the default. The interpreter cannot currently accurately determine filetypes on its own. -l | --language : language to write out. If unspecified, python is the default output language. -e | --ignore-err : ignore syntax errors in the source file when one is encountered and continue processing (note that the error will still be reported to stderr) -r | --recovery : Attempt to recover from any ignored errors, in the best way the interpreter can see fit. This could be dangerous. Don't blame the interpreter if this results in a divide by zero, you've been warned! -T | --translate : Setting this option will force the interpreter to attempt to translate calls to math functions, such as cos, acos, tan and log10, etc, to the internal math functions of whatever host language you're converting to. If this is unset - which is the default - such calls will be left as-is, and if necessary, you will have to change them yourself. Note that some functions may not be interpreted properly by your host language. -S | --supp-trans : Print out what function translations (handled by the -T option) are supported by the converter for your host language -d | --debug : Print debug output (normally supressed.) -O | --langopts : A comma separated list of options for the language processor for your given language, with each option conforming to option=value. For a list of options for each language processor, refer to the complete documentation. Languages currently supported: \n""" USAGE += "\t" + (" ".join(CONVERTERS.keys())) + "\n" USAGE += """Filetypes currently supported:\n""" for proc in PROCESSORS.keys() : USAGE += "\t%s : %s\n" % (proc, PROCESSORS[proc][1]) USAGE += """\npcfconv.py by Andrew Kesterson, 2008, released under the AKLabs License. Go to http://www.aklabs.net/source/license.txt for the full text of this license. Email the author andrew@aklabs.net for all questions and bug reports. """ ######################## MAIN LOGIC ############################# def main (argc, argv): global DEBUG infile = "-" outfile = "-" language = "python" filetype = "mspcf" ignoreErrors = False recovery = False translate = False supp_trans = False langopts = {} opts = getopt.getopt(argv, SHORTOPTS, LONGOPTS) for pair in opts[0]: if ( pair[0] == "-h" or pair[0] == "--help" ): sys.__stderr__.write(USAGE) return 1 elif ( pair[0] == "-d" or pair[0] == "--debug" ): DEBUG=True elif ( pair[0] == "-l" or pair[0] == "--language" ): language = pair[1] elif ( pair[0] == "-f" or pair[0] == "--filename" ): infile = pair[1] elif ( pair[0] == "-o" or pair[0] == "--outfile" ): outfile = pair[1] elif ( pair[0] == "-e" or pair[0] == "--ignore-err" ): ignoreErrors = True elif ( pair[0] == "-r" or pair[0] == "--recovery" ): recovery = True elif ( pair[0] == "-t" or pair[0] == "--filetype" ): filetype = pair[1] elif ( pair[0] == "-T" or pair[0] == "--translate" ): translate = True elif ( pair[0] == "-S" or pair[0] == "--supp-trans" ): supp_trans = True elif ( pair[0] == "-O" or pair[0] == "--langopts" ): splitopts = pair[1].split("=") for i in range(0, len(splitopts)-1, 2): #print "Assigning language option %s = %s" % (splitopts[i], splitopts[i+1]) langopts[splitopts[i]] = splitopts[i+1] procclass = PROCESSORS[filetype][0] proc = procclass(CONVERTERS) if ( supp_trans ): convclass = CONVERTERS[language] conv = convclass(langopts) print conv.supportedTranslations() return 0 return proc.convertFile(infile, outfile, language, ignoreErrors, recovery, translate, langopts) if ( __name__ == "__main__" ): sys.exit(main(len(sys.argv[1:])-1, sys.argv[1:]))