]> rtime.felk.cvut.cz Git - opencv.git/blob - opencv/doc/latex2sphinx/latex.py
eb59fb2578b109b67d1d4c7b7f98f54b9e38211f
[opencv.git] / opencv / doc / latex2sphinx / latex.py
1 import sys
2 from latexparser import latexparser, TexCmd
3 import distutils.dep_util
4 import os
5 import cPickle as pickle
6 import pyparsing as pp
7 import StringIO
8 from qfile import QOpen
9 from string import Template
10
11 # useful things for pyparsing
12 def returnList(x):
13     def listify(s, loc, toks):
14         return [toks]
15     x.setParseAction(listify)
16     return x
17 def returnTuple(x):
18     def listify(s, loc, toks):
19         return [tuple(toks)]
20     x.setParseAction(listify)
21     return x
22 def CommaList(word):
23     return returnList(pp.Optional(word + pp.ZeroOrMore(pp.Suppress(',') + word)))
24 def sl(s):
25     return pp.Suppress(pp.Literal(s))
26
27 import pythonapi
28
29 python_api = pythonapi.reader("../../interfaces/python/api")
30
31
32 class SphinxWriter:
33     def __init__(self, filename, language):
34         assert language in ['py', 'c', 'cpp']
35         self.language = language
36
37         self.f_index = QOpen(os.path.join(self.language, filename), 'wt')
38         self.f = self.f_index
39         self.f_chapter = None
40         self.f_section = None
41         self.indent = 0
42         self.state = None
43         self.envstack = []
44         self.tags = {}
45         self.errors = open('errors.%s' % language, 'wt')
46         self.unhandled_commands = set()
47         self.freshline = True
48         self.function_props = {}
49         self.covered = set()        # covered functions, used for error report
50         self.description = ""
51
52     def write(self, s):
53         self.freshline = len(s) > 0 and (s[-1] == '\n')
54         self.f.write(s.replace('\n', '\n' + self.indent * "    "))
55
56     def appendspace(self):
57         """ append a space to the output - if we're not at the start of a line """
58         if not self.freshline:
59             self.write(' ')
60
61     def doplain(self, s):
62         if (len(s) > 1) and (s[0] == '$' and s[-1] == '$') and self.state != 'math':
63             s = ":math:`%s`" % s[1:-1].strip()
64         elif self.state != 'math':
65             s.replace('\\_', '_')
66         if len(s) > 0 and s[-1] == '\n':
67             s = s[:-1]
68         if self.state == 'fpreamble':
69             self.description += s
70         else:
71             self.write(s)
72
73     def docmd(self, c):
74         if self.state == 'math':
75             if c.cmd != ']':
76                 self.default_cmd(c)
77             else:
78                 self.indent -= 1
79                 self.state = None
80                 self.write('\n\n')
81         else:
82             if c.cmd == '\n':
83                 self.write('\\\n')
84             else:
85                 if c.cmd == '[':
86                     meth = self.cmd_gomath
87                 else:
88                     cname = "cmd_" + c.cmd
89                     meth = getattr(self, cname, self.unrecognized_cmd)
90                 meth(c)
91
92     def cmd_gomath(self, c):
93         self.state = 'math'
94         print >>self, "\n\n.. math::"
95         self.indent += 1
96         print >>self
97
98     def cmd_chapter(self, c):
99         filename = str(c.params[0]).lower().replace(' ', '_').replace('/','_')
100         self.f_index.write("    %s\n" % filename)
101         self.f_chapter = QOpen(os.path.join(self.language, filename + '.rst'), 'wt')
102         self.f_section = None
103         self.f = self.f_chapter
104         self.indent = 0
105         title = str(c.params[0])
106         print >>self, '*' * len(title)
107         print >>self, title
108         print >>self, '*' * len(title)
109         print >>self
110         self.chapter_intoc = False
111
112     def cmd_section(self, c):
113         filename = str(c.params[0]).lower().replace(' ', '_').replace('/','_')
114         if not self.chapter_intoc:
115             self.chapter_intoc = True
116             print >>self.f_chapter
117             print >>self.f_chapter, '.. toctree::'
118             print >>self.f_chapter, '    :maxdepth: 2'
119             print >>self.f_chapter
120         self.f_chapter.write("    %s\n" % filename)
121         self.f_section = QOpen(os.path.join(self.language, filename + '.rst'), 'wt')
122         self.f = self.f_section
123         self.indent = 0
124         title = self.render(c.params[0].str)
125         print >>self, title
126         print >>self, '=' * len(title)
127         print >>self
128         print >>self, '.. highlight:: %s' % {'c': 'c', 'cpp': 'cpp', 'py': 'python'}[self.language]
129         print >>self
130
131     def cmd_subsection(self, c):
132         print >>self
133         print >>self, str(c.params[0])
134         print >>self, '-' * len(str(c.params[0]))
135         print >>self
136         self.function_props = {}
137
138     def cmd_includegraphics(self, c):
139         filename = os.path.join('..', '..', str(c.params[0]))
140         print >>self, "\n\n.. image:: %s\n\n" % filename
141
142     def cmd_cvCppCross(self, c):
143         self.write(":ref:`%s`" % str(c.params[0]))
144
145     def cmd_cvCPyCross(self, c):
146         self.write(":ref:`%s`" % str(c.params[0]))
147
148     def cmd_cross(self, c):
149         self.write(":ref:`%s`" % str(c.params[0]))
150
151     def cmd_cvCross(self, c):
152         self.write(":ref:`%s`" % str(c.params[0]))
153
154     def cmd_cvclass(self, c):
155         self.indent = 0
156         self.state = None
157         nm = self.render(list(c.params[0].str))
158         print >>self, "\n.. index:: %s\n" % nm
159         print >>self, ".. _%s:\n" % nm
160         print >>self, nm
161         print >>self, '-' * len(nm)
162         print >>self
163         if self.language == 'py':
164             print >>self, ".. class:: " + nm + "\n"
165         else:
166             print >>self, ".. ctype:: " + nm + "\n"
167         print >>self
168         self.addtag(nm, c)
169
170     def addtag(self, nm, c):
171         if nm == "":
172             self.report_error(c, "empty name")
173         self.tags[nm] = "%s\t%s\t%d" % (nm, os.path.join(os.getcwd(), c.filename), c.lineno)
174
175     def cmd_cvfunc(self, c):
176         self.cmd_cvCPyFunc(c)
177
178     def cmd_cvCPyFunc(self, c):
179         self.indent = 0
180         nm = self.render(c.params[0].str)
181         print >>self, "\n.. index:: %s\n" % nm
182         print >>self, ".. _%s:\n" % nm
183         print >>self, nm
184         print >>self, '-' * len(nm)
185         print >>self
186         self.state = 'fpreamble'
187         if self.description != "":
188             self.report_error(c, "overflow - preceding cvfunc (starting %s) not terminated?" % repr(self.description[:30]))
189         self.description = ""
190         self.addtag(nm, c)
191
192         self.function_props = {'name' : nm}
193         self.covered.add(nm)
194
195     def cmd_cvCppFunc(self, c):
196         self.indent = 0
197         nm = self.render(c.params[0].str)
198         print >>self, "\n.. index:: %s\n" % nm
199         print >>self, ".. _%s:\n" % nm
200         print >>self, nm
201         print >>self, '-' * len(nm)
202         print >>self
203         self.state = 'fpreamble'
204         if self.description != "":
205             self.report_error(c, "overflow - preceding cvfunc (starting %s) not terminated?" % repr(self.description[:30]))
206         self.description = ""
207         self.addtag(nm, c)
208
209         self.function_props = {'name' : nm}
210         self.covered.add(nm)
211
212     def cmd_cvdefC(self, c):
213         if self.language != 'c':
214             return
215         s = str(c.params[0]).replace('\\_', '_')
216         s = s.replace('\\par', '')
217         s = s.replace('\n', ' ')
218         s = s.replace(';', '')
219         self.indent = 0
220         for proto in s.split('\\newline'):
221             if proto.strip() != "":
222                 print >>self, "\n\n.. cfunction:: " + proto.strip() + "\n"
223         # print >>self, "=", repr(c.params[0].str)
224         print >>self, '    ' + self.description
225         self.description = ""
226         print >>self
227         self.state = None
228         self.function_props['defpy'] = s
229
230     def cmd_cvdefCpp(self, c):
231         if self.language != 'cpp':
232             return
233         s = str(c.params[0]).replace('\\_', '_')
234         s = s.replace('\\par', '')
235         s = s.replace('\n', ' ')
236         s = s.replace(';', '')
237         self.indent = 0
238         for proto in s.split('\\newline'):
239             if proto.strip() != "":
240                 print >>self, "\n\n.. cfunction:: " + proto.strip() + "\n"
241         # print >>self, "=", repr(c.params[0].str)
242         if self.description != "":
243             print >>self, '    ' + self.description
244         else:
245             self.report_error(c, 'empty description')
246         self.description = ""
247         print >>self
248         self.state = None
249         self.function_props['defpy'] = s
250
251     def cmd_cvdefPy(self, c):
252         if self.language != 'py':
253             return
254         s = str(c.params[0]).replace('\\_', '_')
255         self.indent = 0
256         print >>self, ".. function:: " + s + "\n"
257         # print >>self, "=", repr(c.params[0].str)
258         print >>self, '    ' + self.description
259         print >>self
260         self.description = ""
261         self.state = None
262         self.function_props['defpy'] = s
263
264         pp.ParserElement.setDefaultWhitespaceChars(" \n\t")
265
266         ident = pp.Word(pp.alphanums + "_.+-")
267         ident_or_tuple = ident | (sl('(') + CommaList(ident) + sl(')'))
268         initializer = ident_or_tuple
269         arg = returnList(ident + pp.Optional(sl('=') + initializer))
270
271         decl = ident + sl('(') + CommaList(arg) + sl(')') + sl("->") + ident_or_tuple + pp.StringEnd()
272
273         try:
274             l = decl.parseString(s)
275             if str(l[0]) != self.function_props['name']:
276                 self.report_error(c, 'Decl "%s" does not match function name "%s"' % (str(l[0]), self.function_props['name']))
277             self.function_props['signature'] = l
278             if l[0] in python_api:
279                 (ins, outs) = python_api[l[0]]
280                 ins = [a for a in ins if not 'O' in a.flags]
281                 if outs != None:
282                     outs = outs.split(',')
283                 if len(ins) != len(l[1]):
284                     self.report_error(c, "function %s documented arity %d, code arity %d" % (l[0], len(l[1]), len(ins)))
285                 if outs == None:
286                     if l[2] != 'None':
287                         self.report_error(c, "function %s documented None, but code has %s" % (l[0], l[2]))
288                 else:
289                     if isinstance(l[2], str):
290                         doc_outs = [l[2]]
291                     else:
292                         doc_outs = l[2]
293                     if len(outs) != len(doc_outs):
294                         self.report_error(c, "function %s output documented tuple %d, code %d" % (l[0], len(outs), len(doc_outs)))
295             else:
296                 # self.report_error(c, "function %s documented but not found in code" % l[0])
297                 pass
298         except pp.ParseException, pe:
299             self.report_error(c, str(pe))
300             print s
301             print pe
302
303     def report_error(self, c, msg):
304         print >>self.errors, "%s:%d: [%s] Error %s" % (c.filename, c.lineno, self.language, msg)
305
306     def cmd_begin(self, c):
307         if len(c.params) == 0:
308             self.report_error(c, "Malformed begin")
309             return
310         self.write('\n')
311         s = str(c.params[0])
312         self.envstack.append((s, (c.filename, c.lineno)))
313         if s == 'description':
314             if self.language == 'py' and 'name' in self.function_props and not 'defpy' in self.function_props:
315                 self.report_error(c, "No cvdefPy for function %s" % self.function_props['name'])
316             self.indent += 1
317         elif s == 'lstlisting':
318             # Set indent to zero while collecting code; so later write will not double-indent
319             self.saved_f = self.f
320             self.saved_indent = self.indent
321             self.f = StringIO.StringIO()
322             self.indent = 0
323         elif s in ['itemize', 'enumerate']:
324             self.indent += 1
325         elif s == 'tabular':
326             self.f = StringIO.StringIO()
327         else:
328             self.default_cmd(c)
329
330     def cmd_item(self, c):
331         if len(self.ee()) == 0:
332             self.report_error(c, "item without environment")
333             return
334         self.indent -= 1
335         markup = {'itemize' : '*', 'enumerate' : '#.', 'description' : '*'}[self.ee()[-1]]
336         if len(c.args) > 0:
337             markup += " " + self.render([c.args[0].str])
338         if len(c.params) > 0:
339             markup += " " + self.render(c.params[0].str)
340         self.write("\n\n" + markup)
341         self.indent += 1
342
343     def cmd_end(self, c):
344         if len(c.params) != 1:
345             self.report_error(c, "Malformed end")
346             return
347         if len(self.envstack) == 0:
348             self.report_error(c, "end with no env")
349             return
350         self.write('\n')
351         s = str(c.params[0])
352         if self.envstack == []:
353             print "Cannot pop at", (c.filename, c.lineno)
354         if self.envstack[-1][0] != s:
355             self.report_error(c, "end{%s} does not match current stack %s" % (s, repr(self.envstack)))
356         self.envstack.pop()
357         if s == 'description':
358             self.indent -= 1
359             if self.indent == 0:
360                 self.function_props['done'] = True
361         elif s in ['itemize', 'enumerate']:
362             self.indent -= 1
363         elif s == 'tabular':
364             tabletxt = self.f.getvalue()
365             self.f = self.f_section
366             self.f.write(self.handle_table(tabletxt))
367         elif s == 'lstlisting':
368             listing = self.f.getvalue()
369
370             self.f = self.saved_f
371             self.indent = self.saved_indent
372             print >>self
373             if (self.language == 'py') and ('>>>' in listing):
374                 print >>self, "\n.. doctest::\n"
375             else:
376                 print >>self, "\n::\n"
377             self.indent += 1
378             print >>self
379             self.write(listing)
380             self.indent -= 1
381             print >>self
382             print >>self
383             print >>self, ".."      # otherwise a following :param: gets treated as more listing
384         elif s == 'document':
385             pass
386         else:
387             self.default_cmd(c)
388         
389     def cmd_label(self, c):
390         pass
391
392     def cmd_lstinputlisting(self, c):
393         s = str(c.params[0])
394         print >>self.f, ".. include:: %s" % os.path.join('..', s)
395         print >>self.f, "    :literal:"
396         print >>self.f
397
398     # Conditionals
399     def cmd_cvC(self, c):
400         self.do_conditional(['c'], c)
401     def cmd_cvCpp(self, c):
402         self.do_conditional(['cpp'], c)
403     def cmd_cvPy(self, c):
404         self.do_conditional(['py'], c)
405     def cmd_cvCPy(self, c):
406         self.do_conditional(['c', 'py'], c)
407     def do_conditional(self, langs, c):
408         if self.language in langs:
409             self.doL(c.params[0].str, False)
410
411     def render(self, L):
412         """ return L rendered as a string """
413         save = self.f
414         self.f = StringIO.StringIO()
415         for x in L:
416             if isinstance(x, TexCmd):
417                 self.docmd(x)
418             else:
419                 self.doplain(x)
420         r = self.f.getvalue()
421         self.f = save
422         return r
423
424     def cmd_cvarg(self, c):
425         if len(c.params) != 2:
426             self.report_error(c, "Malformed cvarg")
427             return
428         is_func_arg = (self.ee() == ['description']) and (not 'done' in self.function_props)
429         e = self.ee()
430         if is_func_arg:
431             nm = self.render(c.params[0].str)
432             print >>self, '\n:param %s: ' % nm,
433             type = None         # Try to figure out the argument type
434             # For now, multiple args get a pass
435             if (self.language == 'py') and ('signature' in self.function_props) and (not ',' in nm):
436                 sig = self.function_props['signature']
437                 argnames = [a[0] for a in sig[1]]
438                 if isinstance(sig[2], str):
439                     resnames = [sig[2]]
440                 else:
441                     resnames = list(sig[2])
442                 if not nm in argnames + resnames:
443                     self.report_error(c, "Argument %s is not mentioned in signature (%s) (%s)" % (nm, ", ".join(argnames), ", ".join(resnames)))
444
445                 api = python_api.get(self.function_props['name'], None)
446                 if api:
447                     (ins, outs) = api
448                     adict = dict([(a.nm, a) for a in ins])
449                     arg = adict.get(nm, None)
450                     if arg:
451                         type = arg.ty
452                     else:
453                         self.report_error(c, 'cannot find arg %s in code' % nm)
454         elif len(e) > 0 and e[-1] == 'description':
455             print >>self, '\n* **%s** ' % self.render(c.params[0].str),
456         else:
457             self.report_error(c, "unexpected env (%s) for cvarg" % ",".join(e))
458         self.indent += 1
459         self.doL(c.params[1].str, False)
460         self.indent -= 1
461         print >>self
462         if is_func_arg and type:
463             type = type.replace('*', '')
464             translate = {
465                 "ints" : "sequence of int",
466                 "floats" : "sequence of int",
467                 "IplImages" : "sequence of :class:`IplImage`",
468                 "double" : "float",
469                 "int" : "int",
470                 "float" : "float",
471                 "char" : "str",
472                 "cvarrseq" : ":class:`CvArr` or :class:`CvSeq`",
473                 "CvPoint2D32fs" : "sequence of (float, float)",
474                 "pts_npts_contours" : "list of lists of (x,y) pairs",
475             }
476             print >>self, "\n:type %s: %s" % (nm, translate.get(type, ':class:`%s`' % type))
477
478     def cmd_genc(self, c): pass 
479     def cmd_genpy(self, c): pass 
480     def cmd_author(self, c): pass 
481     def cmd_date(self, c): pass
482     def cmd_def(self, c): pass
483     def cmd_documentclass(self, c): pass
484     def cmd_maketitle(self, c): pass
485     def cmd_newcommand(self, c): pass
486     def cmd_newline(self, c): pass
487     def cmd_setcounter(self, c): pass
488     def cmd_tableofcontents(self, c): pass
489     def cmd_targetlang(self, c): pass
490     def cmd_usepackage(self, c): pass
491     def cmd_title(self, c): pass
492     def cmd_par(self, c): pass
493     def cmd_hline(self, c):
494         print >>self, "\\hline"
495
496     def cmd_cite(self, c):
497         self.write("[%s]_" % str(c.params[0]))
498
499     def cmd_href(self, c):
500         if len(c.params) == 2:
501             self.write("`%s <%s>`_" % (str(c.params[1]), str(c.params[0])))
502         else:
503             self.report_error(c, "href should have two params")
504
505     def cmd_url(self, c):
506         self.write(str(c.params[0]))
507
508     def cmd_emph(self, c):
509         self.write("*" + self.render(c.params[0].str) + "*")
510
511     def cmd_textit(self, c):
512         self.write("*" + self.render(c.params[0].str) + "*")
513
514     def cmd_textbf(self, c):
515         self.write("**" + self.render(c.params[0].str) + "**")
516
517     def cmd_texttt(self, c):
518         self.write("``" + self.render(c.params[0].str) + "``")
519
520     def default_cmd(self, c):
521         if self.f == self.f_section:
522             self.write(repr(c))
523
524     def unrecognized_cmd(self, c):
525         if not self.f in [self.f_index, self.f_chapter]:
526             self.write(c.cmd)
527             self.unhandled_commands.add(c.cmd)
528
529     def doL(self, L, newlines = True):
530         for x in L:
531             pos0 = self.f.tell()
532             if isinstance(x, TexCmd):
533                 self.docmd(x)
534             else:
535                 if 'lstlisting' in self.ee() or not newlines:
536                     self.doplain(x)
537                 else:
538                     self.doplain(x.lstrip())
539             pos1 = self.f.tell()
540             if pos0 != pos1:
541                 if self.state in ['math'] or not newlines:
542                     self.appendspace()
543                 else:
544                     if not 'lstlisting' in self.ee():
545                         self.write('\n')
546
547     def handle_table(self, s):
548         oneline = s.replace('\n', ' ').strip()
549         rows = [r.strip() for r in oneline.split('\\hline')]
550         tab = []
551         for r in rows:
552             if r != "":
553                 cols = [c.strip() for c in r.split('&')]
554                 tab.append(cols)
555         widths = [max([len(r[i]) for r in tab]) for i in range(len(tab[0]))]
556
557         st = ""         # Sphinx table
558
559         if 0:
560             sep = "+" + "+".join(["-" * w for w in widths]) + "+"
561             st += sep + '\n'
562             for r in tab:
563                 st += "|" + "|".join([c.center(w) for (c, w) in zip(r, widths)]) + "|" + '\n'
564                 st += sep + '\n'
565
566         st = '.. table::\n\n'
567         sep = "  ".join(["=" * w for w in widths])
568         st += '    ' + sep + '\n'
569         for y,r in enumerate(tab):
570             st += '    ' + "  ".join([c.ljust(w) for (c, w) in zip(r, widths)]) + '\n'
571             if y == 0:
572                 st += '    ' + sep + '\n'
573         st += '    ' + sep + '\n'
574         return st
575
576     def ee(self):
577         """ Return tags of the envstack.  envstack[0] is 'document', so skip it """
578         return [n for (n,_) in self.envstack[1:]]
579
580     def get_tags(self):
581         return self.tags
582
583     def close(self):
584
585         if self.envstack != []:
586             print >>self.errors, "Error envstack not empty at end of doc: " + repr(self.envstack)
587         print >>self.errors, "unrecognized commands:"
588         print >>self.errors, "\n    ".join(sorted(self.unhandled_commands))
589         print >>self.errors
590         print >>self.errors, "The following functions are undocumented"
591         for f in sorted(set(python_api) - self.covered):
592             print >>self.errors, '    ', f
593
594         print >>self.f_index, "    bibliography"
595         print >>self.f_index, """
596
597 Indices and tables
598 ==================
599
600 * :ref:`genindex`
601 * :ref:`search`
602 """
603
604 # Quick and dirty bibtex parser
605
606 def parseBib(filename, language):
607     pp.ParserElement.setDefaultWhitespaceChars(" \n\t")
608     entry = returnList(pp.Word('@', pp.alphanums) + sl('{') +
609         pp.Word(pp.alphanums + "_") + sl(',') +
610         CommaList(returnTuple(pp.Word(pp.alphanums) + sl('=') + pp.QuotedString('{', endQuoteChar = '}'))) +
611         pp.Suppress(pp.Optional(',')) +
612         sl('}'))
613     r = (pp.ZeroOrMore(entry) | pp.Suppress('#' + pp.ZeroOrMore(pp.CharsNotIn('\n'))) + pp.StringEnd()).parseFile(filename)
614
615     bibliography = QOpen(os.path.join(language, "bibliography.rst"), 'wt')
616     print >>bibliography, "Bibliography"
617     print >>bibliography, "============"
618     print >>bibliography
619
620     for _,e in sorted([(str(x[1]), x) for x in r]):
621         (etype, tag, attrs) = str(e[0][1:]), str(e[1]), dict([(str(a), str(b)) for (a,b) in e[2]])
622         
623         representations = {
624             'article' :         '$author, "$title". $journal $volume $number, pp $pages ($year)',
625             'inproceedings' :   '$author "$title", $booktitle, $year',
626             'misc' :            '$author "$title", $year',
627             'techreport' :      '$author "$title", $edition, $edition ($year)',
628         }
629         if etype in representations:
630             if 0:
631                 print >>bibliography, tag
632                 print >>bibliography, "^" * len(tag)
633                 print >>bibliography
634
635             print >>bibliography, ".. [%s] %s" % (tag, Template(representations[etype]).safe_substitute(attrs))
636             print >>bibliography
637     bibliography.close()
638
639 if 1:
640     fulldoc = latexparser(sys.argv[1])
641
642     raw = open('raw.full', 'w')
643     for x in fulldoc:
644         print >>raw, repr(x)
645     raw.close()
646
647     # Filter on target language
648     def preprocess_conditionals(fd, conditionals):
649         r = []
650         ifstack = []
651         for x in fd:
652             if isinstance(x, TexCmd):
653                 ll = x.cmd.rstrip()
654                 loc = (x.filename, x.lineno)
655                 if ll.startswith("if"):
656                     # print " " * len(ifstack), '{', loc
657                     ifstack.append((conditionals.get(ll[2:], False), loc))
658                 elif ll.startswith("else"):
659                     ifstack[-1] = (not ifstack[-1][0], ifstack[-1][1])
660                 elif ll.startswith("fi"):
661                     ifstack.pop()
662                     # print " " * len(ifstack), '}', loc
663                 elif not False in [p for (p,_) in ifstack]:
664                     r.append(x)
665             else:
666                 if not False in [p for (p,_) in ifstack]:
667                     r.append(x)
668         if ifstack != []:
669             print "unterminated if", ifstack
670             sys.exit(0)
671         return r
672
673     tags = {}
674     for language in ['c', 'cpp', 'py']:
675         doc = preprocess_conditionals(fulldoc, {
676                                               'C' : language=='c',
677                                               'Python' : language=='py',
678                                               'Py' : language=='py',
679                                               'CPy' : (language=='py' or language == 'c'),
680                                               'Cpp' : language=='cpp',
681                                               'plastex' : True})
682
683         raw = open('raw.%s' % language, 'w')
684         for x in doc:
685             print >>raw, repr(x)
686         raw.close()
687         sr = SphinxWriter('index.rst', language)
688         print >>sr, """
689 OpenCV |version| %s Reference
690 =================================
691
692 The OpenCV Wiki is here: http://opencv.willowgarage.com/
693
694 Contents:
695
696 .. toctree::
697     :maxdepth: 2
698
699 """ % {'c': 'C', 'cpp': 'C++', 'py': 'Python'}[language]
700         sr.doL(doc)
701         sr.close()
702         parseBib('../opencv.bib', language)
703         tags.update(sr.get_tags())
704     open('TAGS', 'w').write("\n".join(sorted(tags.values())) + "\n")
705