#!/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 # for any purpose. It is provided "as is" without express or implied warranty. # See the GNU General Public License for more details. # # Documents produced by Doxygen are derivative works derived from the # input used in their production; they are not affected by this license. # import xml.dom.minidom import sys import re import textwrap from xml.dom import minidom, 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("", "") doc = doc.replace("", "") 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 -> 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) #description -> description (see: address) doc = re.sub('([^<]*)', '\\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. #
will be removed later on again, we need it here otherwise splitlines # will filter the extra line. doc = doc.replace("
", "\n
\n") # a dirty trick to go to the next line in Doxyfile documentation. #
will be removed later on again, we need it here otherwise splitlines # will filter the line break. doc = doc.replace("
", "\n
\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: if (line.strip() != "
"): docC.append(line.strip().replace('\\', '\\\\'). replace('"', '\\"').replace("
", "")) 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') != "": if n.getAttribute('show_docu') != "NO": name = "" + n.getAttribute('name') + "" 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: 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 += "
The default value is: %s." % (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." % ("The default value is", "system dependent") else: doc += "
%s: %s." % ("The default value is", "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: %s." % ( defval) elif format == 'file': abspath = node.getAttribute('abspath') if defval != '': if abspath != '1': doc += "
The default file is: %s." % ( defval) else: doc += "
%s: %s%s%s." % ( "The default file (with absolute path) is", "",defval,"") else: if abspath == '1': doc += "
The file has to be specified with full path." else: # format == 'string': if defval != '': doc += "
The default value is: %s." % ( defval) # depends handling if (node.hasAttribute('depends')): depends = node.getAttribute('depends') 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): # 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') docC = prepCDocs(node); if len(setting) > 0: print "#if %s" % (setting) print " //----" if type == 'bool': if len(adefval) > 0: enabled = adefval elif defval == '1': enabled = "TRUE" else: enabled = "FALSE" 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) 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 "#endif" def parseGroups(node): name = node.getAttribute('name') 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 "
" print "" print "
\\c %s
" % (name) else: print " \\anchor cfg_%s" % (name.lower()) print "
\\c %s
" % (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 "" print "The default value is: %s." % (defval) print "" elif (type == 'int'): minval = node.getAttribute('minval') maxval = node.getAttribute('maxval') print "" print "" print "%s: %s%s%s, %s: %s%s%s, %s: %s%s%s." % ( " Minimum value", "", minval, "", "maximum value", "", maxval, "", "default value", "", defval, "") print "" elif (type == 'bool'): print "" print "" if (node.hasAttribute('altdefval')): print "The default value is: system dependent." else: print "The default value is: %s." % ( "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 "" print "The default directory is: %s." % ( defval) elif format == 'file': abspath = node.getAttribute('abspath') if defval != '': print "" if abspath != '1': print "The default file is: %s." % ( defval) else: print "%s: %s%s%s." % ( "The default file (with absolute path) is", "",defval,"") else: if abspath == '1': print "" print "The file has to be specified with full path." else: # format == 'string': if defval != '': print "" print "The default value is: %s." % ( defval) print "" # depends handling if (node.hasAttribute('depends')): depends = node.getAttribute('depends') print "" 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 "
" # print "" first = True for n in node.childNodes: if n.nodeType == Node.ELEMENT_NODE: first = parseOptionDoc(n, first) if (not first): print "
" 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 += "
" 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(): 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 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()