2 # -*- coding: UTF-8 -*-
10 def warn(msg
, error
=None):
14 warnings
.warn("-- "+str(errors
)+" --\n "+msg
, RuntimeWarning, 2)
16 warnings
.warn("-- "+str(errors
)+" --\n "+msg
+
17 "\n error was "+str(error
), RuntimeWarning, 2)
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):
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 """
34 s(s(s(s(s(s(s(s(s(s(s(text
,
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>"),
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>" }
62 text
= string
.replace(text
, str, mapping
[str])
65 return section2html(paramdef2html(text
))
67 return string
.replace(text
, "&", "&")
69 return string
.replace(string
.replace(text
, "<","<"), ">",">")
71 return cdata31(cdata1(text
))
73 return string
.replace(text
,"\"", """)
75 return cdata43(cdata31(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 """
86 r
"(?s){<([\w\.\-]+\@[\w\.\-]+\w\w)>",
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) \<\;([^<>\&\;]+\@[^<>\&\;]+)\>\; ",
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
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
"<"), r
">>",r
">"),
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 """
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 # -----------------------------------------------------------------------
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
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
"
151 o.mainheader = o.package+".h
"
154 def __init__(self, filename):
156 self.mainheader = o.mainheader
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):
168 def set_copyright(self, text):
169 self.copyright = text
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
178 # the id will tell us in which order
179 # we did meet each function definition
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)
189 id = self.id ; self.id += 1
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"<
;\
1>
;")
198 func.prototype = prototype
199 func.id = all.next_id()
200 self.funcs.append(func)
204 def scan_options (options, list):
206 return s(s(text, r"¬
", r"&#AC;"), r"\*/",r"¬")
208 return s(text
, r
"¬", r
"*/")
211 found
= m(name
, r
"^(\w+)=(.*)")
213 o
.var
[found
.group(1)] = found
.group(2)
217 input = open(name
, "r")
218 except IOError, error
:
219 warn(#...... (scan_options) ...............
220 "can not open input file: "+name
, error
)
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]*)?)")
237 file.comment
= decode(found
.group(1))
238 file.include
= cdata31(found
.group(2))
242 found
= m(text
, r
"(?sx) ^ [/][*]+(?=\s) ([^¬]+) ¬ ")
244 file.comment
= decode(found
.group(1))
246 # throw away the rest - further processing on memorized strings only
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):
265 if file.comment
is None: continue
266 file.section
= file_comment2section(file.comment
)
269 file.section
, r
"(?sx) \b[Aa]uthor\s*:(.*</email>) ", lambda x
270 : "<author>" + file.set_author(x
.group(1)) + "</author>")
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 # -----------------------------------------------------------------------
281 " <prespec>void* </><namespec>hello</><namespec> (int) const</callspec> "
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]
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
301 def dict_sorted_keys(self
):
302 keys
= self
.__dict
__.keys()
305 def parse(self
, prototype
):
306 found
= m(prototype
, r
"(?sx) ^(.*[^.]) \b(\w[\w.]*\w)\b (\s*\(.*) $ ")
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()
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
):
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 """
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
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
)
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
:
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
):
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
:
393 def __init__(self
, func
):
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\"> </td>\n"+
400 " <td valign=\"top\"><a href=\"#"+func
.name
+"\">\n"+
401 " <code>"+func
.namespec
+"</code>"+
403 " <td valign=\"top\"> </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 " <code>"+func
.callspec
+"</code>\n")
409 self
.anchor
= "<a name=\""+func
.name
+"\" />"
410 self
.section
= "<para><em> "+func
.head
+"\n"+ \
411 "\n</em></para>"+section2html(func
.body
)
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)
432 def combined_html_pages(func_list
):
433 """ and now add descriptions of non-leader entries (html-mode) """
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
)
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>"
468 return "<a href=\"#"+name
+"\"><code>"+name
+extra
+"</code></a>"
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>-></small>") # just sanitize..
473 #fu html_resolve_links
479 self
.package
= o
.package
480 self
.version
= o
.version
482 """ render .toc and .txt parts into proper <html> page """
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>"
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"
496 def add_page_map(self
, list):
497 """ generate the index-block at the start of the onepage-html file """
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>"+
510 def add_page_list(self
, functions
):
511 """ generate the index-block at the start of the onepage-html file """
513 for func
in functions
:
514 mapp
[func
.name
] = func
516 self
.add_page_map(mapp
)
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
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
)
531 print >> F
, html
.page_text()
535 # ========================================================== DOCBOOK =====
536 # let's go for the pure docbook, a reference type master for all man pages
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"
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
= []
566 self
.authors_list
= [] # //sect1[authors]/listitem
567 self
.authors
= None # override
568 self
.copyright
= None
569 self
.copyright_list
= []
571 self
.seealso_list
= []
573 self
.seealso_list
.append(func
.seealso
)
574 # func.func references
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>")
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 """
604 if page
.manvolnum
and page
.refentrytitle
:
606 "\n <refentrytitle>"+page
.refentrytitle
+"</refentrytitle>"+
607 "\n <manvolnum>"+page
.manvolnum
+"</manvolnum>")
608 if page
.manvolnum
and page
.func
.name
:
610 "\n <refentrytitle>"+page
.func
.name
+"</refentrytitle>"+
611 "\n <manvolnum>"+page
.manvolnum
+"</manvolnum>")
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 """
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
:
625 for refname
in page
.refname_list
:
626 T
+= "\n <refname>"+refname
+'</refname>'
627 T
+= "\n <refpurpose>"+page
.refpurpose
+" </refpurpose>"
630 def funcsynopsisdiv_text(page
):
631 """ refsynopsisdiv shall be between the manvol mangemaent information
632 and the reference page description blocks """
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
:
648 T
+= "\n</funcsynopsis>\n"
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. """
655 return page
.description
656 if page
.description_list
:
658 for description
in page
.description_list
:
659 if not description
: continue
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 """
669 if page
.authors_list
:
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>"
677 T
+= "</itemizedlist>"
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 """
686 return page
.copyright
687 """ we only return the first valid instead of merging them """
688 if page
.copyright_list
:
690 for copyright
in page
.copyright_list
:
691 if not copyright
: continue
692 return copyright
# !!!
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 """
700 if page
.seealso_list
:
702 for seealso
in page
.seealso_list
:
703 if not seealso
: continue
708 def refentry_text(page
, id=None):
709 """ combine fields into a proper docbook refentry """
713 T
= '<refentry id="'+id+'">'
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() + \
723 if page
.refnamediv_text():
724 T
+= "\n<refnamediv>"+ page
.refnamediv_text() + \
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"
747 # -----------------------------------------------------------------------
748 class FunctionRefPage(RefPage
):
750 """ here we parse the input function for its values """
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
758 page
.funcsynopsisinfo
+= "\n"+page
.includes
759 if not page
.funcsynopsisinfo
:
760 page
.funcsynopsisinfo
="\n"+' #include <'+page
.mainheader
+'>'
761 page
.refpurpose
= page
.func
.head
762 page
.refname
= page
.func
.name
764 def funcsynopsis_of(func
):
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 ")+
773 page
.funcsynopsis
= funcsynopsis_of(page
.func
)
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
)
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"
791 def __init__(page
,func
):
792 RefPage
.__init
__(page
, func
)
793 FunctionRefPage
.reinit(page
)
795 def refpage_list_from_function_list(funclist
):
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
+"'")
810 list.append(FunctionRefPage(func
))
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
):
824 for hint
in page
.refhint_list
:
827 def refentry_text(page
):
828 return page
.refhint_list_text() + "\n" + \
829 RefPage
.refentry_text(page
)
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 """
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
855 page
.refhint_list
.append( orig
.refhint
)
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
)
865 page
.description_list
.append( orig
.description
)
866 elif orig
.refname_list
:
867 page
.description_list
.extend( orig
.description_list
)
869 page
.seealso_list
.append( orig
.seealso
)
870 elif orig
.seealso_list
:
871 page
.seealso_list
.extend( orig
.seealso_list
)
873 page
.authors_list
.append( orig
.authors
)
874 elif orig
.authors_list
:
875 page
.authors_list
.extend( orig
.authors_list
)
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
)
888 page
= combined
[orig
.func
.into
]
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
)
899 page
.description_list
.append( orig
.description
)
900 elif orig
.refname_list
:
901 page
.description_list
.extend( orig
.description_list
)
903 page
.seealso_list
.append( orig
.seealso
)
904 elif orig
.seealso_list
:
905 page
.seealso_list
.extend( orig
.seealso_list
)
907 page
.authors_list
.append( orig
.authors
)
908 elif orig
.authors_list
:
909 page
.authors_list
.extend( orig
.authors_list
)
911 page
.copyright_list
.append( orig
.copyright
)
912 elif orig
.refname_list
:
913 page
.copyright_list
.extend( orig
.copyright_list
)
918 combined_pages
= docbook_pages_recombine(pagelist
= refpage_list
)
920 # -----------------------------------------------------------------------
922 class HeaderRefPage(RefPage
):
925 def docbook_refpages_perheader(page_list
): # headerlist
926 " creating the per-header manpage - a combination of function man pages "
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([^\%]*)\%")
960 header
[file].description
= found
.group(1)
961 elif not header
[file].description
:
962 header
[file].description
= "<para>" + (
963 page
.refentry_productname
+ " library") + "</para>";
970 def leaders(pagelist
):
972 for page
in pagelist
:
973 if page
.func
.into
: continue
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"'
986 doctype
+= '"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">'+"\n"
989 F
= open(o
.docbookfile
,"w")
990 except IOError, error
:
991 warn("can not open docbook output file: "+o
.docbookfile
, error
)
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"
1009 # _____________________________________________________________________
1011 F
= open( o
.dumpdocfile
, "w")
1012 except IOError, error
:
1013 warn ("can not open"+o
.dumpdocfile
,error
)
1015 for func
in function_list
:
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";
1028 if errors
: sys
.exit(errors
)