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