Imported Upstream version 1.8.8
[platform/upstream/doxygen.git] / src / configgen.py
1 #!/usr/bin/python
2 # python script to generate configoptions.cpp and config.doc from config.xml
3 #
4 # Copyright (C) 1997-2014 by Dimitri van Heesch.
5 #
6 # Permission to use, copy, modify, and distribute this software and its
7 # documentation under the terms of the GNU General Public License is hereby
8 # granted. No representations are made about the suitability of this software
9 # for any purpose. It is provided "as is" without express or implied warranty.
10 # See the GNU General Public License for more details.
11 #
12 # Documents produced by Doxygen are derivative works derived from the
13 # input used in their production; they are not affected by this license.
14 #
15 import xml.dom.minidom
16 import sys
17 import re
18 import textwrap
19 from xml.dom import minidom, Node
20
21 def transformDocs(doc):
22         # join lines, unless it is an empty line
23         # remove doxygen layout constructs
24         doc = doc.strip()
25         doc = doc.replace("\n", " ")
26         doc = doc.replace("\r", " ")
27         doc = doc.replace("\t", " ")
28         doc = doc.replace("\\&", "&")
29         doc = doc.replace("\\c ", " ")
30         doc = doc.replace("\\b ", " ")
31         doc = doc.replace("\\e ", " ")
32         doc = doc.replace("\\$", "$")
33         doc = doc.replace("\\#include ", "#include ")
34         doc = doc.replace("\\#undef ", "#undef ")
35         doc = doc.replace("-# ", "\n - ")
36         doc = doc.replace(" - ", "\n - ")
37         doc = doc.replace("\\sa", "\nSee also: ")
38         doc = doc.replace("\\par", "\n")
39         doc = doc.replace("@note", "\nNote:")
40         doc = doc.replace("\\note", "\nNote:")
41         doc = doc.replace("\\verbatim", "\n")
42         doc = doc.replace("\\endverbatim", "\n")
43         doc = doc.replace("<code>", "")
44         doc = doc.replace("</code>", "")
45         doc = doc.replace("`", "")
46         doc = doc.replace("\\<", "<")
47         doc = doc.replace("\\>", ">")
48         doc = doc.replace("\\@", "@")
49         doc = doc.replace("\\\\", "\\")
50         # \ref name "description" -> description
51         doc = re.sub('\\\\ref +[^ ]* +"([^"]*)"', '\\1', doc)
52         # \ref specials
53         # \ref <key> -> description
54         doc = re.sub('\\\\ref +doxygen_usage', '"Doxygen usage"', doc)
55         doc = re.sub('\\\\ref +extsearch', '"External Indexing and Searching"',
56                                  doc)
57         doc = re.sub('\\\\ref +external', '"Linking to external documentation"',
58                                  doc)
59         # fallback for not handled
60         doc = re.sub('\\\\ref', '', doc)
61         #<a href="address">description</a> -> description (see: address)
62         doc = re.sub('<a +href="([^"]*)" *>([^<]*)</a>', '\\2 (see: \\1)', doc)
63         # LaTeX name as formula -> LaTeX
64         doc = doc.replace("\\f$\\mbox{\\LaTeX}\\f$", "LaTeX")
65         # Other forula's (now just 2) so explicitely mentioned.
66         doc = doc.replace("\\f$2^{(16+\\mbox{LOOKUP\\_CACHE\\_SIZE})}\\f$",
67                                           "2^(16+LOOKUP_CACHE_SIZE)")
68         doc = doc.replace("\\f$2^{16} = 65536\\f$", "2^16=65536")
69         # remove consecutive spaces
70         doc = re.sub(" +", " ", doc)
71         # a dirty trick to get an extra empty line in Doxyfile documentation.
72         # <br> will be removed later on again, we need it here otherwise splitlines
73         # will filter the extra line.
74         doc = doc.replace("<br>", "\n<br>\n")
75         # a dirty trick to go to the next line in Doxyfile documentation.
76         # <br/> will be removed later on again, we need it here otherwise splitlines
77         # will filter the line break.
78         doc = doc.replace("<br/>", "\n<br/>\n")
79         #
80         doc = doc.splitlines()
81         split_doc = []
82         for line in doc:
83                 split_doc += textwrap.wrap(line, 78)
84         # replace \ by \\, replace " by \", and '  ' by a newline with end string
85         # and start string at next line
86         docC = []
87         for line in split_doc:
88                 if (line.strip() != "<br/>"):
89                         docC.append(line.strip().replace('\\', '\\\\').
90                                         replace('"', '\\"').replace("<br>", ""))
91         return docC
92
93
94 def collectValues(node):
95         values = []
96         for n in node.childNodes:
97                 if (n.nodeName == "value"):
98                         if n.nodeType == Node.ELEMENT_NODE:
99                                 if n.getAttribute('name') != "":
100                                         if n.getAttribute('show_docu') != "NO":
101                                                 name = "<code>" + n.getAttribute('name') + "</code>"
102                                                 desc = n.getAttribute('desc')
103                                                 if (desc != ""):
104                                                         name += " " + desc
105                                                 values.append(name)
106         return values
107
108
109 def addValues(var, node):
110         for n in node.childNodes:
111                 if (n.nodeName == "value"):
112                         if n.nodeType == Node.ELEMENT_NODE:
113                                 name = n.getAttribute('name')
114                                 print("  %s->addValue(\"%s\");" % (var, name))
115
116
117 def parseHeader(node,objName):
118         doc = ""
119         for n in node.childNodes:
120                 if n.nodeType == Node.ELEMENT_NODE:
121                         if (n.nodeName == "docs"):
122                                 if (n.getAttribute('doxyfile') != "0"):
123                                         doc += parseDocs(n)
124         docC = transformDocs(doc)
125         print("  %s->setHeader(" % (objName))
126         rng = len(docC)
127         for i in range(rng):
128                 line = docC[i]
129                 if i != rng - 1:  # since we go from 0 to rng-1
130                         print("              \"%s\\n\"" % (line))
131                 else:
132                         print("              \"%s\"" % (line))
133         print("             );")
134
135
136 def prepCDocs(node):
137         type = node.getAttribute('type')
138         format = node.getAttribute('format')
139         defval = node.getAttribute('defval')
140         adefval = node.getAttribute('altdefval')
141         doc = "";
142         if (type != 'obsolete'):
143                 for n in node.childNodes:
144                         if (n.nodeName == "docs"):
145                                 if (n.getAttribute('doxyfile') != "0"):
146                                         if n.nodeType == Node.ELEMENT_NODE:
147                                                 doc += parseDocs(n)
148                 if (type == 'enum'):
149                         values = collectValues(node)
150                         doc += "<br/>Possible values are: "
151                         rng = len(values)
152                         for i in range(rng):
153                                 val = values[i]
154                                 if i == rng - 2:
155                                         doc += "%s and " % (val)
156                                 elif i == rng - 1:
157                                         doc += "%s." % (val)
158                                 else:
159                                         doc += "%s, " % (val)
160                         if (defval != ""):
161                                 doc += "<br/>The default value is: <code>%s</code>." % (defval)
162                 elif (type == 'int'):
163                         minval = node.getAttribute('minval')
164                         maxval = node.getAttribute('maxval')
165                         doc += "<br/>%s: %s, %s: %s, %s: %s." % (" Minimum value", minval, 
166                                          "maximum value", maxval,
167                                          "default value", defval)
168                 elif (type == 'bool'):
169                         if (node.hasAttribute('altdefval')):
170                           doc += "<br/>%s: %s." % ("The default value is", "system dependent")
171                         else:
172                           doc += "<br/>%s: %s." % ("The default value is", "YES" if (defval == "1") else "NO")
173                 elif (type == 'list'):
174                         if format == 'string':
175                                 values = collectValues(node)
176                                 rng = len(values)
177                                 for i in range(rng):
178                                         val = values[i]
179                                         if i == rng - 2:
180                                                 doc += "%s and " % (val)
181                                         elif i == rng - 1:
182                                                 doc += "%s." % (val)
183                                         else:
184                                                 doc += "%s, " % (val)
185                 elif (type == 'string'):
186                         if format == 'dir':
187                                 if defval != '':
188                                         doc += "<br/>The default directory is: <code>%s</code>." % (
189                                                 defval)
190                         elif format == 'file':
191                                 abspath = node.getAttribute('abspath')
192                                 if defval != '':
193                                         if abspath != '1':
194                                                 doc += "<br/>The default file is: <code>%s</code>." % (
195                                                         defval)
196                                         else:
197                                                 doc += "<br/>%s: %s%s%s." % (
198                                                         "The default file (with absolute path) is",
199                                                         "<code>",defval,"</code>")
200                                 else:
201                                         if abspath == '1':
202                                                 doc += "<br/>The file has to be specified with full path."
203                         elif format =='image':
204                                 abspath = node.getAttribute('abspath')
205                                 if defval != '':
206                                         if abspath != '1':
207                                                 doc += "<br/>The default image is: <code>%s</code>." % (
208                                                         defval)
209                                         else:
210                                                 doc += "<br/>%s: %s%s%s." % (
211                                                         "The default image (with absolute path) is",
212                                                         "<code>",defval,"</code>")
213                                 else:
214                                         if abspath == '1':
215                                                 doc += "<br/>The image has to be specified with full path."
216                         else: # format == 'string':
217                                 if defval != '':
218                                         doc += "<br/>The default value is: <code>%s</code>." % (
219                                                 defval)
220                 # depends handling
221                 if (node.hasAttribute('depends')):
222                         depends = node.getAttribute('depends')
223                         doc += "<br/>%s \\ref cfg_%s \"%s\" is set to \\c YES." % (
224                                 "This tag requires that the tag", depends.lower(), depends.upper())
225
226         docC = transformDocs(doc)
227         return docC;
228
229 def parseOption(node):
230         # Handling part for Doxyfile
231         name = node.getAttribute('id')
232         type = node.getAttribute('type')
233         format = node.getAttribute('format')
234         defval = node.getAttribute('defval')
235         adefval = node.getAttribute('altdefval')
236         depends = node.getAttribute('depends')
237         setting = node.getAttribute('setting')
238         docC = prepCDocs(node);
239         if len(setting) > 0:
240                 print("#if %s" % (setting))
241         print("  //----")
242         if type == 'bool':
243                 if len(adefval) > 0:
244                         enabled = adefval
245                 elif defval == '1':
246                         enabled = "TRUE"
247                 else:
248                         enabled = "FALSE"
249                 print("  cb = cfg->addBool(")
250                 print("             \"%s\"," % (name))
251                 rng = len(docC)
252                 for i in range(rng):
253                         line = docC[i]
254                         if i != rng - 1:  # since we go from 0 to rng-1
255                                 print("              \"%s\\n\"" % (line))
256                         else:
257                                 print("              \"%s\"," % (line))
258                 print("              %s" % (enabled))
259                 print("             );")
260                 if depends != '':
261                         print("  cb->addDependency(\"%s\");" % (depends))
262         elif type == 'string':
263                 print("  cs = cfg->addString(")
264                 print("              \"%s\"," % (name))
265                 rng = len(docC)
266                 for i in range(rng):
267                         line = docC[i]
268                         if i != rng - 1:  # since we go from 0 to rng-1
269                                 print("              \"%s\\n\"" % (line))
270                         else:
271                                 print("              \"%s\"" % (line))
272                 print("             );")
273                 if defval != '':
274                         print("  cs->setDefaultValue(\"%s\");" % (defval))
275                 if format == 'file':
276                         print("  cs->setWidgetType(ConfigString::File);")
277                 elif format == 'image':
278                         print("  cs->setWidgetType(ConfigString::Image);")
279                 elif format == 'dir':
280                         print("  cs->setWidgetType(ConfigString::Dir);")
281                 if depends != '':
282                         print("  cs->addDependency(\"%s\");" % (depends))
283         elif type == 'enum':
284                 print("  ce = cfg->addEnum(")
285                 print("              \"%s\"," % (name))
286                 rng = len(docC)
287                 for i in range(rng):
288                         line = docC[i]
289                         if i != rng - 1:  # since we go from 0 to rng-1
290                                 print("              \"%s\\n\"" % (line))
291                         else:
292                                 print("              \"%s\"," % (line))
293                 print("              \"%s\"" % (defval))
294                 print("             );")
295                 addValues("ce", node)
296                 if depends != '':
297                         print("  ce->addDependency(\"%s\");" % (depends))
298         elif type == 'int':
299                 minval = node.getAttribute('minval')
300                 maxval = node.getAttribute('maxval')
301                 print("  ci = cfg->addInt(")
302                 print("              \"%s\"," % (name))
303                 rng = len(docC)
304                 for i in range(rng):
305                         line = docC[i]
306                         if i != rng - 1:  # since we go from 0 to rng-1
307                                 print("              \"%s\\n\"" % (line))
308                         else:
309                                 print("              \"%s\"," % (line))
310                 print("              %s,%s,%s" % (minval, maxval, defval))
311                 print("             );")
312                 if depends != '':
313                         print("  ci->addDependency(\"%s\");" % (depends))
314         elif type == 'list':
315                 print("  cl = cfg->addList(")
316                 print("              \"%s\"," % (name))
317                 rng = len(docC)
318                 for i in range(rng):
319                         line = docC[i]
320                         if i != rng - 1:  # since we go from 0 to rng-1
321                                 print("              \"%s\\n\"" % (line))
322                         else:
323                                 print("              \"%s\"" % (line))
324                 print("             );")
325                 addValues("cl", node)
326                 if depends != '':
327                         print("  cl->addDependency(\"%s\");" % (depends))
328                 if format == 'file':
329                         print("  cl->setWidgetType(ConfigList::File);")
330                 elif format == 'dir':
331                         print("  cl->setWidgetType(ConfigList::Dir);")
332                 elif format == 'filedir':
333                         print("  cl->setWidgetType(ConfigList::FileAndDir);")
334         elif type == 'obsolete':
335                 print("  cfg->addObsolete(\"%s\");" % (name))
336         if len(setting) > 0:
337                 print("#else")
338                 print("  cfg->addDisabled(\"%s\");" % (name))
339                 print("#endif")
340
341
342 def parseGroups(node):
343         name = node.getAttribute('name')
344         doc = node.getAttribute('docs')
345         print("%s%s" % ("  //-----------------------------------------",
346                                         "----------------------------------"))
347         print("  cfg->addInfo(\"%s\",\"%s\");" % (name, doc))
348         print("%s%s" % ("  //-----------------------------------------",
349                                         "----------------------------------"))
350         print("")
351         for n in node.childNodes:
352                 if n.nodeType == Node.ELEMENT_NODE:
353                         parseOption(n)
354
355 def parseGroupCDocs(node):
356         for n in node.childNodes:
357                 if n.nodeType == Node.ELEMENT_NODE:
358                         type = n.getAttribute('type')
359                         name = n.getAttribute('id')
360                         docC = prepCDocs(n);
361                         if type != 'obsolete':
362                                 print("  doc->add(")
363                                 print("              \"%s\"," % (name))
364                                 rng = len(docC)
365                                 for i in range(rng):
366                                         line = docC[i]
367                                         if i != rng - 1:  # since we go from 0 to rng-1
368                                                 print("              \"%s\\n\"" % (line))
369                                         else:
370                                                 print("              \"%s\"" % (line))
371                                 print("          );")
372
373 def parseOptionDoc(node, first):
374         # Handling part for documentation
375         name = node.getAttribute('id')
376         type = node.getAttribute('type')
377         format = node.getAttribute('format')
378         defval = node.getAttribute('defval')
379         adefval = node.getAttribute('altdefval')
380         depends = node.getAttribute('depends')
381         setting = node.getAttribute('setting')
382         doc = ""
383         if (type != 'obsolete'):
384                 for n in node.childNodes:
385                         if (n.nodeName == "docs"):
386                                 if (n.getAttribute('documentation') != "0"):
387                                         if n.nodeType == Node.ELEMENT_NODE:
388                                                 doc += parseDocs(n)
389                 if (first):
390                         print(" \\anchor cfg_%s" % (name.lower()))
391                         print("<dl>")
392                         print("")
393                         print("<dt>\\c %s <dd>" % (name))
394                 else:
395                         print(" \\anchor cfg_%s" % (name.lower()))
396                         print("<dt>\\c %s <dd>" % (name))
397                 print(" \\addindex %s" % (name))
398                 print(doc)
399                 if (type == 'enum'):
400                         values = collectValues(node)
401                         print("")
402                         print("Possible values are: ")
403                         rng = len(values)
404                         for i in range(rng):
405                                 val = values[i]
406                                 if i == rng - 2:
407                                         print("%s and " % (val))
408                                 elif i == rng - 1:
409                                         print("%s." % (val))
410                                 else:
411                                         print("%s, " % (val))
412                         if (defval != ""):
413                                 print("")
414                                 print("")
415                                 print("The default value is: <code>%s</code>." % (defval))
416                         print("")
417                 elif (type == 'int'):
418                         minval = node.getAttribute('minval')
419                         maxval = node.getAttribute('maxval')
420                         print("")
421                         print("")
422                         print("%s: %s%s%s, %s: %s%s%s, %s: %s%s%s." % (
423                                          " Minimum value", "<code>", minval, "</code>", 
424                                          "maximum value", "<code>", maxval, "</code>",
425                                          "default value", "<code>", defval, "</code>"))
426                         print("")
427                 elif (type == 'bool'):
428                         print("")
429                         print("")
430                         if (node.hasAttribute('altdefval')):
431                                 print("The default value is: system dependent.")
432                         else:
433                                 print("The default value is: <code>%s</code>." % (
434                                         "YES" if (defval == "1") else "NO"))
435                         print("")
436                 elif (type == 'list'):
437                         if format == 'string':
438                                 values = collectValues(node)
439                                 rng = len(values)
440                                 for i in range(rng):
441                                         val = values[i]
442                                         if i == rng - 2:
443                                                 print("%s and " % (val))
444                                         elif i == rng - 1:
445                                                 print("%s." % (val))
446                                         else:
447                                                 print("%s, " % (val))
448                         print("")
449                 elif (type == 'string'):
450                         if format == 'dir':
451                                 if defval != '':
452                                         print("")
453                                         print("The default directory is: <code>%s</code>." % (
454                                                 defval))
455                         elif format == 'file':
456                                 abspath = node.getAttribute('abspath')
457                                 if defval != '':
458                                         print("")
459                                         if abspath != '1':
460                                                 print("The default file is: <code>%s</code>." % (
461                                                         defval))
462                                         else:
463                                                 print("%s: %s%s%s." % (
464                                                         "The default file (with absolute path) is",
465                                                         "<code>",defval,"</code>"))
466                                 else:
467                                         if abspath == '1':
468                                                 print("")
469                                                 print("The file has to be specified with full path.")
470                         elif format =='image':
471                                 abspath = node.getAttribute('abspath')
472                                 if defval != '':
473                                         print("")
474                                         if abspath != '1':
475                                                 print("The default image is: <code>%s</code>." % (
476                                                         defval))
477                                         else:
478                                                 print("%s: %s%s%s." % (
479                                                         "The default image (with absolute path) is",
480                                                         "<code>",defval,"</code>"))
481                                 else:
482                                         if abspath == '1':
483                                                 print("")
484                                                 print("The image has to be specified with full path.")
485                         else: # format == 'string':
486                                 if defval != '':
487                                         print("")
488                                         print("The default value is: <code>%s</code>." % (
489                                                 defval))
490                         print("")
491                 # depends handling
492                 if (node.hasAttribute('depends')):
493                         depends = node.getAttribute('depends')
494                         print("")
495                         print("%s \\ref cfg_%s \"%s\" is set to \\c YES." % (
496                                 "This tag requires that the tag", depends.lower(), depends.upper()))
497                 return False
498
499
500 def parseGroupsDoc(node):
501         name = node.getAttribute('name')
502         doc = node.getAttribute('docs')
503         print("\section config_%s %s" % (name.lower(), doc))
504         # Start of list has been moved to the first option for better
505         # anchor placement
506         #  print "<dl>"
507         #  print ""
508         first = True
509         for n in node.childNodes:
510                 if n.nodeType == Node.ELEMENT_NODE:
511                         first = parseOptionDoc(n, first)
512         if (not first):
513                 print("</dl>")
514
515
516 def parseGroupsList(node, commandsList):
517         list = ()
518         for n in node.childNodes:
519                 if n.nodeType == Node.ELEMENT_NODE:
520                         type = n.getAttribute('type')
521                         if type != 'obsolete':
522                                 commandsList = commandsList + (n.getAttribute('id'),)
523         return commandsList
524
525
526 def parseDocs(node):
527         doc = ""
528         for n in node.childNodes:
529                 if n.nodeType == Node.TEXT_NODE:
530                         doc += n.nodeValue.strip()
531                 if n.nodeType == Node.CDATA_SECTION_NODE:
532                         doc += n.nodeValue.rstrip("\r\n ").lstrip("\r\n")
533         #doc += "<br>"
534         return doc
535
536
537 def parseHeaderDoc(node):
538         doc = ""
539         for n in node.childNodes:
540                 if n.nodeType == Node.ELEMENT_NODE:
541                         if (n.nodeName == "docs"):
542                                 if (n.getAttribute('documentation') != "0"):
543                                         doc += parseDocs(n)
544         print(doc)
545
546
547 def parseFooterDoc(node):
548         doc = ""
549         for n in node.childNodes:
550                 if n.nodeType == Node.ELEMENT_NODE:
551                         if (n.nodeName == "docs"):
552                                 if (n.getAttribute('documentation') != "0"):
553                                         doc += parseDocs(n)
554         print(doc)
555
556
557 def main():
558         if len(sys.argv)<3 or (not sys.argv[1] in ['-doc','-cpp','-wiz']):
559                 sys.exit('Usage: %s -doc|-cpp|-wiz config.xml' % sys.argv[0])
560         try:
561                 doc = xml.dom.minidom.parse(sys.argv[2])
562         except Exception as inst:
563                 sys.stdout = sys.stderr
564                 print("")
565                 print(inst)
566                 print("")
567                 sys.exit(1)
568         elem = doc.documentElement
569         if (sys.argv[1] == "-doc"):
570                 print("/* WARNING: This file is generated!")
571                 print(" * Do not edit this file, but edit config.xml instead and run")
572                 print(" * python configgen.py -doc config.xml to regenerate this file!")
573                 print(" */")
574                 # process header
575                 for n in elem.childNodes:
576                         if n.nodeType == Node.ELEMENT_NODE:
577                                 if (n.nodeName == "header"):
578                                         parseHeaderDoc(n)
579                 # generate list with all commands
580                 commandsList = ()
581                 for n in elem.childNodes:
582                         if n.nodeType == Node.ELEMENT_NODE:
583                                 if (n.nodeName == "group"):
584                                         commandsList = parseGroupsList(n, commandsList)
585                 print("\\secreflist")
586                 for x in sorted(commandsList):
587                         print("\\refitem cfg_%s %s" % (x.lower(), x))
588                 print("\\endsecreflist")
589                 # process groups and options
590                 for n in elem.childNodes:
591                         if n.nodeType == Node.ELEMENT_NODE:
592                                 if (n.nodeName == "group"):
593                                         parseGroupsDoc(n)
594                 # process footers
595                 for n in elem.childNodes:
596                         if n.nodeType == Node.ELEMENT_NODE:
597                                 if (n.nodeName == "footer"):
598                                         parseFooterDoc(n)
599         elif (sys.argv[1] == "-cpp"):
600                 print("/* WARNING: This file is generated!")
601                 print(" * Do not edit this file, but edit config.xml instead and run")
602                 print(" * python configgen.py -cpp config.xml to regenerate this file!")
603                 print(" */")
604                 print("")
605                 print("#include \"configoptions.h\"")
606                 print("#include \"config.h\"")
607                 print("#include \"portable.h\"")
608                 print("#include \"settings.h\"")
609                 print("")
610                 print("void addConfigOptions(Config *cfg)")
611                 print("{")
612                 print("  ConfigString *cs;")
613                 print("  ConfigEnum   *ce;")
614                 print("  ConfigList   *cl;")
615                 print("  ConfigInt    *ci;")
616                 print("  ConfigBool   *cb;")
617                 print("")
618                 # process header
619                 for n in elem.childNodes:
620                         if n.nodeType == Node.ELEMENT_NODE:
621                                 if (n.nodeName == "header"):
622                                         parseHeader(n,'cfg')
623                 for n in elem.childNodes:
624                         if n.nodeType == Node.ELEMENT_NODE:
625                                 if (n.nodeName == "group"):
626                                         parseGroups(n)
627                 print("}")
628         elif (sys.argv[1] == "-wiz"):
629                 print("/* WARNING: This file is generated!")
630                 print(" * Do not edit this file, but edit config.xml instead and run")
631                 print(" * python configgen.py -wiz config.xml to regenerate this file!")
632                 print(" */")
633                 print("#include \"configdoc.h\"")
634                 print("#include \"docintf.h\"")
635                 print("")
636                 print("void addConfigDocs(DocIntf *doc)")
637                 print("{")
638                 for n in elem.childNodes:
639                         if n.nodeType == Node.ELEMENT_NODE:
640                                 if (n.nodeName == "header"):
641                                         parseHeader(n,'doc')
642                 for n in elem.childNodes:
643                         if n.nodeType == Node.ELEMENT_NODE:
644                                 if (n.nodeName == "group"):
645                                         parseGroupCDocs(n)
646                 print("}")
647
648 if __name__ == '__main__':
649         main()