diff options
Diffstat (limited to 'src/configgen.py')
-rwxr-xr-x | src/configgen.py | 669 |
1 files changed, 564 insertions, 105 deletions
diff --git a/src/configgen.py b/src/configgen.py index b05f743..fdbdaa7 100755 --- a/src/configgen.py +++ b/src/configgen.py @@ -1,10 +1,11 @@ -# python script to generate configoptions.cpp from config.xml +#!/usr/bin/python +# python script to generate configoptions.cpp and config.doc from config.xml # # Copyright (C) 1997-2013 by Dimitri van Heesch. # # Permission to use, copy, modify, and distribute this software and its -# documentation under the terms of the GNU General Public License is hereby -# granted. No representations are made about the suitability of this software +# documentation under the terms of the GNU General Public License is hereby +# granted. No representations are made about the suitability of this software # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # @@ -13,136 +14,594 @@ # import xml.dom.minidom import sys +import re +import textwrap from xml.dom import minidom, Node -def addValues(var,node): + +def transformDocs(doc): + # join lines, unless it is an empty line + # remove doxygen layout constructs + doc = doc.strip() + doc = doc.replace("\n", " ") + doc = doc.replace("\r", " ") + doc = doc.replace("\t", " ") + doc = doc.replace("\\&", "&") + doc = doc.replace("\\c ", " ") + doc = doc.replace("\\b ", " ") + doc = doc.replace("\\e ", " ") + doc = doc.replace("\\$", "$") + doc = doc.replace("\\#include ", "#include ") + doc = doc.replace("\\#undef ", "#undef ") + doc = doc.replace("-# ", "\n - ") + doc = doc.replace(" - ", "\n - ") + doc = doc.replace("\\sa", "\nSee also: ") + doc = doc.replace("\\par", "\n") + doc = doc.replace("@note", "\nNote:") + doc = doc.replace("\\note", "\nNote:") + doc = doc.replace("\\verbatim", "\n") + doc = doc.replace("\\endverbatim", "\n") + doc = doc.replace("<code>", "") + doc = doc.replace("</code>", "") + doc = doc.replace("`", "") + doc = doc.replace("\\<", "<") + doc = doc.replace("\\>", ">") + doc = doc.replace("\\@", "@") + doc = doc.replace("\\\\", "\\") + # \ref name "description" -> description + doc = re.sub('\\\\ref +[^ ]* +"([^"]*)"', '\\1', doc) + # \ref specials + # \ref <key> -> description + doc = re.sub('\\\\ref +doxygen_usage', '"Doxygen usage"', doc) + doc = re.sub('\\\\ref +extsearch', '"External Indexing and Searching"', + doc) + doc = re.sub('\\\\ref +external', '"Linking to external documentation"', + doc) + # fallback for not handled + doc = re.sub('\\\\ref', '', doc) + #<a href="address">description</a> -> description (see: address) + doc = re.sub('<a +href="([^"]*)" *>([^<]*)</a>', '\\2 (see: \\1)', doc) + # LaTeX name as formula -> LaTeX + doc = doc.replace("\\f$\\mbox{\\LaTeX}\\f$", "LaTeX") + # Other forula's (now just 2) so explicitely mentioned. + doc = doc.replace("\\f$2^{(16+\\mbox{LOOKUP\\_CACHE\\_SIZE})}\\f$", + "2^(16+LOOKUP_CACHE_SIZE)") + doc = doc.replace("\\f$2^{16} = 65536\\f$", "2^16=65536") + # remove consecutive spaces + doc = re.sub(" +", " ", doc) + # a dirty trick to get an extra empty line in Doxyfile documentation. + # <br> will be removed later on again, we need it here otherwise splitlines + # will filter the extra line. + doc = doc.replace("<br>", "\n<br>\n") + # + doc = doc.splitlines() + split_doc = [] + for line in doc: + split_doc += textwrap.wrap(line, 78) + # replace \ by \\, replace " by \", and ' ' by a newline with end string + # and start string at next line + docC = [] + for line in split_doc: + docC.append(line.strip().replace('\\', '\\\\'). + replace('"', '\\"').replace("<br>", "")) + return docC + + +def collectValues(node): + values = [] + for n in node.childNodes: + if (n.nodeName == "value"): + if n.nodeType == Node.ELEMENT_NODE: + if n.getAttribute('name') != "": + name = "<code>" + n.getAttribute('name') + "</code>" + desc = n.getAttribute('desc') + if (desc != ""): + name += " " + desc + values.append(name) + return values + + +def addValues(var, node): + for n in node.childNodes: + if (n.nodeName == "value"): + if n.nodeType == Node.ELEMENT_NODE: + name = n.getAttribute('name') + print " %s->addValue(\"%s\");" % (var, name) + + +def parseHeader(node,objName): + doc = "" for n in node.childNodes: if n.nodeType == Node.ELEMENT_NODE: - name = n.getAttribute('name'); - print " %s->addValue(\"%s\");" % (var,name) - + if (n.nodeName == "docs"): + if (n.getAttribute('doxyfile') != "0"): + doc += parseDocs(n) + docC = transformDocs(doc) + print " %s->setHeader(" % (objName) + rng = len(docC) + for i in range(rng): + line = docC[i] + if i != rng - 1: # since we go from 0 to rng-1 + print " \"%s\\n\"" % (line) + else: + print " \"%s\"" % (line) + print " );" + + +def prepCDocs(node): + type = node.getAttribute('type') + format = node.getAttribute('format') + defval = node.getAttribute('defval') + adefval = node.getAttribute('altdefval') + doc = ""; + if (type != 'obsolete'): + for n in node.childNodes: + if (n.nodeName == "docs"): + if (n.getAttribute('doxyfile') != "0"): + if n.nodeType == Node.ELEMENT_NODE: + doc += parseDocs(n) + if (type == 'enum'): + values = collectValues(node) + doc += "Possible values are: " + rng = len(values) + for i in range(rng): + val = values[i] + if i == rng - 2: + doc += "%s and " % (val) + elif i == rng - 1: + doc += "%s." % (val) + else: + doc += "%s, " % (val) + if (defval != ""): + doc += "<br>" + doc += "The default value is: <code>%s</code>." % (defval) + elif (type == 'int'): + minval = node.getAttribute('minval') + maxval = node.getAttribute('maxval') + doc += "%s: %s, %s: %s, %s: %s." % (" Minimum value", minval, + "maximum value", maxval, + "default value", defval) + elif (type == 'bool'): + if (node.hasAttribute('altdefval')): + doc += "%s: %s." % ("Default value", "system dependent") + else: + doc += "%s: %s." % ("Default value", "YES" if (defval == "1") else "NO") + elif (type == 'list'): + if format == 'string': + values = collectValues(node) + rng = len(values) + for i in range(rng): + val = values[i] + if i == rng - 2: + doc += "%s and " % (val) + elif i == rng - 1: + doc += "%s." % (val) + else: + doc += "%s, " % (val) + elif (type == 'string'): + if format == 'dir': + if defval != '': + doc += "The default directory is: <code>%s</code>." % ( + defval) + elif format == 'file': + abspath = node.getAttribute('abspath') + if defval != '': + if abspath != '1': + doc += "The default file is: <code>%s</code>." % ( + defval) + else: + doc += "%s: %s%s%s." % ( + "The default file (with absolute path) is", + "<code>",defval,"</code>") + else: + if abspath == '1': + doc += "The file has to be specified with full path." + else: # format == 'string': + if defval != '': + doc += "The default value is: <code>%s</code>." % ( + defval) + # depends handling + if (node.hasAttribute('depends')): + depends = node.getAttribute('depends') + doc += "<br>" + doc += "%s \\ref cfg_%s \"%s\" is set to \\c YES." % ( + "This tag requires that the tag", depends.lower(), depends.upper()) + + docC = transformDocs(doc) + return docC; + def parseOption(node): - name = node.getAttribute('id') - type = node.getAttribute('type') - format = node.getAttribute('format') - doc = node.getAttribute('docs') - defval = node.getAttribute('defval') + # Handling part for Doxyfile + name = node.getAttribute('id') + type = node.getAttribute('type') + format = node.getAttribute('format') + defval = node.getAttribute('defval') adefval = node.getAttribute('altdefval') depends = node.getAttribute('depends') setting = node.getAttribute('setting') - # replace \ by \\, replace " by \", and ' ' by a newline with end string and start string at next line - docC = doc.strip().replace('\\','\\\\').replace('"','\\"').replace(' ','\\n"\n\t\t\t"') - if len(setting)>0: + docC = prepCDocs(node); + if len(setting) > 0: print "#if %s" % (setting) - print " //----" - if type=='bool': - if len(adefval)>0: + print " //----" + if type == 'bool': + if len(adefval) > 0: enabled = adefval - elif defval=='1': + elif defval == '1': enabled = "TRUE" else: enabled = "FALSE" - print " cb = cfg->addBool(" - print " \"%s\"," % (name) - print " \"%s\"," % (docC) - print " %s" % (enabled) - print " );" - if depends!='': - print " cb->addDependency(\"%s\");" % (depends) - elif type=='string': - print " cs = cfg->addString(" - print " \"%s\"," % (name) - print " \"%s\"" % (docC) - print " );" - if defval!='': - print " cs->setDefaultValue(\"%s\");" % (defval) - if format=='file': - print " cs->setWidgetType(ConfigString::File);" - elif format=='dir': - print " cs->setWidgetType(ConfigString::Dir);" - if depends!='': - print " cs->addDependency(\"%s\");" % (depends) - elif type=='enum': - print " ce = cfg->addEnum(" - print " \"%s\"," % (name) - print " \"%s\"," % (docC) - print " \"%s\"" % (defval) - print " );" - addValues("ce",node) - if depends!='': - print " ce->addDependency(\"%s\");" % (depends) - elif type=='int': + print " cb = cfg->addBool(" + print " \"%s\"," % (name) + rng = len(docC) + for i in range(rng): + line = docC[i] + if i != rng - 1: # since we go from 0 to rng-1 + print " \"%s\\n\"" % (line) + else: + print " \"%s\"," % (line) + print " %s" % (enabled) + print " );" + if depends != '': + print " cb->addDependency(\"%s\");" % (depends) + elif type == 'string': + print " cs = cfg->addString(" + print " \"%s\"," % (name) + rng = len(docC) + for i in range(rng): + line = docC[i] + if i != rng - 1: # since we go from 0 to rng-1 + print " \"%s\\n\"" % (line) + else: + print " \"%s\"" % (line) + print " );" + if defval != '': + print " cs->setDefaultValue(\"%s\");" % (defval) + if format == 'file': + print " cs->setWidgetType(ConfigString::File);" + elif format == 'dir': + print " cs->setWidgetType(ConfigString::Dir);" + if depends != '': + print " cs->addDependency(\"%s\");" % (depends) + elif type == 'enum': + print " ce = cfg->addEnum(" + print " \"%s\"," % (name) + rng = len(docC) + for i in range(rng): + line = docC[i] + if i != rng - 1: # since we go from 0 to rng-1 + print " \"%s\\n\"" % (line) + else: + print " \"%s\"," % (line) + print " \"%s\"" % (defval) + print " );" + addValues("ce", node) + if depends != '': + print " ce->addDependency(\"%s\");" % (depends) + elif type == 'int': minval = node.getAttribute('minval') maxval = node.getAttribute('maxval') - print " ci = cfg->addInt(" - print " \"%s\"," % (name) - print " \"%s\"," % (docC) - print " %s,%s,%s" % (minval,maxval,defval) - print " );" - if depends!='': - print " ci->addDependency(\"%s\");" % (depends) - elif type=='list': - print " cl = cfg->addList(" - print " \"%s\"," % (name) - print " \"%s\"" % (docC) - print " );" - addValues("cl",node) - if depends!='': - print " cl->addDependency(\"%s\");" % (depends) - if format=='file': - print " cl->setWidgetType(ConfigList::File);" - elif format=='dir': - print " cl->setWidgetType(ConfigList::Dir);" - elif format=='filedir': - print " cl->setWidgetType(ConfigList::FileAndDir);" - elif type=='obsolete': - print " cfg->addObsolete(\"%s\");" % (name) - if len(setting)>0: + print " ci = cfg->addInt(" + print " \"%s\"," % (name) + rng = len(docC) + for i in range(rng): + line = docC[i] + if i != rng - 1: # since we go from 0 to rng-1 + print " \"%s\\n\"" % (line) + else: + print " \"%s\"," % (line) + print " %s,%s,%s" % (minval, maxval, defval) + print " );" + if depends != '': + print " ci->addDependency(\"%s\");" % (depends) + elif type == 'list': + print " cl = cfg->addList(" + print " \"%s\"," % (name) + rng = len(docC) + for i in range(rng): + line = docC[i] + if i != rng - 1: # since we go from 0 to rng-1 + print " \"%s\\n\"" % (line) + else: + print " \"%s\"" % (line) + print " );" + addValues("cl", node) + if depends != '': + print " cl->addDependency(\"%s\");" % (depends) + if format == 'file': + print " cl->setWidgetType(ConfigList::File);" + elif format == 'dir': + print " cl->setWidgetType(ConfigList::Dir);" + elif format == 'filedir': + print " cl->setWidgetType(ConfigList::FileAndDir);" + elif type == 'obsolete': + print " cfg->addObsolete(\"%s\");" % (name) + if len(setting) > 0: print "#else" - print " cfg->addDisabled(\"%s\");" % (name) + print " cfg->addDisabled(\"%s\");" % (name) print "#endif" - - def parseGroups(node): name = node.getAttribute('name') - doc = node.getAttribute('docs') - print " //---------------------------------------------------------------------------"; - print " cfg->addInfo(\"%s\",\"%s\");" % (name,doc) - print " //---------------------------------------------------------------------------"; + doc = node.getAttribute('docs') + print "%s%s" % (" //-----------------------------------------", + "----------------------------------") + print " cfg->addInfo(\"%s\",\"%s\");" % (name, doc) + print "%s%s" % (" //-----------------------------------------", + "----------------------------------") print for n in node.childNodes: if n.nodeType == Node.ELEMENT_NODE: parseOption(n) - + +def parseGroupCDocs(node): + for n in node.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + type = n.getAttribute('type') + name = n.getAttribute('id') + docC = prepCDocs(n); + if type != 'obsolete': + print " doc->add(" + print " \"%s\"," % (name) + rng = len(docC) + for i in range(rng): + line = docC[i] + if i != rng - 1: # since we go from 0 to rng-1 + print " \"%s\\n\"" % (line) + else: + print " \"%s\"" % (line) + print " );" + +def parseOptionDoc(node, first): + # Handling part for documentation + name = node.getAttribute('id') + type = node.getAttribute('type') + format = node.getAttribute('format') + defval = node.getAttribute('defval') + adefval = node.getAttribute('altdefval') + depends = node.getAttribute('depends') + setting = node.getAttribute('setting') + doc = "" + if (type != 'obsolete'): + for n in node.childNodes: + if (n.nodeName == "docs"): + if (n.getAttribute('documentation') != "0"): + if n.nodeType == Node.ELEMENT_NODE: + doc += parseDocs(n) + if (first): + print " \\anchor cfg_%s" % (name.lower()) + print "<dl>" + print "" + print "<dt>\\c %s <dd>" % (name) + else: + print " \\anchor cfg_%s" % (name.lower()) + print "<dt>\\c %s <dd>" % (name) + print " \\addindex %s" % (name) + print doc + if (type == 'enum'): + values = collectValues(node) + print "" + print "Possible values are: " + rng = len(values) + for i in range(rng): + val = values[i] + if i == rng - 2: + print "%s and " % (val) + elif i == rng - 1: + print "%s." % (val) + else: + print "%s, " % (val) + if (defval != ""): + print "" + print "The default value is: <code>%s</code>." % (defval) + print "" + elif (type == 'int'): + minval = node.getAttribute('minval') + maxval = node.getAttribute('maxval') + print "" + print "%s: %s%s%s, %s: %s%s%s, %s: %s%s%s." % ( + " Minimum value", "<code>", minval, "</code>", + "maximum value", "<code>", maxval, "</code>", + "default value", "<code>", defval, "</code>") + print "" + elif (type == 'bool'): + print "" + if (node.hasAttribute('altdefval')): + print "Default value is system dependent." + else: + print "The default value is: <code>%s</code>." % ( + "YES" if (defval == "1") else "NO") + print "" + elif (type == 'list'): + if format == 'string': + values = collectValues(node) + rng = len(values) + for i in range(rng): + val = values[i] + if i == rng - 2: + print "%s and " % (val) + elif i == rng - 1: + print "%s." % (val) + else: + print "%s, " % (val) + print "" + elif (type == 'string'): + if format == 'dir': + if defval != '': + print "The default directory is: <code>%s</code>." % ( + defval) + elif format == 'file': + abspath = node.getAttribute('abspath') + if defval != '': + if abspath != '1': + print "The default file is: <code>%s</code>." % ( + defval) + else: + print "%s: %s%s%s." % ( + "The default file (with absolute path) is", + "<code>",defval,"</code>") + else: + if abspath == '1': + print "The file has to be specified with full path." + else: # format == 'string': + if defval != '': + print "The default value is: <code>%s</code>." % ( + defval) + print "" + # depends handling + if (node.hasAttribute('depends')): + depends = node.getAttribute('depends') + print "%s \\ref cfg_%s \"%s\" is set to \\c YES." % ( + "This tag requires that the tag", depends.lower(), depends.upper()) + return False + + +def parseGroupsDoc(node): + name = node.getAttribute('name') + doc = node.getAttribute('docs') + print "\section config_%s %s" % (name.lower(), doc) + # Start of list has been moved to the first option for better + # anchor placement + # print "<dl>" + # print "" + first = True + for n in node.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + first = parseOptionDoc(n, first) + if (not first): + print "</dl>" + + +def parseGroupsList(node, commandsList): + list = () + for n in node.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + type = n.getAttribute('type') + if type != 'obsolete': + commandsList = commandsList + (n.getAttribute('id'),) + return commandsList + + +def parseDocs(node): + doc = "" + for n in node.childNodes: + if n.nodeType == Node.TEXT_NODE: + doc += n.nodeValue.strip() + if n.nodeType == Node.CDATA_SECTION_NODE: + doc += n.nodeValue.rstrip("\r\n ").lstrip("\r\n") + #doc += "<br>" + return doc + + +def parseHeaderDoc(node): + doc = "" + for n in node.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "docs"): + if (n.getAttribute('documentation') != "0"): + doc += parseDocs(n) + print doc + + +def parseFooterDoc(node): + doc = "" + for n in node.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "docs"): + if (n.getAttribute('documentation') != "0"): + doc += parseDocs(n) + print doc + def main(): - doc = xml.dom.minidom.parse(sys.argv[1]) + if len(sys.argv)<3 or (not sys.argv[1] in ['-doc','-cpp','-wiz']): + sys.exit('Usage: %s -doc|-cpp|-wiz config.xml' % sys.argv[0]) + try: + doc = xml.dom.minidom.parse(sys.argv[2]) + except Exception as inst: + print >> sys.stderr + print >> sys.stderr, inst + print >> sys.stderr + sys.exit(1) elem = doc.documentElement - print "/* WARNING: This file is generated!" - print " * Do not edit this file, but edit config.xml instead and run" - print " * python configgen.py to regenerate this file!" - print " */" - print "" - print "#include \"configoptions.h\"" - print "#include \"config.h\"" - print "#include \"portable.h\"" - print "#include \"settings.h\"" - print "" - print "void addConfigOptions(Config *cfg)" - print "{" - print " ConfigString *cs;" - print " ConfigEnum *ce;" - print " ConfigList *cl;" - print " ConfigInt *ci;" - print " ConfigBool *cb;" - print "" - for n in elem.childNodes: - if n.nodeType == Node.ELEMENT_NODE: - parseGroups(n) - print "}" + if (sys.argv[1] == "-doc"): + print "/* WARNING: This file is generated!" + print " * Do not edit this file, but edit config.xml instead and run" + print " * python configgen.py -doc config.xml to regenerate this file!" + print " */" + # process header + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "header"): + parseHeaderDoc(n) + # generate list with all commands + commandsList = () + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "group"): + commandsList = parseGroupsList(n, commandsList) + print "\\secreflist" + for x in sorted(commandsList): + print "\\refitem cfg_%s %s" % (x.lower(), x) + print "\\endsecreflist" + # process groups and options + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "group"): + parseGroupsDoc(n) + # process footers + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "footer"): + parseFooterDoc(n) + elif (sys.argv[1] == "-cpp"): + print "/* WARNING: This file is generated!" + print " * Do not edit this file, but edit config.xml instead and run" + print " * python configgen.py -cpp config.xml to regenerate this file!" + print " */" + print "" + print "#include \"configoptions.h\"" + print "#include \"config.h\"" + print "#include \"portable.h\"" + print "#include \"settings.h\"" + print "" + print "void addConfigOptions(Config *cfg)" + print "{" + print " ConfigString *cs;" + print " ConfigEnum *ce;" + print " ConfigList *cl;" + print " ConfigInt *ci;" + print " ConfigBool *cb;" + print "" + # process header + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "header"): + parseHeader(n,'cfg') + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "group"): + parseGroups(n) + print "}" + elif (sys.argv[1] == "-wiz"): + print "/* WARNING: This file is generated!" + print " * Do not edit this file, but edit config.xml instead and run" + print " * python configgen.py -wiz config.xml to regenerate this file!" + print " */" + print "#include \"configdoc.h\"" + print "#include \"docintf.h\"" + print "" + print "void addConfigDocs(DocIntf *doc)" + print "{" + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "header"): + parseHeader(n,'doc') + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "group"): + parseGroupCDocs(n) + print "}" if __name__ == '__main__': main() - |