doxygen_xml_parser.py
Go to the documentation of this file.
1 #!/usr/bin/python3
2 
3 from __future__ import print_function
4 from lxml import etree
5 from os import path
6 from xml_docstring import XmlDocString
7 import sys
8 
9 template_file_header = """#ifndef DOXYGEN_AUTODOC_{header_guard}
10 #define DOXYGEN_AUTODOC_{header_guard}
11 
12 #include "{path}/doxygen.hh"
13 """
14 template_file_footer = """
15 #endif // DOXYGEN_AUTODOC_{header_guard}
16 """
17 
18 template_class_doc = """
19 template <{tplargs}>
20 struct class_doc_impl< {classname} >
21 {{
22 static inline const char* run ()
23 {{
24  return "{docstring}";
25 }}
26 static inline const char* attribute (const char* attrib)
27 {{{attributes}
28  (void)attrib; // turn off unused parameter warning.
29  return "";
30 }}
31 }};"""
32 template_class_attribute_body = """
33  if (strcmp(attrib, "{attribute}") == 0)
34  return "{docstring}";"""
35 template_constructor_doc = """
36 template <{tplargs}>
37 struct constructor_{nargs}_impl< {classname_prefix}{comma}{argsstring} >
38 {{
39 static inline const char* doc ()
40 {{
41  return "{docstring}";
42 }}
43 static inline boost::python::detail::keywords<{nargs}+1> args ()
44 {{
45  return ({argnamesstring});
46 }}
47 }};"""
48 template_destructor_doc = """
49 template <{tplargs}>
50 struct destructor_doc_impl < {classname_prefix} >
51 {{
52 static inline const char* run ()
53 {{
54  return "{docstring}";
55 }}
56 }};"""
57 template_member_func_doc = """
58 {template}inline const char* member_func_doc ({rettype} ({classname_prefix}*function_ptr) {argsstring})
59 {{{body}
60  return "";
61 }}"""
62 template_member_func_doc_body = """
63  if (function_ptr == static_cast<{rettype} ({classname_prefix}*) {argsstring}>(&{classname_prefix}{membername}))
64  return "{docstring}";"""
65 template_member_func_args = """
66 {template}inline boost::python::detail::keywords<{n}> member_func_args ({rettype} ({classname_prefix}*function_ptr) {argsstring})
67 {{{body}
68  return ({default_args});
69 }}"""
70 template_member_func_args_body = """
71  if (function_ptr == static_cast<{rettype} ({classname_prefix}*) {argsstring}>(&{classname_prefix}{membername}))
72  return ({args});"""
73 template_static_func_doc = """
74 {template}inline const char* member_func_doc ({rettype} (*function_ptr) {argsstring})
75 {{{body}
76  return "";
77 }}"""
78 template_static_func_doc_body = """
79  if (function_ptr == static_cast<{rettype} (*) {argsstring}>(&{namespace}::{membername}))
80  return "{docstring}";"""
81 template_open_namespace = """namespace {namespace} {{"""
82 template_close_namespace = """}} // namespace {namespace}"""
83 template_include_intern = """#include <doxygen_autodoc/{filename}>
84 """
85 template_include_extern = """#include <{filename}>
86 """
87 
88 
90  type = param.find("type")
91  declname = param.find("declname")
92  defname = param.find("defname")
93  # FIXME type may contain references in two ways:
94  # - the real param type
95  # - the name of the template argument is recognized as the name of a type...
96  if defname is None and declname is None:
97  typetext = type.text
98  for c in type.iter():
99  if c == type:
100  continue
101  if c.text is not None:
102  typetext += c.text
103  if c.tail is not None:
104  typetext += c.tail
105  if typetext.startswith("typename") or typetext.startswith("class"):
106  if sys.version_info.major == 2:
107  s = typetext.split()
108  return {"type": s[0].strip(), "name": typetext[len(s[0]) :].strip()}
109  else:
110  s = typetext.split(maxsplit=1)
111  assert len(s) == 2
112  return {"type": s[0].strip(), "name": s[1].strip()}
113  else:
114  return {"type": type.text, "name": ""}
115  else:
116  assert defname.text == declname.text
117  return {"type": type.text, "name": defname.text}
118 
119 
120 def makeHeaderGuard(filename):
121  import os
122 
123  return filename.upper().replace(".", "_").replace("/", "_").replace("-", "_")
124 
125 
126 def format_description(brief, detailed):
127  b = [el.text.strip() for el in brief.iter() if el.text] if brief is not None else []
128  d = (
129  [el.text.strip() for el in detailed.iter() if el.text]
130  if detailed is not None
131  else []
132  )
133  text = "".join(b)
134  if d:
135  text += "\n" + "".join(d)
136  return text
137 
138 
139 class Reference(object):
140  def __init__(self, index, id=None, name=None):
141  self.id = id
142  self.name = name
143  self.index = index
144 
145  def xmlToType(self, node, array=None, parentClass=None, tplargs=None):
146  """
147  - node:
148  - parentClass: a class
149  - tplargs: if one of the args is parentClass and no template arguments are provided,
150  set the template arguments to this value
151  - array: content of the sibling tag 'array'
152  """
153  if node.text is not None:
154  t = node.text.strip()
155  else:
156  t = ""
157  for c in node.iterchildren():
158  if c.tag == "ref":
159  refid = c.attrib["refid"]
160  if parentClass is not None and refid == parentClass.id:
161  t += " " + parentClass.name
162  if c.tail is not None and c.tail.lstrip()[0] != "<":
163  if tplargs is not None:
164  t += tplargs
165  elif (
166  parentClass is not None
167  and isinstance(parentClass, ClassCompound)
168  and parentClass.hasTypeDef(c.text.strip())
169  ):
170  parent_has_templates = len(parentClass.template_params) > 0
171  if parent_has_templates:
172  t += " typename " + parentClass._className() + "::"
173  else:
174  t += " " + parentClass._className() + "::"
175  self_has_templates = (
176  c.tail is not None and c.tail.strip().find("<") != -1
177  )
178  if self_has_templates:
179  t += " template "
180  t += c.text.strip()
181  elif self.index.hasref(refid):
182  t += " " + self.index.getref(refid).name
183  else:
184  self.index.output.warn("Unknown reference: ", c.text, refid)
185  t += " " + c.text.strip()
186  else:
187  if c.text is not None:
188  t += " " + c.text.strip()
189  if c.tail is not None:
190  t += " " + c.tail.strip()
191  if array is not None:
192  t += array.text
193  return t
194 
195 
196 # Only for function as of now.
198  def __init__(self, index, memberdefxml, parent):
199  super(MemberDef, self).__init__(
200  index=index,
201  id=memberdefxml.attrib["id"],
202  name=memberdefxml.find("definition").text,
203  )
204  self.parent = parent
205 
206  self.xml = memberdefxml
207  self.const = memberdefxml.attrib["const"] == "yes"
208  self.static = memberdefxml.attrib["static"] == "yes"
209  self.rettype = memberdefxml.find("type")
210  self.params = tuple(
211  [
212  (param.find("type"), param.find("declname"), param.find("array"))
213  for param in self.xml.findall("param")
214  ]
215  )
216  self.special = (
217  self.rettype.text is None and len(self.rettype.getchildren()) == 0
218  )
219  # assert self.special or len(self.rettype.text) > 0
220 
221  self._templateParams(self.xml.find("templateparamlist"))
222 
223  def _templateParams(self, tpl):
224  if tpl is not None:
225  self.template_params = tuple(
226  [_templateParamToDict(param) for param in tpl.iterchildren(tag="param")]
227  )
228  else:
229  self.template_params = tuple()
230 
231  def prototypekey(self):
232  prototype = (
233  self.xmlToType(self.rettype, parentClass=self.parent),
234  tuple([tuple(t.items()) for t in self.template_params]),
235  tuple(
236  [
237  self.xmlToType(param.find("type"), parentClass=self.parent)
238  for param in self.xml.findall("param")
239  ]
240  ),
241  self.const,
242  )
243  return prototype
244 
245  def s_prototypeArgs(self):
246  return "({0}){1}".format(self.s_args(), " const" if self.const else "")
247 
248  def s_args(self):
249  # If the class is templated, check if one of the argument is the class itself.
250  # If so, we must add the template arguments to the class (if there is none)
251 
252  if len(self.parent.template_params) > 0:
253  tplargs = (
254  " <"
255  + ", ".join([d["name"] for d in self.parent.template_params])
256  + " > "
257  )
258  args = ", ".join(
259  [
260  self.xmlToType(
261  type, array, parentClass=self.parent, tplargs=tplargs
262  )
263  for type, declname, array in self.params
264  ]
265  )
266  else:
267  args = ", ".join(
268  [
269  self.xmlToType(type, array, parentClass=self.parent)
270  for type, declname, array in self.params
271  ]
272  )
273  return args
274 
275  def s_tpldecl(self):
276  if len(self.template_params) == 0:
277  return ""
278  return ", ".join([d["type"] + " " + d["name"] for d in self.template_params])
279 
280  def s_rettype(self):
281  assert (
282  not self.special
283  ), "Member {} ({}) is a special function and no return type".format(
284  self.name, self.id
285  )
286  if len(self.parent.template_params) > 0:
287  tplargs = (
288  " <"
289  + ", ".join([d["name"] for d in self.parent.template_params])
290  + " > "
291  )
292  else:
293  tplargs = None
294  if isinstance(self.parent, ClassCompound):
295  return self.xmlToType(
296  self.rettype, parentClass=self.parent, tplargs=tplargs
297  )
298  else:
299  return self.xmlToType(self.rettype)
300 
301  def s_name(self):
302  return self.xml.find("name").text.strip()
303 
304  def s_docstring(self):
305  return self.index.xml_docstring.getDocString(
306  self.xml.find("briefdescription"),
307  self.xml.find("detaileddescription"),
308  self.index.output,
309  )
310 
311  def n_args(self):
312  return len(self.params)
313 
314  def s_argnamesstring(self):
315  def getdeclname(i, declname):
316  if declname is None or declname.text is None or declname.text.strip() == "":
317  return "arg{}".format(i)
318  return declname.text.strip()
319 
320  arg = """boost::python::arg("{}")"""
321  argnames = [
322  "self",
323  ] + [getdeclname(i, declname) for i, (_, declname, _) in enumerate(self.params)]
324  return ", ".join([arg.format(n) for n in argnames])
325 
326  def include(self):
327  import os.path
328 
329  loc = self.xml.find("location")
330  # The location is based on $CMAKE_SOURCE_DIR. Remove first directory.
331  return loc.attrib["file"].split("/", 1)[1]
332 
333 
335  def __init__(self, compound, index):
336  self.compound = compound
337  self.filename = path.join(index.directory, compound.attrib["refid"] + ".xml")
338  self.tree = etree.parse(self.filename)
339  self.definition = self.tree.getroot().find("compounddef")
340  super(CompoundBase, self).__init__(
341  index,
342  id=self.definition.attrib["id"],
343  name=self.definition.find("compoundname").text,
344  )
345 
346 
348  def __init__(self, *args):
349  super(NamespaceCompound, self).__init__(*args)
350  self.typedefs = []
351  self.enums = []
352  self.static_funcs = []
353  self.template_params = tuple()
354 
355  # Add references
356  for section in self.definition.iterchildren("sectiondef"):
357  assert "kind" in section.attrib
358  kind = section.attrib["kind"]
359  if kind == "enum":
360  self.parseEnumSection(section)
361  elif kind == "typedef":
362  self.parseTypedefSection(section)
363  elif kind == "func":
364  self.parseFuncSection(section)
365 
366  def parseEnumSection(self, section):
367  for member in section.iterchildren("memberdef"):
368  ref = Reference(
369  index=self.index,
370  id=member.attrib["id"],
371  name=self.name + "::" + member.find("name").text,
372  )
373  self.index.registerReference(ref)
374  self.enums.append(member)
375  for value in member.iterchildren("enumvalue"):
376  ref = Reference(
377  index=self.index,
378  id=value.attrib["id"],
379  name=self.name + "::" + member.find("name").text,
380  )
381 
382  def parseTypedefSection(self, section):
383  for member in section.iterchildren("memberdef"):
384  ref = Reference(
385  index=self.index,
386  id=member.attrib["id"],
387  name=self.name + "::" + member.find("name").text,
388  )
389  self.index.registerReference(ref)
390  self.typedefs.append(member)
391 
392  def parseFuncSection(self, section):
393  for member in section.iterchildren("memberdef"):
394  self.static_funcs.append(MemberDef(self.index, member, self))
395 
396  def innerNamespace(self):
397  return self.name
398 
399  def write(self, output):
400  pass
401 
402 
403 class ClassCompound(CompoundBase):
404  def __init__(self, *args):
405  super(ClassCompound, self).__init__(*args)
406  self.member_funcs = list()
407  self.static_funcs = list()
408  self.special_funcs = list()
409  self.attributes = list()
410 
411  self.struct = self.compound.attrib["kind"] == "struct"
412  self.public = self.definition.attrib["prot"] == "public"
413  self.template_specialization = self.name.find("<") > 0
414  self.typedef = dict()
415 
416  # Handle templates
417  self._templateParams(self.definition.find("templateparamlist"))
418  for memberdef in self.definition.iter(tag="memberdef"):
419  if memberdef.attrib["prot"] != "public":
420  continue
421  if memberdef.attrib["kind"] == "variable":
422  self._attribute(memberdef)
423  elif memberdef.attrib["kind"] == "typedef":
424  ref = Reference(
425  index=self.index,
426  id=memberdef.attrib["id"],
427  name=self._className() + "::" + memberdef.find("name").text,
428  )
429  self.index.registerReference(ref)
430  self.typedef[memberdef.find("name").text.strip()] = True
431 
432  elif memberdef.attrib["kind"] == "enum":
433  ref = Reference(
434  index=self.index,
435  id=memberdef.attrib["id"],
436  name=self._className() + "::" + memberdef.find("name").text,
437  )
438  self.index.registerReference(ref)
439  for value in memberdef.iterchildren("enumvalue"):
440  ref = Reference(
441  index=self.index,
442  id=value.attrib["id"],
443  name=self._className() + "::" + memberdef.find("name").text,
444  )
445  self.index.registerReference(ref)
446  elif memberdef.attrib["kind"] == "function":
447  self._memberfunc(memberdef)
448 
449  def _templateParams(self, tpl):
450  if tpl is not None:
451  self.template_params = tuple(
452  [_templateParamToDict(param) for param in tpl.iterchildren(tag="param")]
453  )
454  else:
455  self.template_params = tuple()
456 
457  def _templateDecl(self):
458  if not hasattr(self, "template_params") or len(self.template_params) == 0:
459  return ""
460  return ", ".join([d["type"] + " " + d["name"] for d in self.template_params])
461 
462  def _className(self):
463  if not hasattr(self, "template_params") or len(self.template_params) == 0:
464  return self.name
465  return (
466  self.name
467  + " <"
468  + ", ".join([d["name"] for d in self.template_params])
469  + " >"
470  )
471 
472  def hasTypeDef(self, typename):
473  return typename in self.typedef
474 
475  def innerNamespace(self):
476  return self._className()
477 
478  def _memberfunc(self, member):
479  m = MemberDef(self.index, member, self)
480  if m.special:
481  self.special_funcs.append(m)
482  elif m.static:
483  self.static_funcs.append(m)
484  else:
485  self.member_funcs.append(m)
486 
487  def _writeClassDoc(self, output):
488  docstring = self.index.xml_docstring.getDocString(
489  self.definition.find("briefdescription"),
490  self.definition.find("detaileddescription"),
491  self.index.output,
492  )
493  attribute_docstrings = ""
494  for member in self.attributes:
495  _dc = self.index.xml_docstring.getDocString(
496  member.find("briefdescription"),
497  member.find("detaileddescription"),
498  self.index.output,
499  )
500  if len(_dc) == 0:
501  continue
502  attribute_docstrings += template_class_attribute_body.format(
503  attribute=member.find("name").text,
504  docstring=_dc,
505  )
506  if len(docstring) == 0 and len(attribute_docstrings) == 0:
507  return
508  output.out(
509  template_class_doc.format(
510  tplargs=self._templateDecl(),
511  classname=self._className(),
512  docstring=docstring,
513  attributes=attribute_docstrings,
514  )
515  )
516 
517  def write(self, output):
518  if not self.public:
519  return
520  if self.template_specialization:
521  output.warn(
522  "Disable class {} because template argument are not resolved for templated class specialization.".format(
523  self.name
524  )
525  )
526  return
527 
528  include = self.definition.find("includes")
529  if include is None:
530  output.err("Does not know where to write doc of", self.name)
531  return
532  output.open(include.text)
533  output.out(template_include_extern.format(filename=include.text))
534  output.out(template_open_namespace.format(namespace="doxygen"))
535 
536  # Write class doc
537  self._writeClassDoc(output)
538 
539  # Group member function by prototype
540  member_funcs = dict()
541  for m in self.member_funcs:
542  prototype = m.prototypekey()
543  if prototype in member_funcs:
544  member_funcs[prototype].append(m)
545  else:
546  member_funcs[prototype] = [
547  m,
548  ]
549 
550  classname_prefix = self._className() + "::"
551 
552  for member in self.special_funcs:
553  docstring = member.s_docstring()
554  argnamesstring = member.s_argnamesstring()
555  if len(docstring) == 0 and len(argnamesstring) == 0:
556  continue
557  if member.s_name()[0] == "~":
558  output.out(
559  template_destructor_doc.format(
560  tplargs=self._templateDecl(),
561  classname_prefix=self._className(),
562  docstring=docstring,
563  )
564  )
565  else:
566  output.out(
567  template_constructor_doc.format(
568  tplargs=", ".join(
569  [
570  d["type"] + " " + d["name"]
571  for d in self.template_params + member.template_params
572  ]
573  ),
574  nargs=len(member.params),
575  comma=", " if len(member.params) > 0 else "",
576  classname_prefix=self._className(),
577  argsstring=member.s_args(),
578  docstring=docstring,
579  argnamesstring=argnamesstring,
580  )
581  )
582 
583  for prototype, members in member_funcs.items():
584  # remove undocumented members
585  documented_members = []
586  docstrings = []
587  argnamesstrings = []
588  for member in members:
589  docstring = member.s_docstring()
590  argnamesstring = member.s_argnamesstring()
591  if len(docstring) == 0 and len(argnamesstring) == 0:
592  continue
593  documented_members.append(member)
594  docstrings.append(docstring)
595  argnamesstrings.append(argnamesstring)
596  if len(documented_members) == 0:
597  continue
598 
599  # Write docstrings
600  body = "".join(
601  [
602  template_member_func_doc_body.format(
603  classname_prefix=classname_prefix,
604  membername=member.s_name(),
605  docstring=docstring,
606  rettype=member.s_rettype(),
607  argsstring=member.s_prototypeArgs(),
608  )
609  for member, docstring in zip(documented_members, docstrings)
610  ]
611  )
612 
613  member = members[0]
614  tplargs = ", ".join(
615  [
616  d["type"] + " " + d["name"]
617  for d in self.template_params + member.template_params
618  ]
619  )
620  output.out(
621  template_member_func_doc.format(
622  template="template <{}>\n".format(tplargs)
623  if len(tplargs) > 0
624  else "",
625  rettype=member.s_rettype(),
626  classname_prefix=classname_prefix,
627  argsstring=member.s_prototypeArgs(),
628  body=body,
629  )
630  )
631 
632  # Write argnamesstrings
633  body = "".join(
634  [
635  template_member_func_args_body.format(
636  classname_prefix=classname_prefix,
637  membername=member.s_name(),
638  args=argnamesstring,
639  rettype=member.s_rettype(),
640  argsstring=member.s_prototypeArgs(),
641  )
642  for member, argnamesstring in zip(
643  documented_members, argnamesstrings
644  )
645  ]
646  )
647 
648  n_args = member.n_args()
649 
650  default_args = ", ".join(
651  [
652  """boost::python::arg("self")""",
653  ]
654  + ["""boost::python::arg("arg{}")""".format(i) for i in range(n_args)]
655  )
656  output.out(
657  template_member_func_args.format(
658  template="template <{}>\n".format(tplargs)
659  if len(tplargs) > 0
660  else "",
661  rettype=member.s_rettype(),
662  n=n_args + 1,
663  default_args=default_args,
664  classname_prefix=classname_prefix,
665  argsstring=member.s_prototypeArgs(),
666  body=body,
667  )
668  )
669 
670  output.out(template_close_namespace.format(namespace="doxygen"))
671  output.close()
672 
673  def _attribute(self, member):
674  self.attributes.append(member)
675 
676 
677 class Index:
678  """
679  This class is responsible for generating the list of all C++-usable documented elements.
680  """
681 
682  def __init__(self, input, output):
683  self.tree = etree.parse(input)
684  self.directory = path.dirname(input)
686  self.compounds = list()
687  self.references = dict()
688  self.output = output
689 
690  def parseCompound(self):
691  for compound in self.tree.getroot().iterchildren("compound"):
692  if compound.attrib["kind"] in ["class", "struct"]:
693  obj = ClassCompound(compound, self)
694  elif compound.attrib["kind"] == "namespace":
695  obj = NamespaceCompound(compound, self)
696  if obj.id not in self.compounds:
697  self.compounds.append(obj.id)
698  self.registerReference(obj)
699 
700  def write(self):
701  # Header
702  from os.path import abspath, dirname
703  from time import asctime
704 
705  self.output.open("doxygen_xml_parser_for_cmake.hh")
706  # self.output.out ("// Generated on {}".format (asctime()))
707  self.output.close()
708 
709  # Implement template specialization for classes and member functions
710  for id in self.compounds:
711  compound = self.references[id]
712  compound.write(self.output)
713 
714  self.output.open("functions.h")
715 
716  # Implement template specialization for static functions
717  static_funcs = dict()
718  prototypes = list()
719  includes = list()
720  for id in self.compounds:
721  compound = self.references[id]
722  for m in compound.static_funcs:
723  include = m.include()
724  if include not in includes:
725  includes.append(include)
726  docstring = m.s_docstring()
727  if len(docstring) == 0:
728  continue
729  prototype = m.prototypekey()
730  if prototype in static_funcs:
731  static_funcs[prototype].append((m, docstring))
732  else:
733  static_funcs[prototype] = [
734  (m, docstring),
735  ]
736  prototypes.append(prototype)
737 
738  self.output.out(
739  "".join(
740  [
741  template_include_extern.format(filename=filename)
742  for filename in includes
743  ]
744  )
745  )
746 
747  self.output.out(template_open_namespace.format(namespace="doxygen"))
748 
749  for prototype in prototypes:
750  member_and_docstring_s = static_funcs[prototype]
751  body = "".join(
752  [
753  template_static_func_doc_body.format(
754  namespace=member.parent.innerNamespace(),
755  membername=member.s_name(),
756  docstring=docstring,
757  rettype=member.s_rettype(),
758  argsstring=member.s_prototypeArgs(),
759  )
760  for member, docstring in member_and_docstring_s
761  ]
762  )
763 
764  member = member_and_docstring_s[0][0]
765  # TODO fix case of static method in templated class.
766  tplargs = ", ".join(
767  [
768  d["type"] + " " + d["name"]
769  for d in member.parent.template_params + member.template_params
770  ]
771  )
772  self.output.out(
773  template_static_func_doc.format(
774  template="template <{}>\n".format(tplargs)
775  if len(tplargs) > 0
776  else "",
777  rettype=member.s_rettype(),
778  argsstring=member.s_prototypeArgs(),
779  body=body,
780  )
781  )
782 
783  self.output.out(template_close_namespace.format(namespace="doxygen"))
784  self.output.close()
785 
786  def registerReference(self, obj, overwrite=True):
787  if obj.id in self.references:
788  if obj.name != self.references[obj.id].name:
789  self.output.warn(
790  "!!!! Compounds " + obj.id + " already exists.",
791  obj.name,
792  self.references[obj.id].name,
793  )
794  else:
795  self.output.warn("Reference " + obj.id + " already exists.", obj.name)
796  if not overwrite:
797  return
798  self.references[obj.id] = obj
799 
800  def hasref(self, id):
801  return id in self.references
802 
803  def getref(self, id):
804  return self.references[id]
805 
806 
807 class OutputStreams(object):
808  def __init__(self, output_dir, warn, error, errorPrefix=""):
809  self.output_dir = output_dir
810  self._out = None
811  self._warn = warn
812  self._err = error
813  self.errorPrefix = errorPrefix
814 
815  self._created_files = dict()
816 
817  def open(self, name):
818  assert self._out == None, "You did not close the previous file"
819  import os
820 
821  fullname = os.path.join(self.output_dir, name)
822  dirname = os.path.dirname(fullname)
823  if not os.path.isdir(dirname):
824  os.makedirs(dirname)
825 
826  if name in self._created_files:
827  self._out = self._created_files[name]
828  else:
829  import codecs
830 
831  if sys.version_info >= (3,):
832  encoding = "utf-8"
833  else:
834  encoding = "latin1"
835  self._out = codecs.open(fullname, mode="w", encoding=encoding)
836  self._created_files[name] = self._out
837 
838  # Header
839  self.out(
840  template_file_header.format(
841  path=os.path.dirname(os.path.abspath(__file__)),
842  header_guard=makeHeaderGuard(name),
843  )
844  )
845 
846  def close(self):
847  self._out = None
848 
850  for n, f in self._created_files.items():
851  # Footer
852  self._out = f
853  self.out(
854  template_file_footer.format(
855  header_guard=makeHeaderGuard(n),
856  )
857  )
858  f.close()
859  self._created_files.clear()
860  self._out = None
861 
862  def out(self, *args):
863  if sys.version_info >= (3,):
864  print(*args, file=self._out)
865  else:
866  print(" ".join(str(arg) for arg in args).decode("latin1"), file=self._out)
867 
868  def warn(self, *args):
869  print(self.errorPrefix, *args, file=self._warn)
870 
871  def err(self, *args):
872  print(self.errorPrefix, *args, file=self._err)
873 
874 
875 if __name__ == "__main__":
876  import argparse
877 
878  parser = argparse.ArgumentParser(
879  description="Process Doxygen XML documentation and generate C++ code."
880  )
881  parser.add_argument("doxygen_index_xml", type=str, help="the Doxygen XML index.")
882  parser.add_argument("output_directory", type=str, help="the output directory.")
883  args = parser.parse_args()
884 
885  index = Index(
886  input=sys.argv[1],
887  output=OutputStreams(args.output_directory, sys.stdout, sys.stderr),
888  )
889  index.parseCompound()
890  index.write()
891  index.output.writeFooterAndCloseFiles()
892  assert index.output._out == None
def format_description(brief, detailed)
def _templateParamToDict(param)
def __init__(self, index, id=None, name=None)
def registerReference(self, obj, overwrite=True)
def xmlToType(self, node, array=None, parentClass=None, tplargs=None)
def __init__(self, index, memberdefxml, parent)
def makeHeaderGuard(filename)
def __init__(self, input, output)
def __init__(self, compound, index)
def __init__(self, output_dir, warn, error, errorPrefix="")


hpp-fcl
Author(s):
autogenerated on Fri Jun 2 2023 02:39:01