beta-0.89.2
[luatex.git] / source / libs / zziplib / zziplib-0.13.62 / docs / make-doc.py
blobc58427c4a5c249ad637ef0452752594d7390392b
1 #! /usr/bin/python
2 # -*- coding: UTF-8 -*-
3 import sys
4 import re
5 import string
6 import commands
7 import warnings
9 errors = 0
10 def warn(msg, error=None):
11 global errors
12 errors += 1
13 if error is None:
14 warnings.warn("-- "+str(errors)+" --\n "+msg, RuntimeWarning, 2)
15 else:
16 warnings.warn("-- "+str(errors)+" --\n "+msg+
17 "\n error was "+str(error), RuntimeWarning, 2)
18 #fu
20 # beware, stupid python interprets backslashes in repl only partially!
21 def s(string, pattern, repl, count=0):
22 return re.sub(pattern, repl, string, count)
23 def m(string, pattern):
24 return re.match(pattern, string)
25 def sorted_keys(dict):
26 keys = dict.keys()
27 keys.sort()
28 return keys
30 # we make up a few formatter routines to help in the processing:
31 def html2docbook(text):
32 """ the C comment may contain html markup - simulate with docbook tags """
33 return (
34 s(s(s(s(s(s(s(s(s(s(s(text,
35 r"<br\s*/?>",""),
36 r"(</?)em>",r"\1emphasis>"),
37 r"<code>","<userinput>"),
38 r"</code>","</userinput>"),
39 r"<link>","<function>"),
40 r"</link>","</function>"),
41 r"(?s)\s*</screen>","</screen>"),
42 # r"<ul>","</para><itemizedlist>"),
43 # r"</ul>","</itemizedlist><para>"),
44 # r"<li>","<listitem><para>"),
45 # r"</li>","</para></listitem>\n"),
46 r"<ul>","</para><programlisting>\n"),
47 r"</ul>","</programlisting><para>"),
48 r"<li>",""),
49 r"</li>",""))
50 def paramdef2html(text):
51 return s(s(s(s(s(text,
52 r"\s+<paramdef>", r"\n<nobr>"),
53 r"<paramdef>",r"<nobr>"),
54 r"</paramdef>",r"</nobr>"),
55 r"<parameters>",r"\n <code>"),
56 r"</parameters>",r"</code>\n")
57 def section2html(text):
58 mapping = { "<screen>" : "<pre>", "</screen>" : "</pre>",
59 "<para>" : "<p>", "</para>" : "</p>" ,
60 "<function>" : "<link>", "</function>" : "</link>" }
61 for str in mapping:
62 text = string.replace(text, str, mapping[str])
63 return text
64 def html(text):
65 return section2html(paramdef2html(text))
66 def cdata1(text):
67 return string.replace(text, "&", "&amp;")
68 def cdata31(text):
69 return string.replace(string.replace(text, "<","&lt;"), ">","&gt;")
70 def cdata3(text):
71 return cdata31(cdata1(text))
72 def cdata43(text):
73 return string.replace(text,"\"", "&quot;")
74 def cdata41(text):
75 return cdata43(cdata31(text))
76 def cdata4(text):
77 return cdata43(cdata3(text))
78 def markup_as_screen41 (text):
79 """ used for non-star lines in comment blocks """
80 return " <screen> " + s(cdata41(text), r"(?m)^", r" ") +" </screen> "
82 def file_comment2section(text):
83 """ convert a C comment into a series of <para> and <screen> parts """
84 return ("<para>\n"+
85 s(s(s(s(s(s(s(text,
86 r"(?s){<([\w\.\-]+\@[\w\.\-]+\w\w)>",
87 r"&lt;\1&gt;"),
88 r"(?mx) ^\s?\s?\s? ([^\*\s]+ .*) $",
89 lambda x : markup_as_screen41 (x.group(1))),
90 r"(?mx) ^\s*[*]\s* $", r" \n</para><para>\n"),
91 r"(?mx) ^\s?\s?\s?\* (.*) $", r" \1 "),
92 r"(?sx) </screen>(\s*)<screen> ", r"\1"),
93 r"(?sx) <([^<>\;]+\@[^<>\;]+)> ", r"<email>\1</email>"),
94 r"(?sx) \&lt\;([^<>\&\;]+\@[^<>\&\;]+)\&gt\; ",
95 r"<email>\1</email>") + "\n</para>")
96 def func_comment2section(text):
97 """ convert a C comment into a series of <para> and <screen> parts
98 and sanitize a few markups already present in the comment text
99 """
100 return ("<para>\n"+
101 s(s(s(s(s(s(s(s(s(s(s(text,
102 r"<c>",r"<code>"), r"</c>", r"</code>"),
103 r"(?mx) ^\s?\s?\s? ([^\*\s]+.*)",
104 lambda x: markup_as_screen41 (x.group(1))),
105 r"(?mx) ^\s?\s?\s?\* (.*) $", r" <br /> \1"),
106 r"(?mx) ^\s*<br\s*\/>\s* $", r"\n</para><para>\n"),
107 r"<<",r"&lt;"), r">>",r"&gt;"),
108 r"(?sx) (</?para>\s*)<br\s*\/?>",r"\1"),
109 r"(?sx) (</?para>\s*)<br\s*\/?>",r"\1"),
110 r"(?sx) (<br\s*\/?>\s*)<br\s*\/?>",r"\1"),
111 r"(?sx) <\/screen>(\s*)<screen>",r"\1") + "\n</para>")
112 def markup_link_syntax(text):
113 """ markup the link-syntax ` => somewhere ` in the text block """
114 return (
115 s(s(s(s(text,
116 r"(?mx) (^|\s)\=\>\"([^\"]*)\"", r"\1<link>\2</link>"),
117 r"(?mx) (^|\s)\=\>\'([^\"]*)\'", r"\1<link>\2</link>"),
118 r"(?mx) (^|\s)\=\>\s(\w[\w.]*\w)\b", r"\1<link>\2</link>"),
119 r"(?mx) (^|\s)\=\>\s([^\s\,\.\!\?\:\;\<\>\&\'\=\-]+)",
120 r"\1<link>\2</link>"))
121 def this_function_link(text, name):
122 return s(text, r"(?sx) (T|t)his \s (function|procedure) ", lambda x
123 : "<function>"+x.group(1)+"he "+name+" "+x.group(2)+"</function>")
125 # -----------------------------------------------------------------------
126 class Options:
127 var = {}
128 def __getattr__(self, name):
129 if not self.var.has_key(name): return None
130 return self.var[name]
131 def __setattr__(self, name, value):
132 self.var[name] = value
133 #end
135 o = Options()
136 o.verbose = 0
138 o.version = s( commands.getoutput(
139 """ grep -i "^version *:" *.spec 2>/dev/null |
140 sed -e "s/[Vv]ersion *: *//" """), r"\s*",r"")
141 o.package = s(commands.getoutput(
142 """ grep -i "^name *:" *.spec 2>/dev/null |
143 sed -e "s/[Nn]ame *: *//" """), r"\s*",r"")
145 if not len(o.version):
146 o.version = commands.getoutput(""" date +%Y.%m.%d """)
147 if not len(o.package):
148 o.package = "_project"
150 o.suffix = "-doc3"
151 o.mainheader = o.package+".h"
153 class File:
154 def __init__(self, filename):
155 self.name = filename
156 self.mainheader = o.mainheader
157 self.authors = ""
158 self.copyright = ""
159 def __getattr__(self, name):
160 """ defend against program to break on uninited members """
161 if self.__dict__.has_key(name): return self.__dict__[name]
162 warn("no such member: "+name); return None
163 def set_author(self, text):
164 if self.authors:
165 self.authors += "\n"
166 self.authors += text
167 return text
168 def set_copyright(self, text):
169 self.copyright = text
170 return text
172 class InputFiles:
173 """ for each set of input files we can create an object
174 it does correspond with a single html-output page and
175 a single docbook <reference> master page to be output
177 def __init__(self):
178 # the id will tell us in which order
179 # we did meet each function definition
180 self.id = 1000
181 self.files = [] # file_list
182 self.funcs = [] # func_list: of hidden class FuncDeclaration
183 self.file = None # current file
184 def new_File(self, name):
185 self.file = File(name)
186 self.files.append(self.file)
187 return self.file
188 def next_id(self):
189 id = self.id ; self.id += 1
190 return id
191 def add_function_declaration(self, comment, prototype):
192 class FuncDeclaration: # note that both decl.comment and
193 pass # decl.prototype are in cdata1 format
194 func = FuncDeclaration()
195 func.file = self.file
196 func.comment = s(comment, # need to take out email-style markups
197 r"<([\w\.\-]+\@[\w\.\-]+\w\w)>", r"&lt;\1&gt;")
198 func.prototype = prototype
199 func.id = all.next_id()
200 self.funcs.append(func)
201 # print id
202 return prototype
204 def scan_options (options, list):
205 def encode(text):
206 return s(s(text, r"¬", r"&#AC;"), r"\*/",r"¬")
207 def decode(text):
208 return s(text, r"¬", r"*/")
210 for name in options:
211 found = m(name, r"^(\w+)=(.*)")
212 if found:
213 o.var[found.group(1)] = found.group(2)
214 continue
215 #else
216 try:
217 input = open(name, "r")
218 except IOError, error:
219 warn(#...... (scan_options) ...............
220 "can not open input file: "+name, error)
221 continue
222 text = input.read() ; input.close()
223 text = encode (cdata1 (text))
225 file = list.new_File(name)
227 # cut per-function comment block
228 text = s(text, r"(?x) [/][*][*](?=\s) ([^¬]+) ¬ ([^\{\}\;\#]+) [\{\;]",
229 lambda x : list.add_function_declaration(
230 decode(x.group(1)), decode(x.group(2))))
232 # cut per-file comment block
233 found = m(text, r"(?sx) [/][*]+(?=\s) ([^¬]+) ¬ "
234 r"(?:\s*\#define\s*\S+)*"
235 r"(\s*\#include\s*<[^<>]*>(?:\s*//[^\n]*)?)")
236 if found:
237 file.comment = decode(found.group(1))
238 file.include = cdata31(found.group(2))
239 else:
240 file.comment = None
241 file.include = None
242 found = m(text, r"(?sx) ^ [/][*]+(?=\s) ([^¬]+) ¬ ")
243 if found:
244 file.comment = decode(found.group(1))
246 # throw away the rest - further processing on memorized strings only
248 return None
250 all = InputFiles()
251 scan_options (sys.argv[1:], all)
253 if not o.docbookfile:
254 o.docbookfile = o.package+o.suffix+".docbook"
255 if not o.libhtmlfile:
256 o.libhtmlfile = o.package+o.suffix+".html"
257 if not o.dumpdocfile:
258 o.dumpdocfile = o.package+o.suffix+".dxml"
260 # ...........................................................................
261 # check out information in the file.comment section
263 def all_files_comment2section(list):
264 for file in list:
265 if file.comment is None: continue
266 file.section = file_comment2section(file.comment)
268 file.section = s(
269 file.section, r"(?sx) \b[Aa]uthor\s*:(.*</email>) ", lambda x
270 : "<author>" + file.set_author(x.group(1)) + "</author>")
271 file.section = s(
272 file.section, r"(?sx) \b[Cc]opyright\s*:([^<>]*)</para> ",lambda x
273 : "<copyright>" + file.set_copyright(x.group(1)) + "</copyright>")
274 # if "file" in file.name: print >> sys.stderr, file.comment # 2.3
276 all_files_comment2section(all.files)
278 # -----------------------------------------------------------------------
280 class Function:
281 " <prespec>void* </><namespec>hello</><namespec> (int) const</callspec> "
282 def __init__(self):
283 self.prespec = ""
284 self.namespec = ""
285 self.callspec = ""
286 self.name = ""
287 # def set(self, **defines):
288 # name = defines.keys()[0]
289 # self.__dict__[name] = defines[name]
290 # return defines[name]
291 # def cut(self, **defines):
292 # name = defines.keys()[0]
293 # self.__dict__[name] += defines[name]
294 # return ""
295 def __getattr__(self, name):
296 """ defend against program exit on members being not inited """
297 if self.__dict__.has_key(name): return self.__dict__[name]
298 warn("no such member: "+name); return None
299 def dict(self):
300 return self.__dict__
301 def dict_sorted_keys(self):
302 keys = self.__dict__.keys()
303 keys.sort()
304 return keys
305 def parse(self, prototype):
306 found = m(prototype, r"(?sx) ^(.*[^.]) \b(\w[\w.]*\w)\b (\s*\(.*) $ ")
307 if found:
308 self.prespec = found.group(1).lstrip()
309 self.namespec = found.group(2)
310 self.callspec = found.group(3).lstrip()
311 self.name = self.namespec.strip()
312 return self.name
313 return None
315 # pass 1 of per-func strings ...............................................
316 # (a) cut prototype into prespec/namespec/callspec
317 # (b) cut out first line of comment as headline information
318 # (c) sanitize rest of comment block into proper docbook formatted .body
320 # do this while copying strings from all.funcs to function_list
321 # and remember the original order in name_list
323 def markup_callspec(text):
324 return (
325 s(s(s(s(s(text,
326 r"(?sx) ^([^\(\)]*)\(", r"\1<parameters>(<paramdef>",1),
327 r"(?sx) \)([^\(\)]*)$", r"</paramdef>)</parameters>\1",1),
328 r"(?sx) , ", r"</paramdef>,<paramdef>"),
329 r"(?sx) <paramdef>(\s+) ", r"\1<paramdef>"),
330 r"(?sx) (\s+)</paramdef>", r"</paramdef>\1"))
332 def parse_all_functions(func_list): # list of FunctionDeclarations
333 """ parse all FunctionDeclarations and create a list of Functions """
334 list = []
335 for func in all.funcs:
336 function = Function()
337 if not function.parse (func.prototype): continue
339 list.append(function)
341 function.body = markup_link_syntax(func.comment)
342 if "\n" not in function.body: # single-line comment is the head
343 function.head = function.body
344 function.body = ""
345 else: # cut comment in first-line and only keep the rest as descr body
346 function.head = s(function.body, r"(?sx) ^([^\n]*\n).*",r"\1",1)
347 function.body = s(function.body, r"(?sx) ^[^\n]*\n", r"", 1)
349 if m(function.head, r"(?sx) ^\s*$ "): # empty head line, autofill here
350 function.head = s("("+func.file.name+")", r"[.][.][/]", r"")
352 function.body = func_comment2section(function.body)
353 function.src = func # keep a back reference
355 # add extra docbook markups to callspec in $fn-hash
356 function.callspec = markup_callspec (function.callspec)
358 return list
359 function_list = parse_all_functions(all.funcs)
361 def examine_head_anchors(func_list):
362 """ .into tells later steps which func-name is the leader of a man
363 page and that this func should add its descriptions over there. """
364 for function in func_list:
365 function.into = None
366 function.seealso = None
368 found = m(function.head, r"(?sx) ^ \s* <link>(\w[\w.]*\w)<\/link>")
369 # if found and found.group(1) in func_list.names:
370 if found and found.group(1):
371 function.into = found.group(1)
373 def set_seealso(f, value):
374 f.seealso = value
375 return value
376 function.head = s(function.head, r"(.*)also:(.*)", lambda x
377 : set_seealso(function, x.group(2)) and x.group(1))
378 if function.seealso and None:
379 print "function[",function.name,"].seealso=",function.seealso
380 examine_head_anchors(function_list)
382 # =============================================================== HTML =====
384 def find_by_name(func_list, name):
385 for func in func_list:
386 if func.name == name:
387 return func
389 return None
392 class HtmlFunction:
393 def __init__(self, func):
394 self.src = func.src
395 self.into = func.into
396 self.name = func.name
397 self.toc_line = paramdef2html(
398 " <td valign=\"top\"><code>"+func.prespec+"</code></td>\n"+
399 " <td valign=\"top\">&nbsp;&nbsp;</td>\n"+
400 " <td valign=\"top\"><a href=\"#"+func.name+"\">\n"+
401 " <code>"+func.namespec+"</code>"+
402 " </a></td>\n"+
403 " <td valign=\"top\">&nbsp;&nbsp;</td>\n"+
404 " <td valign=\"top\">"+func.callspec+"</td>\n")
405 self.synopsis = paramdef2html(
406 " <code>"+func.prespec+"</code>\n"+
407 " <br /><b><code>"+func.namespec+"</code></b>\n"+
408 " &nbsp; <code>"+func.callspec+"</code>\n")
409 self.anchor = "<a name=\""+func.name+"\" />"
410 self.section = "<para><em> &nbsp;"+func.head+"\n"+ \
411 "\n</em></para>"+section2html(func.body)
412 #class
414 class HtmlFunctionFamily(HtmlFunction):
415 def __init__(page, func):
416 HtmlFunction.__init__(page, func)
417 page.toc_line_list = [ page.toc_line ]
418 # page.html_txt = page.synopsis
419 page.synopsis_list = [ page.synopsis ]
420 page.anchor_list = [ page.anchor ]
421 page.section_list = [ this_function_link(page.section, func.name) ]
423 def ensure_name(text, name):
424 adds = "<small><code>"+name+"</code></small> -"
425 match = r"(?sx) .*>[^<>]*\b" + name + r"\b[^<>]*<.*"
426 found = m(text, match)
427 if found: return text
428 found = m(text, r".*<p(ara)?>.*")
429 if found: return s(text, r"(<p(ara)?>)", r"\1"+adds, 1)
430 return adds+text
432 def combined_html_pages(func_list):
433 """ and now add descriptions of non-leader entries (html-mode) """
434 combined = {}
436 for func in func_list: # assemble leader pages
437 if func.into is not None: continue
438 combined[func.name] = HtmlFunctionFamily(func)
440 for func in func_list:
441 if func.into is None: continue
442 if func.into not in combined :
443 warn(#......... (combine_html_pages) ..............
444 "function '"+func.name+"'s into => '"+func.into+
445 "\n: no such target function: "+func.into)
446 combined[func.name] = HtmlFunctionFamily(func)
447 continue
449 page = HtmlFunction(func)
450 into = combined[func.into]
451 into.toc_line_list.append( page.toc_line )
452 into.anchor_list.append( page.anchor )
453 into.synopsis_list.append( page.synopsis )
454 into.section_list.append(
455 s(ensure_name(this_function_link(section2html( func.body ),
456 func.name), func.name),
457 r"(?sx) (</?para>\s*) <br\s*\/>", r"\1"))
458 return combined.values()
459 html_pages = combined_html_pages(function_list)
461 def html_resolve_links_on_page(text, list):
462 """ link ref-names of a page with its endpoint on the same html page"""
463 def html_link (name , extra):
464 """ make <link>s to <href> of correct target or make it <code> """
465 if find_by_name(list, name) is None:
466 return "<code>"+name+extra+"</code>"
467 else:
468 return "<a href=\"#"+name+"\"><code>"+name+extra+"</code></a>"
469 #fu html_link
470 return s(s(text, r"(?sx) <link>(\w+)([^<>]*)<\/link> ",
471 lambda x : html_link(x.group(1),x.group(2))),
472 r"(?sx) \-\> ", r"<small>-&gt;</small>") # just sanitize..
473 #fu html_resolve_links
475 class HtmlPage:
476 def __init__(self):
477 self.toc = ""
478 self.txt = ""
479 self.package = o.package
480 self.version = o.version
481 def page_text(self):
482 """ render .toc and .txt parts into proper <html> page """
483 T = ""
484 T += "<html><head>"
485 T += "<title>"+self.package+"autodoc documentation </title>"
486 T += "</head>\n<body>\n"
487 T += "\n<h1>"+self.package+" <small><small><i>- "+self.version
488 T += "</i></small></small></h1>"
489 T += "\n<table border=0 cellspacing=2 cellpadding=0>"
490 T += self.toc
491 T += "\n</table>"
492 T += "\n<h3>Documentation</h3>\n\n<dl>"
493 T += html_resolve_links_on_page(self.txt, function_list)
494 T += "\n</dl>\n</body></html>\n"
495 return T
496 def add_page_map(self, list):
497 """ generate the index-block at the start of the onepage-html file """
498 keys = list.keys()
499 keys.sort()
500 for name in keys:
501 self.toc += "<tr valign=\"top\">\n"+ \
502 "\n</tr><tr valign=\"top\">\n".join(
503 list[name].toc_line_list)+"</tr>\n"
504 self.txt += "\n<dt>"+" ".join(list[name].anchor_list)
505 self.txt += "\n"+"\n<br />".join(list[name].synopsis_list)+"<dt>"
506 self.txt += "\n<dd>\n"+"\n".join(list[name].section_list)
507 self.txt += ("\n<p align=\"right\">"+
508 "<small>("+list[name].src.file.name+")</small>"+
509 "</p></dd>")
510 def add_page_list(self, functions):
511 """ generate the index-block at the start of the onepage-html file """
512 mapp = {}
513 for func in functions:
514 mapp[func.name] = func
516 self.add_page_map(mapp)
517 #end
519 html = HtmlPage()
520 # html.add_function_dict(Fn)
521 # html.add_function_list(Fn.sort.values())
522 html.add_page_list(html_pages)
524 # and finally print the html-formatted output
525 try:
526 F = open(o.libhtmlfile, "w")
527 except IOError, error:
528 warn(# ............. open(o.libhtmlfile, "w") ..............
529 "can not open html output file: "+o.libhtmlfile, error)
530 else:
531 print >> F, html.page_text()
532 F.close()
535 # ========================================================== DOCBOOK =====
536 # let's go for the pure docbook, a reference type master for all man pages
538 class RefPage:
539 def __init__(self, func):
540 """ initialize the fields needed for a man page entry - the fields are
541 named after the docbook-markup that encloses (!!) the text we store
542 the entries like X.refhint = "hello" will be printed therefore as
543 <refhint>hello</refhint>. Names with underscores are only used as
544 temporaries but they are memorized, perhaps for later usage. """
545 self.refhint = "\n<!--========= "+func.name+" (3) ===========-->\n"
546 self.refentry = None
547 self.refentry_date = o.version.strip() # //refentryinfo/date
548 self.refentry_productname = o.package.strip() # //refentryinfo/prod*
549 self.refentry_title = None # //refentryinfo/title
550 self.refentryinfo = None # override
551 self.manvolnum = "3" # //refmeta/manvolnum
552 self.refentrytitle = None # //refmeta/refentrytitle
553 self.refmeta = None # override
554 self.refpurpose = None # //refnamediv/refpurpose
555 self.refname = None # //refnamediv/refname
556 self.refname_list = []
557 self.refnamediv = None # override
558 self.mainheader = func.src.file.mainheader
559 self.includes = func.src.file.include
560 self.funcsynopsisinfo = "" # //funcsynopsisdiv/funcsynopsisinfo
561 self.funcsynopsis = None # //funcsynopsisdiv/funcsynopsis
562 self.funcsynopsis_list = []
563 self.description = None
564 self.description_list = []
565 # optional sections
566 self.authors_list = [] # //sect1[authors]/listitem
567 self.authors = None # override
568 self.copyright = None
569 self.copyright_list = []
570 self.seealso = None
571 self.seealso_list = []
572 if func.seealso:
573 self.seealso_list.append(func.seealso)
574 # func.func references
575 self.func = func
576 self.file_authors = None
577 if func.src.file.authors:
578 self.file_authors = func.src.file.authors
579 self.file_copyright = None
580 if func.src.file.copyright:
581 self.file_copyright = func.src.file.copyright
583 def refentryinfo_text(page):
584 """ the manvol formatter wants to render a footer line and header line
585 on each manpage and such info is set in <refentryinfo> """
586 if page.refentryinfo:
587 return page.refentryinfo
588 if page.refentry_date and \
589 page.refentry_productname and \
590 page.refentry_title: return (
591 "\n <date>"+page.refentry_date+"</date>"+
592 "\n <productname>"+page.refentry_productname+"</productname>"+
593 "\n <title>"+page.refentry_title+"</title>")
594 if page.refentry_date and \
595 page.refentry_productname: return (
596 "\n <date>"+page.refentry_date+"</date>"+
597 "\n <productname>"+page.refentry_productname+"</productname>")
598 return ""
599 def refmeta_text(page):
600 """ the manvol formatter needs to know the filename of the manpage to
601 be made up and these parts are set in <refmeta> actually """
602 if page.refmeta:
603 return page.refmeta
604 if page.manvolnum and page.refentrytitle:
605 return (
606 "\n <refentrytitle>"+page.refentrytitle+"</refentrytitle>"+
607 "\n <manvolnum>"+page.manvolnum+"</manvolnum>")
608 if page.manvolnum and page.func.name:
609 return (
610 "\n <refentrytitle>"+page.func.name+"</refentrytitle>"+
611 "\n <manvolnum>"+page.manvolnum+"</manvolnum>")
612 return ""
613 def refnamediv_text(page):
614 """ the manvol formatter prints a header line with a <refpurpose> line
615 and <refname>'d functions that are described later. For each of
616 the <refname>s listed here, a mangpage is generated, and for each
617 of the <refname>!=<refentrytitle> then a symlink is created """
618 if page.refnamediv:
619 return page.refnamediv
620 if page.refpurpose and page.refname:
621 return ("\n <refname>"+page.refname+'</refname>'+
622 "\n <refpurpose>"+page.refpurpose+" </refpurpose>")
623 if page.refpurpose and page.refname_list:
624 T = ""
625 for refname in page.refname_list:
626 T += "\n <refname>"+refname+'</refname>'
627 T += "\n <refpurpose>"+page.refpurpose+" </refpurpose>"
628 return T
629 return ""
630 def funcsynopsisdiv_text(page):
631 """ refsynopsisdiv shall be between the manvol mangemaent information
632 and the reference page description blocks """
633 T=""
634 if page.funcsynopsis:
635 T += "\n<funcsynopsis>"
636 if page.funcsynopsisinfo:
637 T += "\n<funcsynopsisinfo>"+ page.funcsynopsisinfo + \
638 "\n</funcsynopsisinfo>\n"
639 T += page.funcsynopsis + \
640 "\n</funcsynopsis>\n"
641 if page.funcsynopsis_list:
642 T += "\n<funcsynopsis>"
643 if page.funcsynopsisinfo:
644 T += "\n<funcsynopsisinfo>"+ page.funcsynopsisinfo + \
645 "\n</funcsynopsisinfo>\n"
646 for funcsynopsis in page.funcsynopsis_list:
647 T += funcsynopsis
648 T += "\n</funcsynopsis>\n"
650 return T
651 def description_text(page):
652 """ the description section on a manpage is the main part. Here
653 it is generated from the per-function comment area. """
654 if page.description:
655 return page.description
656 if page.description_list:
657 T = ""
658 for description in page.description_list:
659 if not description: continue
660 T += description
661 if T: return T
662 return ""
663 def authors_text(page):
664 """ part of the footer sections on a manpage and a description of
665 original authors. We prever an itimizedlist to let the manvol
666 show a nice vertical aligment of authors of this ref item """
667 if page.authors:
668 return page.authors
669 if page.authors_list:
670 T = "<itemizedlist>"
671 previous=""
672 for authors in page.authors_list:
673 if not authors: continue
674 if previous == authors: continue
675 T += "\n <listitem><para>"+authors+"</para></listitem>"
676 previous = authors
677 T += "</itemizedlist>"
678 return T
679 if page.authors:
680 return page.authors
681 return ""
682 def copyright_text(page):
683 """ the copyright section is almost last on a manpage and purely
684 optional. We list the part of the per-file copyright info """
685 if page.copyright:
686 return page.copyright
687 """ we only return the first valid instead of merging them """
688 if page.copyright_list:
689 T = ""
690 for copyright in page.copyright_list:
691 if not copyright: continue
692 return copyright # !!!
693 return ""
694 def seealso_text(page):
695 """ the last section on a manpage is called 'SEE ALSO' usally and
696 contains a comma-separated list of references. Some manpage
697 viewers can parse these and convert them into hyperlinks """
698 if page.seealso:
699 return page.seealso
700 if page.seealso_list:
701 T = ""
702 for seealso in page.seealso_list:
703 if not seealso: continue
704 if T: T += ", "
705 T += seealso
706 if T: return T
707 return ""
708 def refentry_text(page, id=None):
709 """ combine fields into a proper docbook refentry """
710 if id is None:
711 id = page.refentry
712 if id:
713 T = '<refentry id="'+id+'">'
714 else:
715 T = '<refentry>' # this is an error
717 if page.refentryinfo_text():
718 T += "\n<refentryinfo>"+ page.refentryinfo_text()+ \
719 "\n</refentryinfo>\n"
720 if page.refmeta_text():
721 T += "\n<refmeta>"+ page.refmeta_text() + \
722 "\n</refmeta>\n"
723 if page.refnamediv_text():
724 T += "\n<refnamediv>"+ page.refnamediv_text() + \
725 "\n</refnamediv>\n"
726 if page.funcsynopsisdiv_text():
727 T += "\n<refsynopsisdiv>\n"+ page.funcsynopsisdiv_text()+ \
728 "\n</refsynopsisdiv>\n"
729 if page.description_text():
730 T += "\n<refsect1><title>Description</title> " + \
731 page.description_text() + "\n</refsect1>"
732 if page.authors_text():
733 T += "\n<refsect1><title>Author</title> " + \
734 page.authors_text() + "\n</refsect1>"
735 if page.copyright_text():
736 T += "\n<refsect1><title>Copyright</title> " + \
737 page.copyright_text() + "\n</refsect1>\n"
738 if page.seealso_text():
739 T += "\n<refsect1><title>See Also</title><para> " + \
740 page.seealso_text() + "\n</para></refsect1>\n"
742 T += "\n</refentry>\n"
743 return T
745 #end
747 # -----------------------------------------------------------------------
748 class FunctionRefPage(RefPage):
749 def reinit(page):
750 """ here we parse the input function for its values """
751 if page.func.into:
752 page.refhint = "\n <!-- see "+page.func.into+" -->\n"
754 page.refentry = page.func.name # //refentry@id
755 page.refentry_title = page.func.name.strip() # //refentryinfo/title
756 page.refentrytitle = page.func.name # //refmeta/refentrytitle
757 if page.includes:
758 page.funcsynopsisinfo += "\n"+page.includes
759 if not page.funcsynopsisinfo:
760 page.funcsynopsisinfo="\n"+' #include &lt;'+page.mainheader+'&gt;'
761 page.refpurpose = page.func.head
762 page.refname = page.func.name
764 def funcsynopsis_of(func):
765 return (
766 "\n <funcprototype>\n <funcdef>"+func.prespec+
767 " <function>"+func.name+"</function></funcdef>"+
768 "\n"+s(s(s(func.callspec,
769 r"<parameters>\s*\(",r" "),
770 r"\)\s*</parameters>",r" "),
771 r"</paramdef>\s*,\s*",r"</paramdef>\n ")+
772 " </funcprototype>")
773 page.funcsynopsis = funcsynopsis_of(page.func)
775 page.description = (
776 html2docbook(this_function_link(page.func.body, page.func.name)))
778 if page.file_authors:
779 def add_authors(page, ename, email):
780 page.authors_list.append( ename+' '+email )
781 return ename+email
782 s(page.file_authors,
783 r"(?sx) \s* ([^<>]*) (<email>[^<>]*</email>) ", lambda x
784 : add_authors(page, x.group(1), x.group(2)))
787 if page.file_copyright:
788 page.copyright = "<screen>\n"+page.file_copyright+"</screen>\n"
790 return page
791 def __init__(page,func):
792 RefPage.__init__(page, func)
793 FunctionRefPage.reinit(page)
795 def refpage_list_from_function_list(funclist):
796 list = []
797 mapp = {}
798 for func in funclist:
799 mapp[func.name] = func
801 for func in funclist:
802 page = FunctionRefPage(func)
803 if func.into and func.into not in mapp:
804 warn (# ............ (refpage_list_from_function_list) .......
805 "page '"+page.func.name+"' has no target => "+
806 "'"+page.func.into+"'"
807 "\n: going to reset .into of Function '"+page.func.name+"'")
808 func.into = None
810 list.append(FunctionRefPage(func))
811 return list
814 # ordered list of pages
815 refpage_list = refpage_list_from_function_list(function_list)
817 class FunctionFamilyRefPage(RefPage):
818 def __init__(self, page):
819 RefPage.__init__(self, page.func)
820 self.seealso_list = [] # reset
821 self.refhint_list = []
822 def refhint_list_text(page):
823 T = ""
824 for hint in page.refhint_list:
825 T += hint
826 return T
827 def refentry_text(page):
828 return page.refhint_list_text() + "\n" + \
829 RefPage.refentry_text(page)
830 pass
832 def docbook_pages_recombine(pagelist):
833 """ take a list of RefPages and create a new list where sections are
834 recombined in a way that their description is listed on the same
835 page and the manvol formatter creates symlinks to the combined
836 function description page - use the attribute 'into' to guide the
837 processing here as each of these will be removed from the output
838 list. If no into-pages are there then the returned list should
839 render to the very same output text like the input list would do """
841 list = []
842 combined = {}
843 for orig in pagelist:
844 if orig.func.into: continue
845 page = FunctionFamilyRefPage(orig)
846 combined[orig.func.name] = page ; list.append(page)
848 page.refentry = orig.refentry # //refentry@id
849 page.refentry_title = orig.refentrytitle # //refentryinfo/title
850 page.refentrytitle = orig.refentrytitle # //refmeta/refentrytitle
851 page.includes = orig.includes
852 page.funcsynopsisinfo = orig.funcsynopsisinfo
853 page.refpurpose = orig.refpurpose
854 if orig.refhint:
855 page.refhint_list.append( orig.refhint )
856 if orig.refname:
857 page.refname_list.append( orig.refname )
858 elif orig.refname_list:
859 page.refname_list.extend( orig.refname_list )
860 if orig.funcsynopsis:
861 page.funcsynopsis_list.append( orig.funcsynopsis )
862 elif orig.refname_list:
863 page.funcsynopsis_list.extend( orig.funcsynopsis_list )
864 if orig.description:
865 page.description_list.append( orig.description )
866 elif orig.refname_list:
867 page.description_list.extend( orig.description_list )
868 if orig.seealso:
869 page.seealso_list.append( orig.seealso )
870 elif orig.seealso_list:
871 page.seealso_list.extend( orig.seealso_list )
872 if orig.authors:
873 page.authors_list.append( orig.authors )
874 elif orig.authors_list:
875 page.authors_list.extend( orig.authors_list )
876 if orig.copyright:
877 page.copyright_list.append( orig.copyright )
878 elif orig.refname_list:
879 page.copyright_list.extend( orig.copyright_list )
881 for orig in pagelist:
882 if not orig.func.into: continue
883 if orig.func.into not in combined:
884 warn("page for '"+orig.func.name+
885 "' has no target => '"+orig.func.into+"'")
886 page = FunctionFamilyRefPage(orig)
887 else:
888 page = combined[orig.func.into]
890 if orig.refname:
891 page.refname_list.append( orig.refname )
892 elif orig.refname_list:
893 page.refname_list.extend( orig.refname_list )
894 if orig.funcsynopsis:
895 page.funcsynopsis_list.append( orig.funcsynopsis )
896 elif orig.refname_list:
897 page.funcsynopsis_list.extend( orig.funcsynopsis_list )
898 if orig.description:
899 page.description_list.append( orig.description )
900 elif orig.refname_list:
901 page.description_list.extend( orig.description_list )
902 if orig.seealso:
903 page.seealso_list.append( orig.seealso )
904 elif orig.seealso_list:
905 page.seealso_list.extend( orig.seealso_list )
906 if orig.authors:
907 page.authors_list.append( orig.authors )
908 elif orig.authors_list:
909 page.authors_list.extend( orig.authors_list )
910 if orig.copyright:
911 page.copyright_list.append( orig.copyright )
912 elif orig.refname_list:
913 page.copyright_list.extend( orig.copyright_list )
915 return list
918 combined_pages = docbook_pages_recombine(pagelist = refpage_list)
920 # -----------------------------------------------------------------------
922 class HeaderRefPage(RefPage):
923 pass
925 def docbook_refpages_perheader(page_list): # headerlist
926 " creating the per-header manpage - a combination of function man pages "
927 header = {}
928 for page in page_list:
929 assert not page.func.into
930 file = page.func.src.file.mainheader # short for the mainheader index
931 if file not in header:
932 header[file] = HeaderRefPage(page.func)
933 header[file].id = s(file, r"[^\w\.]","-")
934 header[file].refentry = header[file].id
935 header[file].refentryinfo = None
936 header[file].refentry_date = page.refentry_date
937 header[file].refentry_productname = (
938 "the library "+page.refentry_productname)
939 header[file].manvolnum = page.manvolnum
940 header[file].refentrytitle = file
941 header[file].funcsynopsis = ""
942 if 1: # or += or if not header[file].refnamediv:
943 header[file].refpurpose = " library "
944 header[file].refname = header[file].id
946 if not header[file].funcsynopsisinfo and page.funcsynopsisinfo:
947 header[file].funcsynopsisinfo = page.funcsynopsisinfo
948 if page.funcsynopsis:
949 header[file].funcsynopsis += "\n"+page.funcsynopsis
950 if not header[file].copyright and page.copyright:
951 header[file].copyright = page.copyright
952 if not header[file].authors and page.authors:
953 header[file].authors = page.authors
954 if not header[file].authors and page.authors_list:
955 header[file].authors_list = page.authors_list
956 if not header[file].description:
957 found = m(commands.getoutput("cat "+o.package+".spec"),
958 r"(?s)\%description\b([^\%]*)\%")
959 if found:
960 header[file].description = found.group(1)
961 elif not header[file].description:
962 header[file].description = "<para>" + (
963 page.refentry_productname + " library") + "</para>";
967 return header#list
970 def leaders(pagelist):
971 list = []
972 for page in pagelist:
973 if page.func.into : continue
974 list.append(page)
975 return list
976 header_refpages = docbook_refpages_perheader(leaders(refpage_list))
978 # -----------------------------------------------------------------------
979 # printing the docbook file is a two-phase process - we spit out the
980 # leader pages first - later we add more pages with _refstart pointing
981 # to the leader page, so that xmlto will add the functions there. Only the
982 # leader page contains some extra info needed for troff page processing.
984 doctype = '<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"'
985 doctype += "\n "
986 doctype += '"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">'+"\n"
988 try:
989 F = open(o.docbookfile,"w")
990 except IOError, error:
991 warn("can not open docbook output file: "+o.docbookfile, error)
992 else:
993 print >> F, doctype, '<reference><title>Manual Pages</title>'
995 for page in combined_pages:
996 print >> F, page.refentry_text()
999 for page in header_refpages.values():
1000 if not page.refentry: continue
1001 print >> F, "\n<!-- _______ "+page.id+" _______ -->",
1002 print >> F, page.refentry_text()
1005 print >> F, "\n",'</reference>',"\n"
1006 F.close()
1009 # _____________________________________________________________________
1010 try:
1011 F = open( o.dumpdocfile, "w")
1012 except IOError, error:
1013 warn ("can not open"+o.dumpdocfile,error)
1014 else:
1015 for func in function_list:
1016 name = func.name
1017 print >> F, "<fn id=\""+name+"\">"+"<!-- FOR \""+name+"\" -->\n"
1018 for H in sorted_keys(func.dict()):
1019 print >> F, "<"+H+" name=\""+name+"\">",
1020 print >> F, str(func.dict()[H]),
1021 print >> F, "</"+H+">"
1023 print >> F, "</fn><!-- END \""+name+"\" -->\n\n";
1025 F.close();
1028 if errors: sys.exit(errors)