Add codegen to the tracked files
[platform/upstream/gst-editing-services.git] / bindings / python / codegen / docgen.py
1 #!/usr/bin/env python
2 # -*- Mode: Python; py-indent-offset: 4 -*-
3 import sys, os, string, re, getopt
4
5 import defsparser
6 import definitions
7 import override
8 import docextract
9
10 class Node:
11     def __init__(self, name, interfaces=[]):
12         self.name = name
13         self.interfaces = interfaces
14         self.subclasses = []
15     def add_child(self, node):
16         self.subclasses.append(node)
17
18 def build_object_tree(parser):
19     # reorder objects so that parent classes come first ...
20     objects = parser.objects[:]
21     pos = 0
22     while pos < len(objects):
23         parent = objects[pos].parent
24         for i in range(pos+1, len(objects)):
25             if objects[i].c_name == parent:
26                 objects.insert(i+1, objects[pos])
27                 del objects[pos]
28                 break
29         else:
30             pos = pos + 1
31
32     root = Node(None)
33     nodes = { None: root }
34     for obj_def in objects:
35         print obj_def.name
36         parent_node = nodes[obj_def.parent]
37         node = Node(obj_def.c_name, obj_def.implements)
38         parent_node.add_child(node)
39         nodes[node.name] = node
40
41     if parser.interfaces:
42         interfaces = Node('gobject.GInterface')
43         root.add_child(interfaces)
44         nodes[interfaces.name] = interfaces
45         for obj_def in parser.interfaces:
46             node = Node(obj_def.c_name)
47             interfaces.add_child(node)
48             nodes[node.name] = node
49
50     if parser.boxes:
51         boxed = Node('gobject.GBoxed')
52         root.add_child(boxed)
53         nodes[boxed.name] = boxed
54         for obj_def in parser.boxes:
55             node = Node(obj_def.c_name)
56             boxed.add_child(node)
57             nodes[node.name] = node
58
59     if parser.pointers:
60         pointers = Node('gobject.GPointer')
61         root.add_child(pointers)
62         nodes[pointers.name] = pointers
63         for obj_def in parser.pointers:
64             node = Node(obj_def.c_name)
65             pointers.add_child(node)
66             nodes[node.name] = node
67
68     return root
69
70 class DocWriter:
71     def __init__(self):
72         # parse the defs file
73         self.parser = defsparser.DefsParser(())
74         self.overrides = override.Overrides()
75         self.classmap = {}
76         self.docs = {}
77
78     def add_sourcedirs(self, source_dirs):
79         self.docs = docextract.extract(source_dirs, self.docs)
80     def add_tmpldirs(self, tmpl_dirs):
81         self.docs = docextract.extract_tmpl(tmpl_dirs, self.docs)
82
83     def add_docs(self, defs_file, overrides_file, module_name):
84         '''parse information about a given defs file'''
85         self.parser.filename = defs_file
86         self.parser.startParsing(defs_file)
87         if overrides_file:
88             self.overrides.handle_file(overrides_file)
89
90         for obj in self.parser.objects:
91             if not self.classmap.has_key(obj.c_name):
92                 self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
93         for obj in self.parser.interfaces:
94             if not self.classmap.has_key(obj.c_name):
95                 self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
96         for obj in self.parser.boxes:
97             if not self.classmap.has_key(obj.c_name):
98                 self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
99         for obj in self.parser.pointers:
100             if not self.classmap.has_key(obj.c_name):
101                 self.classmap[obj.c_name] = '%s.%s' % (module_name, obj.name)
102
103     def pyname(self, name):
104         return self.classmap.get(name, name)
105
106     def __compare(self, obja, objb):
107         return cmp(self.pyname(obja.c_name), self.pyname(objb.c_name))
108     def output_docs(self, output_prefix):
109         files = []
110
111         # class hierarchy
112         hierarchy = build_object_tree(self.parser)
113         filename = self.create_filename('hierarchy', output_prefix)
114         fp = open(filename, 'w')
115         self.write_full_hierarchy(hierarchy, fp)
116         fp.close()
117
118         obj_defs = self.parser.objects + self.parser.interfaces + \
119                    self.parser.boxes + self.parser.pointers
120         obj_defs.sort(self.__compare)
121         for obj_def in obj_defs:
122             filename = self.create_filename(obj_def.c_name, output_prefix)
123             fp = open(filename, 'w')
124             if isinstance(obj_def, definitions.ObjectDef):
125                 self.output_object_docs(obj_def, fp)
126             elif isinstance(obj_def, definitions.InterfaceDef):
127                 self.output_interface_docs(obj_def, fp)
128             elif isinstance(obj_def, definitions.BoxedDef):
129                 self.output_boxed_docs(obj_def, fp)
130             elif isinstance(obj_def, definitions.PointerDef):
131                 self.output_boxed_docs(obj_def, fp)
132             fp.close()
133             files.append((os.path.basename(filename), obj_def))
134
135         if files:
136             filename = self.create_toc_filename(output_prefix)
137             fp = open(filename, 'w')
138             self.output_toc(files, fp)
139             fp.close()
140
141     def output_object_docs(self, obj_def, fp=sys.stdout):
142         self.write_class_header(obj_def.c_name, fp)
143
144         self.write_heading('Synopsis', fp)
145         self.write_synopsis(obj_def, fp)
146         self.close_section(fp)
147
148         # construct the inheritence hierarchy ...
149         ancestry = [ (obj_def.c_name, obj_def.implements) ]
150         try:
151             parent = obj_def.parent
152             while parent != None:
153                 if parent == 'GObject':
154                     ancestry.append(('GObject', []))
155                     parent = None
156                 else:
157                     parent_def = self.parser.find_object(parent)
158                     ancestry.append((parent_def.c_name, parent_def.implements))
159                     parent = parent_def.parent
160         except ValueError:
161             pass
162         ancestry.reverse()
163         self.write_heading('Ancestry', fp)
164         self.write_hierarchy(obj_def.c_name, ancestry, fp)
165         self.close_section(fp)
166
167         constructor = self.parser.find_constructor(obj_def, self.overrides)
168         if constructor:
169             self.write_heading('Constructor', fp)
170             self.write_constructor(constructor,
171                                    self.docs.get(constructor.c_name, None),
172                                    fp)
173             self.close_section(fp)
174
175         methods = self.parser.find_methods(obj_def)
176         methods = filter(lambda meth, self=self:
177                          not self.overrides.is_ignored(meth.c_name), methods)
178         if methods:
179             self.write_heading('Methods', fp)
180             for method in methods:
181                 self.write_method(method, self.docs.get(method.c_name, None), fp)
182             self.close_section(fp)
183
184         self.write_class_footer(obj_def.c_name, fp)
185
186     def output_interface_docs(self, int_def, fp=sys.stdout):
187         self.write_class_header(int_def.c_name, fp)
188
189         self.write_heading('Synopsis', fp)
190         self.write_synopsis(int_def, fp)
191         self.close_section(fp)
192
193         methods = self.parser.find_methods(int_def)
194         methods = filter(lambda meth, self=self:
195                          not self.overrides.is_ignored(meth.c_name), methods)
196         if methods:
197             self.write_heading('Methods', fp)
198             for method in methods:
199                 self.write_method(method, self.docs.get(method.c_name, None), fp)
200             self.close_section(fp)
201
202         self.write_class_footer(int_def.c_name, fp)
203
204     def output_boxed_docs(self, box_def, fp=sys.stdout):
205         self.write_class_header(box_def.c_name, fp)
206
207         self.write_heading('Synopsis', fp)
208         self.write_synopsis(box_def, fp)
209         self.close_section(fp)
210
211         constructor = self.parser.find_constructor(box_def, self.overrides)
212         if constructor:
213             self.write_heading('Constructor', fp)
214             self.write_constructor(constructor,
215                                    self.docs.get(constructor.c_name, None),
216                                    fp)
217             self.close_section(fp)
218
219         methods = self.parser.find_methods(box_def)
220         methods = filter(lambda meth, self=self:
221                          not self.overrides.is_ignored(meth.c_name), methods)
222         if methods:
223             self.write_heading('Methods', fp)
224             for method in methods:
225                 self.write_method(method, self.docs.get(method.c_name, None), fp)
226             self.close_section(fp)
227
228         self.write_class_footer(box_def.c_name, fp)
229
230     def output_toc(self, files, fp=sys.stdout):
231         fp.write('TOC\n\n')
232         for filename, obj_def in files:
233             fp.write(obj_def.c_name + ' - ' + filename + '\n')
234
235     # override the following to create a more complex output format
236     def create_filename(self, obj_name, output_prefix):
237         '''Create output filename for this particular object'''
238         return output_prefix + '-' + string.lower(obj_name) + '.txt'
239     def create_toc_filename(self, output_prefix):
240         return self.create_filename(self, 'docs', output_prefix)
241
242     def write_full_hierarchy(self, hierarchy, fp):
243         def handle_node(node, fp, indent=''):
244             for child in node.subclasses:
245                 fp.write(indent + node.name)
246                 if node.interfaces:
247                     fp.write(' (implements ')
248                     fp.write(string.join(node.interfaces, ', '))
249                     fp.write(')\n')
250                 else:
251                     fp.write('\n')
252                 handle_node(child, fp, indent + '  ')
253         handle_node(hierarchy, fp)
254
255     # these need to handle default args ...
256     def create_constructor_prototype(self, func_def):
257         return func_def.is_constructor_of + '(' + \
258                string.join(map(lambda x: x[1], func_def.params), ', ') + \
259                ')'
260     def create_function_prototype(self, func_def):
261         return func_def.name + '(' + \
262                string.join(map(lambda x: x[1], func_def.params), ', ') + \
263                ')'
264     def create_method_prototype(self, meth_def):
265         return meth_def.of_object + '.' + \
266                meth_def.name + '(' + \
267                string.join(map(lambda x: x[1], meth_def.params), ', ') + \
268                ')'
269
270     def write_class_header(self, obj_name, fp):
271         fp.write('Class %s\n' % obj_name)
272         fp.write('======%s\n\n' % ('=' * len(obj_name)))
273     def write_class_footer(self, obj_name, fp):
274         pass
275     def write_heading(self, text, fp):
276         fp.write('\n' + text + '\n' + ('-' * len(text)) + '\n')
277     def close_section(self, fp):
278         pass
279     def write_synopsis(self, obj_def, fp):
280         fp.write('class %s' % obj_def.c_name)
281         if isinstance(obj_def, definitions.ObjectDef):
282             bases = []
283             if obj_def.parent: bases.append(obj_def.parent)
284             bases = bases = obj_def.implements
285             if bases:
286                 fp.write('(%s)' % string.join(bases, ', '))
287         fp.write(':\n')
288
289         constructor = self.parser.find_constructor(obj_def, self.overrides)
290         if constructor:
291             prototype = self.create_constructor_prototype(constructor)
292             fp.write('    def %s\n' % prototype)
293         methods = self.parser.find_methods(obj_def)
294         methods = filter(lambda meth, self=self:
295                          not self.overrides.is_ignored(meth.c_name), methods)
296         for meth in methods:
297             prototype = self.create_method_prototype(meth)
298             fp.write('    def %s\n' % prototype)
299
300     def write_hierarchy(self, obj_name, ancestry, fp):
301         indent = ''
302         for name, interfaces in ancestry:
303             fp.write(indent + '+-- ' + name)
304             if interfaces:
305                 fp.write(' (implements ')
306                 fp.write(string.join(interfaces, ', '))
307                 fp.write(')\n')
308             else:
309                 fp.write('\n')
310             indent = indent + '  '
311         fp.write('\n')
312     def write_constructor(self, func_def, func_doc, fp):
313         prototype = self.create_constructor_prototype(func_def)
314         fp.write(prototype + '\n\n')
315         for type, name, dflt, null in func_def.params:
316             if func_doc:
317                 descr = func_doc.get_param_description(name)
318             else:
319                 descr = 'a ' + type
320             fp.write('  ' + name + ': ' + descr + '\n')
321         if func_def.ret and func_def.ret != 'none':
322             if func_doc and func_doc.ret:
323                 descr = func_doc.ret
324             else:
325                 descr = 'a ' + func_def.ret
326             fp.write('  Returns: ' + descr + '\n')
327         if func_doc and func_doc.description:
328             fp.write(func_doc.description)
329         fp.write('\n\n\n')
330     def write_method(self, meth_def, func_doc, fp):
331         prototype = self.create_method_prototype(meth_def)
332         fp.write(prototype + '\n\n')
333         for type, name, dflt, null in meth_def.params:
334             if func_doc:
335                 descr = func_doc.get_param_description(name)
336             else:
337                 descr = 'a ' + type
338             fp.write('  ' + name + ': ' + descr + '\n')
339         if meth_def.ret and meth_def.ret != 'none':
340             if func_doc and func_doc.ret:
341                 descr = func_doc.ret
342             else:
343                 descr = 'a ' + meth_def.ret
344             fp.write('  Returns: ' + descr + '\n')
345         if func_doc and func_doc.description:
346             fp.write('\n')
347             fp.write(func_doc.description)
348         fp.write('\n\n')
349
350 class DocbookDocWriter(DocWriter):
351     def __init__(self, use_xml=0):
352         DocWriter.__init__(self)
353         self.use_xml = use_xml
354
355     def create_filename(self, obj_name, output_prefix):
356         '''Create output filename for this particular object'''
357         stem = output_prefix + '-' + string.lower(obj_name)
358         if self.use_xml:
359             return stem + '.xml'
360         else:
361             return stem + '.sgml'
362     def create_toc_filename(self, output_prefix):
363         if self.use_xml:
364             return self.create_filename('classes', output_prefix)
365         else:
366             return self.create_filename('docs', output_prefix)
367
368     # make string -> reference translation func
369     __transtable = [ '-' ] * 256
370     for digit in '0123456789':
371         __transtable[ord(digit)] = digit
372     for letter in 'abcdefghijklmnopqrstuvwxyz':
373         __transtable[ord(letter)] = letter
374         __transtable[ord(string.upper(letter))] = letter
375     __transtable = string.join(__transtable, '')
376
377     def make_class_ref(self, obj_name):
378         return 'class-' + string.translate(obj_name, self.__transtable)
379     def make_method_ref(self, meth_def):
380         return 'method-' + string.translate(meth_def.of_object,
381                                             self.__transtable) + \
382             '--' + string.translate(meth_def.name, self.__transtable)
383
384     __function_pat = re.compile(r'(\w+)\s*\(\)')
385     def __format_function(self, match):
386         info = self.parser.c_name.get(match.group(1), None)
387         if info:
388             if isinstance(info, defsparser.FunctionDef):
389                 if info.is_constructor_of is not None:
390                     # should have a link here
391                     return '<function>%s()</function>' % \
392                            self.pyname(info.is_constructor_of)
393                 else:
394                     return '<function>' + info.name + '()</function>'
395             if isinstance(info, defsparser.MethodDef):
396                 return '<link linkend="' + self.make_method_ref(info) + \
397                        '"><function>' + self.pyname(info.of_object) + '.' + \
398                        info.name + '()</function></link>'
399         # fall through through
400         return '<function>' + match.group(1) + '()</function>'
401     __parameter_pat = re.compile(r'\@(\w+)')
402     def __format_param(self, match):
403         return '<parameter>' + match.group(1) + '</parameter>'
404     __constant_pat = re.compile(r'\%(-?\w+)')
405     def __format_const(self, match):
406         return '<literal>' + match.group(1) + '</literal>'
407     __symbol_pat = re.compile(r'#([\w-]+)')
408     def __format_symbol(self, match):
409         info = self.parser.c_name.get(match.group(1), None)
410         if info:
411             if isinstance(info, defsparser.FunctionDef):
412                 if info.is_constructor_of is not None:
413                     # should have a link here
414                     return '<methodname>' + self.pyname(info.is_constructor_of) + \
415                            '</methodname>'
416                 else:
417                     return '<function>' + info.name + '</function>'
418             if isinstance(info, defsparser.MethodDef):
419                 return '<link linkend="' + self.make_method_ref(info) + \
420                        '"><methodname>' + self.pyname(info.of_object) + '.' + \
421                        info.name + '</methodname></link>'
422             if isinstance(info, defsparser.ObjectDef) or \
423                    isinstance(info, defsparser.InterfaceDef) or \
424                    isinstance(info, defsparser.BoxedDef) or \
425                    isinstance(info, defsparser.PointerDef):
426                 return '<link linkend="' + self.make_class_ref(info.c_name) + \
427                        '"><classname>' + self.pyname(info.c_name) + \
428                        '</classname></link>'
429         # fall through through
430         return '<literal>' + match.group(1) + '</literal>'
431
432     def reformat_text(self, text, singleline=0):
433         # replace special strings ...
434         text = self.__function_pat.sub(self.__format_function, text)
435         text = self.__parameter_pat.sub(self.__format_param, text)
436         text = self.__constant_pat.sub(self.__format_const, text)
437         text = self.__symbol_pat.sub(self.__format_symbol, text)
438
439         # don't bother with <para> expansion for single line text.
440         if singleline: return text
441
442         lines = string.split(string.strip(text), '\n')
443         for index in range(len(lines)):
444             if string.strip(lines[index]) == '':
445                 lines[index] = '</para>\n<para>'
446                 continue
447         lines.insert(0, '<para>')
448         lines.append('</para>')
449         return string.join(lines, '\n')
450
451     # write out hierarchy
452     def write_full_hierarchy(self, hierarchy, fp):
453         def handle_node(node, fp, indent=''):
454             if node.name:
455                 fp.write('%s<link linkend="%s">%s</link>' %
456                          (indent, self.make_class_ref(node.name),
457                           self.pyname(node.name)))
458                 if node.interfaces:
459                     fp.write(' (implements ')
460                     for i in range(len(node.interfaces)):
461                         fp.write('<link linkend="%s">%s</link>' %
462                                  (self.make_class_ref(node.interfaces[i]),
463                                   self.pyname(node.interfaces[i])))
464                         if i != len(node.interfaces) - 1:
465                             fp.write(', ')
466                     fp.write(')\n')
467                 else:
468                     fp.write('\n')
469
470                 indent = indent + '  '
471             node.subclasses.sort(lambda a,b:
472                                  cmp(self.pyname(a.name), self.pyname(b.name)))
473             for child in node.subclasses:
474                 handle_node(child, fp, indent)
475         if self.use_xml:
476             fp.write('<?xml version="1.0" standalone="no"?>\n')
477             fp.write('<!DOCTYPE synopsis PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
478             fp.write('    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
479         fp.write('<synopsis>')
480         handle_node(hierarchy, fp)
481         fp.write('</synopsis>\n')
482
483     # these need to handle default args ...
484     def create_constructor_prototype(self, func_def):
485         sgml = [ '<constructorsynopsis language="python">\n']
486         sgml.append('    <methodname>__init__</methodname>\n')
487         for type, name, dflt, null in func_def.params:
488             sgml.append('    <methodparam><parameter>')
489             sgml.append(name)
490             sgml.append('</parameter>')
491             if dflt:
492                 sgml.append('<initializer>')
493                 sgml.append(dflt)
494                 sgml.append('</initializer>')
495             sgml.append('</methodparam>\n')
496         if not func_def.params:
497             sgml.append('    <methodparam></methodparam>')
498         sgml.append('  </constructorsynopsis>')
499         return string.join(sgml, '')
500     def create_function_prototype(self, func_def):
501         sgml = [ '<funcsynopsis language="python">\n    <funcprototype>\n']
502         sgml.append('      <funcdef><function>')
503         sgml.append(func_def.name)
504         sgml.append('</function></funcdef>\n')
505         for type, name, dflt, null in func_def.params:
506             sgml.append('      <paramdef><parameter>')
507             sgml.append(name)
508             sgml.append('</parameter>')
509             if dflt:
510                 sgml.append('<initializer>')
511                 sgml.append(dflt)
512                 sgml.append('</initializer>')
513             sgml.append('</paramdef>\n')
514         if not func_def.params:
515             sgml.append('      <paramdef></paramdef')
516         sgml.append('    </funcprototype>\n  </funcsynopsis>')
517         return string.join(sgml, '')
518     def create_method_prototype(self, meth_def, addlink=0):
519         sgml = [ '<methodsynopsis language="python">\n']
520         sgml.append('    <methodname>')
521         if addlink:
522             sgml.append('<link linkend="%s">' % self.make_method_ref(meth_def))
523         sgml.append(self.pyname(meth_def.name))
524         if addlink:
525             sgml.append('</link>')
526         sgml.append('</methodname>\n')
527         for type, name, dflt, null in meth_def.params:
528             sgml.append('    <methodparam><parameter>')
529             sgml.append(name)
530             sgml.append('</parameter>')
531             if dflt:
532                 sgml.append('<initializer>')
533                 sgml.append(dflt)
534                 sgml.append('</initializer>')
535             sgml.append('</methodparam>\n')
536         if not meth_def.params:
537             sgml.append('    <methodparam></methodparam>')
538         sgml.append('  </methodsynopsis>')
539         return string.join(sgml, '')
540
541     def write_class_header(self, obj_name, fp):
542         if self.use_xml:
543             fp.write('<?xml version="1.0" standalone="no"?>\n')
544             fp.write('<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
545             fp.write('    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
546         fp.write('<refentry id="' + self.make_class_ref(obj_name) + '">\n')
547         fp.write('  <refmeta>\n')
548         fp.write('    <refentrytitle>%s</refentrytitle>\n'
549                  % self.pyname(obj_name))
550         fp.write('    <manvolnum>3</manvolnum>\n')
551         fp.write('    <refmiscinfo>PyGTK Docs</refmiscinfo>\n')
552         fp.write('  </refmeta>\n\n')
553         fp.write('  <refnamediv>\n')
554         fp.write('    <refname>%s</refname><refpurpose></refpurpose>\n'
555                  % self.pyname(obj_name))
556         fp.write('  </refnamediv>\n\n')
557     def write_class_footer(self, obj_name, fp):
558         fp.write('</refentry>\n')
559     def write_heading(self, text, fp):
560         fp.write('  <refsect1>\n')
561         fp.write('    <title>' + text + '</title>\n\n')
562     def close_section(self, fp):
563         fp.write('  </refsect1>\n')
564
565     def write_synopsis(self, obj_def, fp):
566         fp.write('<classsynopsis language="python">\n')
567         fp.write('  <ooclass><classname>%s</classname></ooclass>\n'
568                  % self.pyname(obj_def.c_name))
569         if isinstance(obj_def, definitions.ObjectDef):
570             if obj_def.parent:
571                 fp.write('  <ooclass><classname><link linkend="%s">%s'
572                          '</link></classname></ooclass>\n'
573                          % (self.make_class_ref(obj_def.parent),
574                             self.pyname(obj_def.parent)))
575             for base in obj_def.implements:
576                 fp.write('  <ooclass><classname><link linkend="%s">%s'
577                          '</link></classname></ooclass>\n'
578                          % (self.make_class_ref(base), self.pyname(base)))
579         elif isinstance(obj_def, definitions.InterfaceDef):
580             fp.write('  <ooclass><classname>gobject.GInterface'
581                      '</classname></ooclass>\n')
582         elif isinstance(obj_def, definitions.BoxedDef):
583             fp.write('  <ooclass><classname>gobject.GBoxed'
584                      '</classname></ooclass>\n')
585         elif isinstance(obj_def, definitions.PointerDef):
586             fp.write('  <ooclass><classname>gobject.GPointer'
587                      '</classname></ooclass>\n')
588
589         constructor = self.parser.find_constructor(obj_def, self.overrides)
590         if constructor:
591             fp.write('%s\n' % self.create_constructor_prototype(constructor))
592         methods = self.parser.find_methods(obj_def)
593         methods = filter(lambda meth, self=self:
594                          not self.overrides.is_ignored(meth.c_name), methods)
595         for meth in methods:
596             fp.write('%s\n' % self.create_method_prototype(meth, addlink=1))
597         fp.write('</classsynopsis>\n\n')
598
599     def write_hierarchy(self, obj_name, ancestry, fp):
600         fp.write('<synopsis>')
601         indent = ''
602         for name, interfaces in ancestry:
603             fp.write(indent + '+-- <link linkend="' +
604                      self.make_class_ref(name) + '">'+ self.pyname(name) + '</link>')
605             if interfaces:
606                 fp.write(' (implements ')
607                 for i in range(len(interfaces)):
608                     fp.write('<link linkend="%s">%s</link>' %
609                              (self.make_class_ref(interfaces[i]),
610                               self.pyname(interfaces[i])))
611                     if i != len(interfaces) - 1:
612                         fp.write(', ')
613                 fp.write(')\n')
614             else:
615                 fp.write('\n')
616             indent = indent + '  '
617         fp.write('</synopsis>\n\n')
618
619     def write_params(self, params, ret, func_doc, fp):
620         if not params and (not ret or ret == 'none'):
621             return
622         fp.write('  <variablelist>\n')
623         for type, name, dflt, null in params:
624             if func_doc:
625                 descr = string.strip(func_doc.get_param_description(name))
626             else:
627                 descr = 'a ' + type
628             fp.write('    <varlistentry>\n')
629             fp.write('      <term><parameter>%s</parameter>&nbsp;:</term>\n' % name)
630             fp.write('      <listitem><simpara>%s</simpara></listitem>\n' %
631                      self.reformat_text(descr, singleline=1))
632             fp.write('    </varlistentry>\n')
633         if ret and ret != 'none':
634             if func_doc and func_doc.ret:
635                 descr = string.strip(func_doc.ret)
636             else:
637                 descr = 'a ' + ret
638             fp.write('    <varlistentry>\n')
639             fp.write('      <term><emphasis>Returns</emphasis>&nbsp;:</term>\n')
640             fp.write('      <listitem><simpara>%s</simpara></listitem>\n' %
641                      self.reformat_text(descr, singleline=1))
642             fp.write('    </varlistentry>\n')
643         fp.write('  </variablelist>\n')
644
645     def write_constructor(self, func_def, func_doc, fp):
646         prototype = self.create_constructor_prototype(func_def)
647         fp.write('<programlisting>%s</programlisting>\n' % prototype)
648         self.write_params(func_def.params, func_def.ret, func_doc, fp)
649
650         if func_doc and func_doc.description:
651             fp.write(self.reformat_text(func_doc.description))
652         fp.write('\n\n\n')
653
654     def write_method(self, meth_def, func_doc, fp):
655         fp.write('  <refsect2 id="' + self.make_method_ref(meth_def) + '">\n')
656         fp.write('    <title>' + self.pyname(meth_def.of_object) + '.' +
657                  meth_def.name + '</title>\n\n')
658         prototype = self.create_method_prototype(meth_def)
659         fp.write('<programlisting>%s</programlisting>\n' % prototype)
660         self.write_params(meth_def.params, meth_def.ret, func_doc, fp)
661         if func_doc and func_doc.description:
662             fp.write(self.reformat_text(func_doc.description))
663         fp.write('  </refsect2>\n\n\n')
664
665     def output_toc(self, files, fp=sys.stdout):
666         if self.use_xml:
667             fp.write('<?xml version="1.0" standalone="no"?>\n')
668             fp.write('<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"\n')
669             fp.write('    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n')
670             #for filename, obj_def in files:
671             #    fp.write('  <!ENTITY ' + string.translate(obj_def.c_name,
672             #                                              self.__transtable) +
673             #             ' SYSTEM "' + filename + '" >\n')
674             #fp.write(']>\n\n')
675
676             #fp.write('<reference id="class-reference">\n')
677             #fp.write('  <title>Class Documentation</title>\n')
678             #for filename, obj_def in files:
679             #    fp.write('&' + string.translate(obj_def.c_name,
680             #                                    self.__transtable) + ';\n')
681             #fp.write('</reference>\n')
682
683             fp.write('<reference id="class-reference" xmlns:xi="http://www.w3.org/2001/XInclude">\n')
684             fp.write('  <title>Class Reference</title>\n')
685             for filename, obj_def in files:
686                 fp.write('  <xi:include href="%s"/>\n' % filename)
687             fp.write('</reference>\n')
688         else:
689             fp.write('<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.1.2//EN" [\n')
690             for filename, obj_def in files:
691                 fp.write('  <!ENTITY ' + string.translate(obj_def.c_name,
692                                                           self.__transtable) +
693                          ' SYSTEM "' + filename + '" >\n')
694             fp.write(']>\n\n')
695
696             fp.write('<book id="index">\n\n')
697             fp.write('  <bookinfo>\n')
698             fp.write('    <title>PyGTK Docs</title>\n')
699             fp.write('    <authorgroup>\n')
700             fp.write('      <author>\n')
701             fp.write('        <firstname>James</firstname>\n')
702             fp.write('        <surname>Henstridge</surname>\n')
703             fp.write('      </author>\n')
704             fp.write('    </authorgroup>\n')
705             fp.write('  </bookinfo>\n\n')
706
707             fp.write('  <chapter id="class-hierarchy">\n')
708             fp.write('    <title>Class Hierarchy</title>\n')
709             fp.write('    <para>Not done yet</para>\n')
710             fp.write('  </chapter>\n\n')
711
712             fp.write('  <reference id="class-reference">\n')
713             fp.write('    <title>Class Documentation</title>\n')
714             for filename, obj_def in files:
715                 fp.write('&' + string.translate(obj_def.c_name,
716                                                 self.__transtable) + ';\n')
717
718             fp.write('  </reference>\n')
719             fp.write('</book>\n')
720
721 if __name__ == '__main__':
722     try:
723         opts, args = getopt.getopt(sys.argv[1:], "d:s:o:",
724                                    ["defs-file=", "override=", "source-dir=",
725                                     "output-prefix="])
726     except getopt.error, e:
727         sys.stderr.write('docgen.py: %s\n' % e)
728         sys.stderr.write(
729             'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n')
730         sys.exit(1)
731     defs_file = None
732     overrides_file = None
733     source_dirs = []
734     output_prefix = 'docs'
735     for opt, arg in opts:
736         if opt in ('-d', '--defs-file'):
737             defs_file = arg
738         if opt in ('--override',):
739             overrides_file = arg
740         elif opt in ('-s', '--source-dir'):
741             source_dirs.append(arg)
742         elif opt in ('-o', '--output-prefix'):
743             output_prefix = arg
744     if len(args) != 0 or not defs_file:
745         sys.stderr.write(
746             'usage: docgen.py -d file.defs [-s /src/dir] [-o output-prefix]\n')
747         sys.exit(1)
748
749     d = DocbookDocWriter()
750     d.add_sourcedirs(source_dirs)
751     d.add_docs(defs_file, overrides_file, 'gtk')
752     d.output_docs(output_prefix)