8 def warn(msg, error=None):
12 warnings.warn("-- "+str(errors)+" --\n "+msg, RuntimeWarning, 2)
14 warnings.warn("-- "+str(errors)+" --\n "+msg+
15 "\n error was "+str(error), RuntimeWarning, 2)
18 # beware, stupid python interprets backslashes in repl only partially!
19 def s(string, pattern, repl, count=0):
20 return re.sub(pattern, repl, string, count)
21 def m(string, pattern):
22 return re.match(pattern, string)
23 def sorted_keys(dict):
28 # we make up a few formatter routines to help in the processing:
29 def html2docbook(text):
30 """ the C comment may contain html markup - simulate with docbook tags """
32 s(s(s(s(s(s(s(s(s(s(s(text,
34 r"(</?)em>",r"\1emphasis>"),
35 r"<code>","<userinput>"),
36 r"</code>","</userinput>"),
37 r"<link>","<function>"),
38 r"</link>","</function>"),
39 r"(?s)\s*</screen>","</screen>"),
40 # r"<ul>","</para><itemizedlist>"),
41 # r"</ul>","</itemizedlist><para>"),
42 # r"<li>","<listitem><para>"),
43 # r"</li>","</para></listitem>\n"),
44 r"<ul>","</para><programlisting>\n"),
45 r"</ul>","</programlisting><para>"),
48 def paramdef2html(text):
49 return s(s(s(s(s(text,
50 r"\s+<paramdef>", r"\n<nobr>"),
51 r"<paramdef>",r"<nobr>"),
52 r"</paramdef>",r"</nobr>"),
53 r"<parameters>",r"\n <code>"),
54 r"</parameters>",r"</code>\n")
55 def section2html(text):
56 mapping = { "<screen>" : "<pre>", "</screen>" : "</pre>",
57 "<para>" : "<p>", "</para>" : "</p>" ,
58 "<function>" : "<link>", "</function>" : "</link>" }
60 text = string.replace(text, str, mapping[str])
63 return section2html(paramdef2html(text))
65 return string.replace(text, "&", "&")
67 return string.replace(string.replace(text, "<","<"), ">",">")
69 return cdata31(cdata1(text))
71 return string.replace(text,"\"", """)
73 return cdata43(cdata31(text))
75 return cdata43(cdata3(text))
76 def markup_as_screen41 (text):
77 """ used for non-star lines in comment blocks """
78 return " <screen> " + s(cdata41(text), r"(?m)^", r" ") +" </screen> "
80 def file_comment2section(text):
81 """ convert a C comment into a series of <para> and <screen> parts """
84 r"(?s){<([\w\.\-]+\@[\w\.\-]+\w\w)>",
86 r"(?mx) ^\s?\s?\s? ([^\*\s]+ .*) $",
87 lambda x : markup_as_screen41 (x.group(1))),
88 r"(?mx) ^\s*[*]\s* $", r" \n</para><para>\n"),
89 r"(?mx) ^\s?\s?\s?\* (.*) $", r" \1 "),
90 r"(?sx) </screen>(\s*)<screen> ", r"\1"),
91 r"(?sx) <([^<>\;]+\@[^<>\;]+)> ", r"<email>\1</email>"),
92 r"(?sx) \<\;([^<>\&\;]+\@[^<>\&\;]+)\>\; ",
93 r"<email>\1</email>") + "\n</para>")
94 def func_comment2section(text):
95 """ convert a C comment into a series of <para> and <screen> parts
96 and sanitize a few markups already present in the comment text
99 s(s(s(s(s(s(s(s(s(s(s(text,
100 r"<c>",r"<code>"), r"</c>", r"</code>"),
101 r"(?mx) ^\s?\s?\s? ([^\*\s]+.*)",
102 lambda x: markup_as_screen41 (x.group(1))),
103 r"(?mx) ^\s?\s?\s?\* (.*) $", r" <br /> \1"),
104 r"(?mx) ^\s*<br\s*\/>\s* $", r"\n</para><para>\n"),
105 r"<<",r"<"), r">>",r">"),
106 r"(?sx) (</?para>\s*)<br\s*\/?>",r"\1"),
107 r"(?sx) (</?para>\s*)<br\s*\/?>",r"\1"),
108 r"(?sx) (<br\s*\/?>\s*)<br\s*\/?>",r"\1"),
109 r"(?sx) <\/screen>(\s*)<screen>",r"\1") + "\n</para>")
110 def markup_link_syntax(text):
111 """ markup the link-syntax ` => somewhere ` in the text block """
114 r"(?mx) (^|\s)\=\>\"([^\"]*)\"", r"\1<link>\2</link>"),
115 r"(?mx) (^|\s)\=\>\'([^\"]*)\'", r"\1<link>\2</link>"),
116 r"(?mx) (^|\s)\=\>\s(\w[\w.]*\w)\b", r"\1<link>\2</link>"),
117 r"(?mx) (^|\s)\=\>\s([^\s\,\.\!\?\:\;\<\>\&\'\=\-]+)",
118 r"\1<link>\2</link>"))
119 def this_function_link(text, name):
120 return s(text, r"(?sx) (T|t)his \s (function|procedure) ", lambda x
121 : "<function>"+x.group(1)+"he "+name+" "+x.group(2)+"</function>")
123 # -----------------------------------------------------------------------
126 def __getattr__(self, name):
127 if not self.var.has_key(name): return None
128 return self.var[name]
129 def __setattr__(self, name, value):
130 self.var[name] = value
136 o.version = s( commands.getoutput(
137 """ grep -i "^version *:" *.spec 2>/dev/null |
138 sed -e "s/[Vv]ersion *: *//" """), r"\s*",r"")
139 o.package = s(commands.getoutput(
140 """ grep -i "^name *:" *.spec 2>/dev/null |
141 sed -e "s/[Nn]ame *: *//" """), r"\s*",r"")
143 if not len(o.version):
144 o.version = commands.getoutput(""" date +%Y.%m.%d """)
145 if not len(o.package):
146 o.package = "_project"
149 o.mainheader = o.package+".h"
152 def __init__(self, filename):
154 self.mainheader = o.mainheader
157 def __getattr__(self, name):
158 """ defend against program to break on uninited members """
159 if self.__dict__.has_key(name): return self.__dict__[name]
160 warn("no such member: "+name); return None
161 def set_author(self, text):
166 def set_copyright(self, text):
167 self.copyright = text
171 """ for each set of input files we can create an object
172 it does correspond with a single html-output page and
173 a single docbook <reference> master page to be output
176 # the id will tell us in which order
177 # we did meet each function definition
179 self.files = [] # file_list
180 self.funcs = [] # func_list: of hidden class FuncDeclaration
181 self.file = None # current file
182 def new_File(self, name):
183 self.file = File(name)
184 self.files.append(self.file)
187 id = self.id ; self.id += 1
189 def add_function_declaration(self, comment, prototype):
190 class FuncDeclaration: # note that both decl.comment and
191 pass # decl.prototype are in cdata1 format
192 func = FuncDeclaration()
193 func.file = self.file
194 func.comment = s(comment, # need to take out email-style markups
195 r"<([\w\.\-]+\@[\w\.\-]+\w\w)>", r"<\1>")
196 func.prototype = prototype
197 func.id = all.next_id()
198 self.funcs.append(func)
202 def scan_options (options, list):
204 return s(s(text, r"¬", r"&#AC;"), r"\*/",r"¬")
206 return s(text, r"¬", r"*/")
209 found = m(name, r"^(\w+)=(.*)")
211 o.var[found.group(1)] = found.group(2)
215 input = open(name, "r")
216 except IOError, error:
217 warn(#...... (scan_options) ...............
218 "can not open input file: "+name, error)
220 text = input.read() ; input.close()
221 text = encode (cdata1 (text))
223 file = list.new_File(name)
225 # cut per-function comment block
226 text = s(text, r"(?x) [/][*][*](?=\s) ([^¬]+) ¬ ([^\{\}\;\#]+) [\{\;]",
227 lambda x : list.add_function_declaration(
228 decode(x.group(1)), decode(x.group(2))))
230 # cut per-file comment block
231 found = m(text, r"(?sx) [/][*]+(?=\s) ([^¬]+) ¬ "
232 r"(?:\s*\#define\s*\S+)*"
233 r"(\s*\#include\s*<[^<>]*>(?:\s*//[^\n]*)?)")
235 file.comment = decode(found.group(1))
236 file.include = cdata31(found.group(2))
240 found = m(text, r"(?sx) ^ [/][*]+(?=\s) ([^¬]+) ¬ ")
242 file.comment = decode(found.group(1))
244 # throw away the rest - further processing on memorized strings only
249 scan_options (sys.argv[1:], all)
251 if not o.docbookfile:
252 o.docbookfile = o.package+o.suffix+".docbook"
253 if not o.libhtmlfile:
254 o.libhtmlfile = o.package+o.suffix+".html"
255 if not o.dumpdocfile:
256 o.dumpdocfile = o.package+o.suffix+".dxml"
258 # ...........................................................................
259 # check out information in the file.comment section
261 def all_files_comment2section(list):
263 if file.comment is None: continue
264 file.section = file_comment2section(file.comment)
267 file.section, r"(?sx) \b[Aa]uthor\s*:(.*</email>) ", lambda x
268 : "<author>" + file.set_author(x.group(1)) + "</author>")
270 file.section, r"(?sx) \b[Cc]opyright\s*:([^<>]*)</para> ",lambda x
271 : "<copyright>" + file.set_copyright(x.group(1)) + "</copyright>")
272 # if "file" in file.name: print >> sys.stderr, file.comment # 2.3
274 all_files_comment2section(all.files)
276 # -----------------------------------------------------------------------
279 " <prespec>void* </><namespec>hello</><namespec> (int) const</callspec> "
285 # def set(self, **defines):
286 # name = defines.keys()[0]
287 # self.__dict__[name] = defines[name]
288 # return defines[name]
289 # def cut(self, **defines):
290 # name = defines.keys()[0]
291 # self.__dict__[name] += defines[name]
293 def __getattr__(self, name):
294 """ defend against program exit on members being not inited """
295 if self.__dict__.has_key(name): return self.__dict__[name]
296 warn("no such member: "+name); return None
299 def dict_sorted_keys(self):
300 keys = self.__dict__.keys()
303 def parse(self, prototype):
304 found = m(prototype, r"(?sx) ^(.*[^.]) \b(\w[\w.]*\w)\b (\s*\(.*) $ ")
306 self.prespec = found.group(1).lstrip()
307 self.namespec = found.group(2)
308 self.callspec = found.group(3).lstrip()
309 self.name = self.namespec.strip()
313 # pass 1 of per-func strings ...............................................
314 # (a) cut prototype into prespec/namespec/callspec
315 # (b) cut out first line of comment as headline information
316 # (c) sanitize rest of comment block into proper docbook formatted .body
318 # do this while copying strings from all.funcs to function_list
319 # and remember the original order in name_list
321 def markup_callspec(text):
324 r"(?sx) ^([^\(\)]*)\(", r"\1<parameters>(<paramdef>",1),
325 r"(?sx) \)([^\(\)]*)$", r"</paramdef>)</parameters>\1",1),
326 r"(?sx) , ", r"</paramdef>,<paramdef>"),
327 r"(?sx) <paramdef>(\s+) ", r"\1<paramdef>"),
328 r"(?sx) (\s+)</paramdef>", r"</paramdef>\1"))
330 def parse_all_functions(func_list): # list of FunctionDeclarations
331 """ parse all FunctionDeclarations and create a list of Functions """
333 for func in all.funcs:
334 function = Function()
335 if not function.parse (func.prototype): continue
337 list.append(function)
339 function.body = markup_link_syntax(func.comment)
340 if "\n" not in function.body: # single-line comment is the head
341 function.head = function.body
343 else: # cut comment in first-line and only keep the rest as descr body
344 function.head = s(function.body, r"(?sx) ^([^\n]*\n).*",r"\1",1)
345 function.body = s(function.body, r"(?sx) ^[^\n]*\n", r"", 1)
347 if m(function.head, r"(?sx) ^\s*$ "): # empty head line, autofill here
348 function.head = s("("+func.file.name+")", r"[.][.][/]", r"")
350 function.body = func_comment2section(function.body)
351 function.src = func # keep a back reference
353 # add extra docbook markups to callspec in $fn-hash
354 function.callspec = markup_callspec (function.callspec)
357 function_list = parse_all_functions(all.funcs)
359 def examine_head_anchors(func_list):
360 """ .into tells later steps which func-name is the leader of a man
361 page and that this func should add its descriptions over there. """
362 for function in func_list:
364 function.seealso = None
366 found = m(function.head, r"(?sx) ^ \s* <link>(\w[\w.]*\w)<\/link>")
367 # if found and found.group(1) in func_list.names:
368 if found and found.group(1):
369 function.into = found.group(1)
371 def set_seealso(f, value):
374 function.head = s(function.head, r"(.*)also:(.*)", lambda x
375 : set_seealso(function, x.group(2)) and x.group(1))
376 if function.seealso and None:
377 print "function[",function.name,"].seealso=",function.seealso
378 examine_head_anchors(function_list)
380 # =============================================================== HTML =====
382 def find_by_name(func_list, name):
383 for func in func_list:
384 if func.name == name:
391 def __init__(self, func):
393 self.into = func.into
394 self.name = func.name
395 self.toc_line = paramdef2html(
396 " <td valign=\"top\"><code>"+func.prespec+"</code></td>\n"+
397 " <td valign=\"top\"> </td>\n"+
398 " <td valign=\"top\"><a href=\"#"+func.name+"\">\n"+
399 " <code>"+func.namespec+"</code>"+
401 " <td valign=\"top\"> </td>\n"+
402 " <td valign=\"top\">"+func.callspec+"</td>\n")
403 self.synopsis = paramdef2html(
404 " <code>"+func.prespec+"</code>\n"+
405 " <br /><b><code>"+func.namespec+"</code></b>\n"+
406 " <code>"+func.callspec+"</code>\n")
407 self.anchor = "<a name=\""+func.name+"\" />"
408 self.section = "<para><em> "+func.head+"\n"+ \
409 "\n</em></para>"+section2html(func.body)
412 class HtmlFunctionFamily(HtmlFunction):
413 def __init__(page, func):
414 HtmlFunction.__init__(page, func)
415 page.toc_line_list = [ page.toc_line ]
416 # page.html_txt = page.synopsis
417 page.synopsis_list = [ page.synopsis ]
418 page.anchor_list = [ page.anchor ]
419 page.section_list = [ this_function_link(page.section, func.name) ]
421 def ensure_name(text, name):
422 adds = "<small><code>"+name+"</code></small> -"
423 match = r"(?sx) .*>[^<>]*\b" + name + r"\b[^<>]*<.*"
424 found = m(text, match)
425 if found: return text
426 found = m(text, r".*<p(ara)?>.*")
427 if found: return s(text, r"(<p(ara)?>)", r"\1"+adds, 1)
430 def combined_html_pages(func_list):
431 """ and now add descriptions of non-leader entries (html-mode) """
434 for func in func_list: # assemble leader pages
435 if func.into is not None: continue
436 combined[func.name] = HtmlFunctionFamily(func)
438 for func in func_list:
439 if func.into is None: continue
440 if func.into not in combined :
441 warn(#......... (combine_html_pages) ..............
442 "function '"+func.name+"'s into => '"+func.into+
443 "\n: no such target function: "+func.into)
444 combined[func.name] = HtmlFunctionFamily(func)
447 page = HtmlFunction(func)
448 into = combined[func.into]
449 into.toc_line_list.append( page.toc_line )
450 into.anchor_list.append( page.anchor )
451 into.synopsis_list.append( page.synopsis )
452 into.section_list.append(
453 s(ensure_name(this_function_link(section2html( func.body ),
454 func.name), func.name),
455 r"(?sx) (</?para>\s*) <br\s*\/>", r"\1"))
456 return combined.values()
457 html_pages = combined_html_pages(function_list)
459 def html_resolve_links_on_page(text, list):
460 """ link ref-names of a page with its endpoint on the same html page"""
461 def html_link (name , extra):
462 """ make <link>s to <href> of correct target or make it <code> """
463 if find_by_name(list, name) is None:
464 return "<code>"+name+extra+"</code>"
466 return "<a href=\"#"+name+"\"><code>"+name+extra+"</code></a>"
468 return s(s(text, r"(?sx) <link>(\w+)([^<>]*)<\/link> ",
469 lambda x : html_link(x.group(1),x.group(2))),
470 r"(?sx) \-\> ", r"<small>-></small>") # just sanitize..
471 #fu html_resolve_links
477 self.package = o.package
478 self.version = o.version
480 """ render .toc and .txt parts into proper <html> page """
483 T += "<title>"+self.package+"autodoc documentation </title>"
484 T += "</head>\n<body>\n"
485 T += "\n<h1>"+self.package+" <small><small><i>- "+self.version
486 T += "</i></small></small></h1>"
487 T += "\n<table border=0 cellspacing=2 cellpadding=0>"
490 T += "\n<h3>Documentation</h3>\n\n<dl>"
491 T += html_resolve_links_on_page(self.txt, function_list)
492 T += "\n</dl>\n</body></html>\n"
494 def add_page_map(self, list):
495 """ generate the index-block at the start of the onepage-html file """
499 self.toc += "<tr valign=\"top\">\n"+ \
500 "\n</tr><tr valign=\"top\">\n".join(
501 list[name].toc_line_list)+"</tr>\n"
502 self.txt += "\n<dt>"+" ".join(list[name].anchor_list)
503 self.txt += "\n"+"\n<br />".join(list[name].synopsis_list)+"<dt>"
504 self.txt += "\n<dd>\n"+"\n".join(list[name].section_list)
505 self.txt += ("\n<p align=\"right\">"+
506 "<small>("+list[name].src.file.name+")</small>"+
508 def add_page_list(self, functions):
509 """ generate the index-block at the start of the onepage-html file """
511 for func in functions:
512 mapp[func.name] = func
514 self.add_page_map(mapp)
518 # html.add_function_dict(Fn)
519 # html.add_function_list(Fn.sort.values())
520 html.add_page_list(html_pages)
522 # and finally print the html-formatted output
524 F = open(o.libhtmlfile, "w")
525 except IOError, error:
526 warn(# ............. open(o.libhtmlfile, "w") ..............
527 "can not open html output file: "+o.libhtmlfile, error)
529 print >> F, html.page_text()
533 # ========================================================== DOCBOOK =====
534 # let's go for the pure docbook, a reference type master for all man pages
537 def __init__(self, func):
538 """ initialize the fields needed for a man page entry - the fields are
539 named after the docbook-markup that encloses (!!) the text we store
540 the entries like X.refhint = "hello" will be printed therefore as
541 <refhint>hello</refhint>. Names with underscores are only used as
542 temporaries but they are memorized, perhaps for later usage. """
543 self.refhint = "\n<!--========= "+func.name+" (3) ===========-->\n"
545 self.refentry_date = o.version.strip() # //refentryinfo/date
546 self.refentry_productname = o.package.strip() # //refentryinfo/prod*
547 self.refentry_title = None # //refentryinfo/title
548 self.refentryinfo = None # override
549 self.manvolnum = "3" # //refmeta/manvolnum
550 self.refentrytitle = None # //refmeta/refentrytitle
551 self.refmeta = None # override
552 self.refpurpose = None # //refnamediv/refpurpose
553 self.refname = None # //refnamediv/refname
554 self.refname_list = []
555 self.refnamediv = None # override
556 self.mainheader = func.src.file.mainheader
557 self.includes = func.src.file.include
558 self.funcsynopsisinfo = "" # //funcsynopsisdiv/funcsynopsisinfo
559 self.funcsynopsis = None # //funcsynopsisdiv/funcsynopsis
560 self.funcsynopsis_list = []
561 self.description = None
562 self.description_list = []
564 self.authors_list = [] # //sect1[authors]/listitem
565 self.authors = None # override
566 self.copyright = None
567 self.copyright_list = []
569 self.seealso_list = []
571 self.seealso_list.append(func.seealso)
572 # func.func references
574 self.file_authors = None
575 if func.src.file.authors:
576 self.file_authors = func.src.file.authors
577 self.file_copyright = None
578 if func.src.file.copyright:
579 self.file_copyright = func.src.file.copyright
581 def refentryinfo_text(page):
582 """ the manvol formatter wants to render a footer line and header line
583 on each manpage and such info is set in <refentryinfo> """
584 if page.refentryinfo:
585 return page.refentryinfo
586 if page.refentry_date and \
587 page.refentry_productname and \
588 page.refentry_title: return (
589 "\n <date>"+page.refentry_date+"</date>"+
590 "\n <productname>"+page.refentry_productname+"</productname>"+
591 "\n <title>"+page.refentry_title+"</title>")
592 if page.refentry_date and \
593 page.refentry_productname: return (
594 "\n <date>"+page.refentry_date+"</date>"+
595 "\n <productname>"+page.refentry_productname+"</productname>")
597 def refmeta_text(page):
598 """ the manvol formatter needs to know the filename of the manpage to
599 be made up and these parts are set in <refmeta> actually """
602 if page.manvolnum and page.refentrytitle:
604 "\n <refentrytitle>"+page.refentrytitle+"</refentrytitle>"+
605 "\n <manvolnum>"+page.manvolnum+"</manvolnum>")
606 if page.manvolnum and page.func.name:
608 "\n <refentrytitle>"+page.func.name+"</refentrytitle>"+
609 "\n <manvolnum>"+page.manvolnum+"</manvolnum>")
611 def refnamediv_text(page):
612 """ the manvol formatter prints a header line with a <refpurpose> line
613 and <refname>'d functions that are described later. For each of
614 the <refname>s listed here, a mangpage is generated, and for each
615 of the <refname>!=<refentrytitle> then a symlink is created """
617 return page.refnamediv
618 if page.refpurpose and page.refname:
619 return ("\n <refname>"+page.refname+'</refname>'+
620 "\n <refpurpose>"+page.refpurpose+" </refpurpose>")
621 if page.refpurpose and page.refname_list:
623 for refname in page.refname_list:
624 T += "\n <refname>"+refname+'</refname>'
625 T += "\n <refpurpose>"+page.refpurpose+" </refpurpose>"
628 def funcsynopsisdiv_text(page):
629 """ refsynopsisdiv shall be between the manvol mangemaent information
630 and the reference page description blocks """
632 if page.funcsynopsis:
633 T += "\n<funcsynopsis>"
634 if page.funcsynopsisinfo:
635 T += "\n<funcsynopsisinfo>"+ page.funcsynopsisinfo + \
636 "\n</funcsynopsisinfo>\n"
637 T += page.funcsynopsis + \
638 "\n</funcsynopsis>\n"
639 if page.funcsynopsis_list:
640 T += "\n<funcsynopsis>"
641 if page.funcsynopsisinfo:
642 T += "\n<funcsynopsisinfo>"+ page.funcsynopsisinfo + \
643 "\n</funcsynopsisinfo>\n"
644 for funcsynopsis in page.funcsynopsis_list:
646 T += "\n</funcsynopsis>\n"
649 def description_text(page):
650 """ the description section on a manpage is the main part. Here
651 it is generated from the per-function comment area. """
653 return page.description
654 if page.description_list:
656 for description in page.description_list:
657 if not description: continue
661 def authors_text(page):
662 """ part of the footer sections on a manpage and a description of
663 original authors. We prever an itimizedlist to let the manvol
664 show a nice vertical aligment of authors of this ref item """
667 if page.authors_list:
670 for authors in page.authors_list:
671 if not authors: continue
672 if previous == authors: continue
673 T += "\n <listitem><para>"+authors+"</para></listitem>"
675 T += "</itemizedlist>"
680 def copyright_text(page):
681 """ the copyright section is almost last on a manpage and purely
682 optional. We list the part of the per-file copyright info """
684 return page.copyright
685 """ we only return the first valid instead of merging them """
686 if page.copyright_list:
688 for copyright in page.copyright_list:
689 if not copyright: continue
690 return copyright # !!!
692 def seealso_text(page):
693 """ the last section on a manpage is called 'SEE ALSO' usally and
694 contains a comma-separated list of references. Some manpage
695 viewers can parse these and convert them into hyperlinks """
698 if page.seealso_list:
700 for seealso in page.seealso_list:
701 if not seealso: continue
706 def refentry_text(page, id=None):
707 """ combine fields into a proper docbook refentry """
711 T = '<refentry id="'+id+'">'
713 T = '<refentry>' # this is an error
715 if page.refentryinfo_text():
716 T += "\n<refentryinfo>"+ page.refentryinfo_text()+ \
717 "\n</refentryinfo>\n"
718 if page.refmeta_text():
719 T += "\n<refmeta>"+ page.refmeta_text() + \
721 if page.refnamediv_text():
722 T += "\n<refnamediv>"+ page.refnamediv_text() + \
724 if page.funcsynopsisdiv_text():
725 T += "\n<refsynopsisdiv>\n"+ page.funcsynopsisdiv_text()+ \
726 "\n</refsynopsisdiv>\n"
727 if page.description_text():
728 T += "\n<refsect1><title>Description</title> " + \
729 page.description_text() + "\n</refsect1>"
730 if page.authors_text():
731 T += "\n<refsect1><title>Author</title> " + \
732 page.authors_text() + "\n</refsect1>"
733 if page.copyright_text():
734 T += "\n<refsect1><title>Copyright</title> " + \
735 page.copyright_text() + "\n</refsect1>\n"
736 if page.seealso_text():
737 T += "\n<refsect1><title>See Also</title><para> " + \
738 page.seealso_text() + "\n</para></refsect1>\n"
740 T += "\n</refentry>\n"
745 # -----------------------------------------------------------------------
746 class FunctionRefPage(RefPage):
748 """ here we parse the input function for its values """
750 page.refhint = "\n <!-- see "+page.func.into+" -->\n"
752 page.refentry = page.func.name # //refentry@id
753 page.refentry_title = page.func.name.strip() # //refentryinfo/title
754 page.refentrytitle = page.func.name # //refmeta/refentrytitle
756 page.funcsynopsisinfo += "\n"+page.includes
757 if not page.funcsynopsisinfo:
758 page.funcsynopsisinfo="\n"+' #include <'+page.mainheader+'>'
759 page.refpurpose = page.func.head
760 page.refname = page.func.name
762 def funcsynopsis_of(func):
764 "\n <funcprototype>\n <funcdef>"+func.prespec+
765 " <function>"+func.name+"</function></funcdef>"+
766 "\n"+s(s(s(func.callspec,
767 r"<parameters>\s*\(",r" "),
768 r"\)\s*</parameters>",r" "),
769 r"</paramdef>\s*,\s*",r"</paramdef>\n ")+
771 page.funcsynopsis = funcsynopsis_of(page.func)
774 html2docbook(this_function_link(page.func.body, page.func.name)))
776 if page.file_authors:
777 def add_authors(page, ename, email):
778 page.authors_list.append( ename+' '+email )
781 r"(?sx) \s* ([^<>]*) (<email>[^<>]*</email>) ", lambda x
782 : add_authors(page, x.group(1), x.group(2)))
785 if page.file_copyright:
786 page.copyright = "<screen>\n"+page.file_copyright+"</screen>\n"
789 def __init__(page,func):
790 RefPage.__init__(page, func)
791 FunctionRefPage.reinit(page)
793 def refpage_list_from_function_list(funclist):
796 for func in funclist:
797 mapp[func.name] = func
799 for func in funclist:
800 page = FunctionRefPage(func)
801 if func.into and func.into not in mapp:
802 warn (# ............ (refpage_list_from_function_list) .......
803 "page '"+page.func.name+"' has no target => "+
804 "'"+page.func.into+"'"
805 "\n: going to reset .into of Function '"+page.func.name+"'")
808 list.append(FunctionRefPage(func))
812 # ordered list of pages
813 refpage_list = refpage_list_from_function_list(function_list)
815 class FunctionFamilyRefPage(RefPage):
816 def __init__(self, page):
817 RefPage.__init__(self, page.func)
818 self.seealso_list = [] # reset
819 self.refhint_list = []
820 def refhint_list_text(page):
822 for hint in page.refhint_list:
825 def refentry_text(page):
826 return page.refhint_list_text() + "\n" + \
827 RefPage.refentry_text(page)
830 def docbook_pages_recombine(pagelist):
831 """ take a list of RefPages and create a new list where sections are
832 recombined in a way that their description is listed on the same
833 page and the manvol formatter creates symlinks to the combined
834 function description page - use the attribute 'into' to guide the
835 processing here as each of these will be removed from the output
836 list. If no into-pages are there then the returned list should
837 render to the very same output text like the input list would do """
841 for orig in pagelist:
842 if orig.func.into: continue
843 page = FunctionFamilyRefPage(orig)
844 combined[orig.func.name] = page ; list.append(page)
846 page.refentry = orig.refentry # //refentry@id
847 page.refentry_title = orig.refentrytitle # //refentryinfo/title
848 page.refentrytitle = orig.refentrytitle # //refmeta/refentrytitle
849 page.includes = orig.includes
850 page.funcsynopsisinfo = orig.funcsynopsisinfo
851 page.refpurpose = orig.refpurpose
853 page.refhint_list.append( orig.refhint )
855 page.refname_list.append( orig.refname )
856 elif orig.refname_list:
857 page.refname_list.extend( orig.refname_list )
858 if orig.funcsynopsis:
859 page.funcsynopsis_list.append( orig.funcsynopsis )
860 elif orig.refname_list:
861 page.funcsynopsis_list.extend( orig.funcsynopsis_list )
863 page.description_list.append( orig.description )
864 elif orig.refname_list:
865 page.description_list.extend( orig.description_list )
867 page.seealso_list.append( orig.seealso )
868 elif orig.seealso_list:
869 page.seealso_list.extend( orig.seealso_list )
871 page.authors_list.append( orig.authors )
872 elif orig.authors_list:
873 page.authors_list.extend( orig.authors_list )
875 page.copyright_list.append( orig.copyright )
876 elif orig.refname_list:
877 page.copyright_list.extend( orig.copyright_list )
879 for orig in pagelist:
880 if not orig.func.into: continue
881 if orig.func.into not in combined:
882 warn("page for '"+orig.func.name+
883 "' has no target => '"+orig.func.into+"'")
884 page = FunctionFamilyRefPage(orig)
886 page = combined[orig.func.into]
889 page.refname_list.append( orig.refname )
890 elif orig.refname_list:
891 page.refname_list.extend( orig.refname_list )
892 if orig.funcsynopsis:
893 page.funcsynopsis_list.append( orig.funcsynopsis )
894 elif orig.refname_list:
895 page.funcsynopsis_list.extend( orig.funcsynopsis_list )
897 page.description_list.append( orig.description )
898 elif orig.refname_list:
899 page.description_list.extend( orig.description_list )
901 page.seealso_list.append( orig.seealso )
902 elif orig.seealso_list:
903 page.seealso_list.extend( orig.seealso_list )
905 page.authors_list.append( orig.authors )
906 elif orig.authors_list:
907 page.authors_list.extend( orig.authors_list )
909 page.copyright_list.append( orig.copyright )
910 elif orig.refname_list:
911 page.copyright_list.extend( orig.copyright_list )
916 combined_pages = docbook_pages_recombine(pagelist = refpage_list)
918 # -----------------------------------------------------------------------
920 class HeaderRefPage(RefPage):
923 def docbook_refpages_perheader(page_list): # headerlist
924 " creating the per-header manpage - a combination of function man pages "
926 for page in page_list:
927 assert not page.func.into
928 file = page.func.src.file.mainheader # short for the mainheader index
929 if file not in header:
930 header[file] = HeaderRefPage(page.func)
931 header[file].id = s(file, r"[^\w\.]","-")
932 header[file].refentry = header[file].id
933 header[file].refentryinfo = None
934 header[file].refentry_date = page.refentry_date
935 header[file].refentry_productname = (
936 "the library "+page.refentry_productname)
937 header[file].manvolnum = page.manvolnum
938 header[file].refentrytitle = file
939 header[file].funcsynopsis = ""
940 if 1: # or += or if not header[file].refnamediv:
941 header[file].refpurpose = " library "
942 header[file].refname = header[file].id
944 if not header[file].funcsynopsisinfo and page.funcsynopsisinfo:
945 header[file].funcsynopsisinfo = page.funcsynopsisinfo
946 if page.funcsynopsis:
947 header[file].funcsynopsis += "\n"+page.funcsynopsis
948 if not header[file].copyright and page.copyright:
949 header[file].copyright = page.copyright
950 if not header[file].authors and page.authors:
951 header[file].authors = page.authors
952 if not header[file].authors and page.authors_list:
953 header[file].authors_list = page.authors_list
954 if not header[file].description:
955 found = m(commands.getoutput("cat "+o.package+".spec"),
956 r"(?s)\%description\b([^\%]*)\%")
958 header[file].description = found.group(1)
959 elif not header[file].description:
960 header[file].description = "<para>" + (
961 page.refentry_productname + " library") + "</para>";
968 def leaders(pagelist):
970 for page in pagelist:
971 if page.func.into : continue
974 header_refpages = docbook_refpages_perheader(leaders(refpage_list))
976 # -----------------------------------------------------------------------
977 # printing the docbook file is a two-phase process - we spit out the
978 # leader pages first - later we add more pages with _refstart pointing
979 # to the leader page, so that xmlto will add the functions there. Only the
980 # leader page contains some extra info needed for troff page processing.
982 doctype = '<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"'
984 doctype += '"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">'+"\n"
987 F = open(o.docbookfile,"w")
988 except IOError, error:
989 warn("can not open docbook output file: "+o.docbookfile, error)
991 print >> F, doctype, '<reference><title>Manual Pages</title>'
993 for page in combined_pages:
994 print >> F, page.refentry_text()
997 for page in header_refpages.values():
998 if not page.refentry: continue
999 print >> F, "\n<!-- _______ "+page.id+" _______ -->",
1000 print >> F, page.refentry_text()
1003 print >> F, "\n",'</reference>',"\n"
1007 # _____________________________________________________________________
1009 F = open( o.dumpdocfile, "w")
1010 except IOError, error:
1011 warn ("can not open"+o.dumpdocfile,error)
1013 for func in function_list:
1015 print >> F, "<fn id=\""+name+"\">"+"<!-- FOR \""+name+"\" -->\n"
1016 for H in sorted_keys(func.dict()):
1017 print >> F, "<"+H+" name=\""+name+"\">",
1018 print >> F, str(func.dict()[H]),
1019 print >> F, "</"+H+">"
1021 print >> F, "</fn><!-- END \""+name+"\" -->\n\n";
1026 if errors: sys.exit(errors)