3 ## Copyright (c) 2003 Simon Josefsson ##
4 ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ##
5 ## hacked to allow -tex option --nmav ##
6 ## hacked to allow -texinfo option --jas ##
8 ## This software falls under the GNU Public License. Please read ##
9 ## the COPYING file for more information ##
12 # This will read a 'c' file and scan for embedded comments in the
13 # style of gnome comments (+minor extensions - see below).
15 # This program is modified by Nikos Mavroyanopoulos, for the gnutls
18 # Note: This only supports 'c'.
21 # gdoc [ -docbook | -html | -text | -man | -tex | -texinfo ]
22 # [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile
24 # Set output format using one of -docbook -html -text -man -tex or
25 # -texinfo. Default is man.
28 # If set, then only generate documentation for the given
29 # function(s). All other functions are ignored.
31 # c files - list of 'c' files to process
33 # All output goes to stdout, with errors to stderr.
37 # In the following table, (...)? signifies optional structure.
38 # (...)* signifies 0 or more structure elements
40 # * function_name(:)? (- short description)?
41 # (* @parameterx: (description of parameter x)?)*
43 # * (Description:)? (Description of function)?
44 # * (section header: (section description)? )*
47 # So .. the trivial example would be:
53 # If the Description: header tag is ommitted, then there must be a blank line
54 # after the last parameter specification.
57 # * my_function - does my stuff
58 # * @my_arg: its mine damnit
60 # * Does my stuff explained.
65 # * my_function - does my stuff
66 # * @my_arg: its mine damnit
67 # * Description: Does my stuff explained.
71 # All descriptions can be multiline, apart from the short function description.
73 # All descriptive text is further processed, scanning for the following special
74 # patterns, which are highlighted appropriately.
76 # 'funcname()' - function
77 # '$ENVVAR' - environmental variable
78 # '&struct_name' - name of a structure
79 # '@parameter' - name of a parameter
80 # '%CONST' - name of a constant.
83 # Extensions for LaTeX:
85 # 1. the symbol '->' will be replaced with a rightarrow
86 # 2. x^y with ${x}^{y}$.
89 use POSIX
qw(strftime);
91 # match expressions used to find embedded type information
92 $type_constant = "\\\%(\\w+)";
93 $type_func = "(\\w+\\(\\))";
94 #$type_func = "(\\(w||\\\\)+\\(\\))";
95 $type_param = "\\\@(\\w+)";
96 $type_struct = "\\\&(\\w+)";
97 $type_env = "(\\\$\\w+)";
100 # Output conversion substitutions.
101 # One for each output format
103 # these work fairly well
104 %highlights_html = ( $type_constant, "<i>\$1</i>",
105 $type_func, "<b>\$1</b>",
106 $type_struct, "<i>\$1</i>",
107 $type_param, "<tt><b>\$1</b></tt>" );
108 $blankline_html = "<p>";
111 %highlights_texinfo = ( $type_constant, "CMDvar{\$1}",
112 $type_func, "CMDcode{\$1}",
113 $type_struct, "CMDcode{\$1}",
114 $type_param, "CMDcode\{\$1\}" );
115 $blankline_texinfo = "";
117 %highlights_tex = ( $type_constant, "{\\\\it \$1}",
118 $type_func, "{\\\\bf \$1}",
119 $type_struct, "{\\\\it \$1}",
120 $type_param, "{\\\\bf \$1}" );
121 $blankline_tex = "\\par";
123 # sgml, docbook format
124 %highlights_sgml = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
125 $type_func, "<function>\$1</function>",
126 $type_struct, "<structname>\$1</structname>",
127 $type_env, "<envar>\$1</envar>",
128 $type_param, "<parameter>\$1</parameter>" );
129 $blankline_sgml = "</para><para>\n";
131 # these are pretty rough
132 %highlights_man = ( $type_constant, "\\n.I \\\"\$1\\\"\\n",
133 $type_func, "\\n.B \\\"\$1\\\"\\n",
134 $type_struct, "\\n.I \\\"\$1\\\"\\n",
135 $type_param."([\.\, ]*)\n?", "\\n.I \\\"\$1\$2\\\"\\n" );
139 %highlights_text = ( $type_constant, "\$1",
142 $type_param, "\$1" );
143 $blankline_text = "";
147 print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -tex | -texinfo ]\n";
148 print " [ -function funcname [ -function funcname ...] ]\n";
149 print " c source file(s) > outputfile\n";
159 $output_mode = "man";
160 %highlights = %highlights_man;
161 $blankline = $blankline_man;
162 $modulename = "API Documentation";
163 $version = strftime
"%Y-%m-%d", localtime;
165 while ($ARGV[0] =~ m/^-(.*)/) {
167 if ($cmd eq "-html") {
168 $output_mode = "html";
169 %highlights = %highlights_html;
170 $blankline = $blankline_html;
171 } elsif ($cmd eq "-man") {
172 $output_mode = "man";
173 %highlights = %highlights_man;
174 $blankline = $blankline_man;
175 } elsif ($cmd eq "-tex") {
176 $output_mode = "tex";
177 %highlights = %highlights_tex;
178 $blankline = $blankline_tex;
179 } elsif ($cmd eq "-texinfo") {
180 $output_mode = "texinfo";
181 %highlights = %highlights_texinfo;
182 $blankline = $blankline_texinfo;
183 } elsif ($cmd eq "-text") {
184 $output_mode = "text";
185 %highlights = %highlights_text;
186 $blankline = $blankline_text;
187 } elsif ($cmd eq "-docbook") {
188 $output_mode = "sgml";
189 %highlights = %highlights_sgml;
190 $blankline = $blankline_sgml;
191 } elsif ($cmd eq "-module") { # not needed for sgml, inherits from calling document
192 $modulename = shift @ARGV;
193 } elsif ($cmd eq "-version") {
194 $version = shift @ARGV;
195 } elsif ($cmd eq "-function") { # to only output specific functions
197 $function = shift @ARGV;
198 $function_table{$function} = 1;
199 } elsif ($cmd eq "-v") {
201 } elsif (($cmd eq "-h") || ($cmd eq "--help")) {
207 # generate a sequence of code that will splice in highlighting information
208 # using the s// operator.
210 foreach $pattern (keys %highlights) {
211 # print STDERR "scanning pattern $pattern ($highlights{$pattern})\n";
212 $dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n";
216 # dumps section contents to arrays/hashes intended for that purpose.
220 my $contents = join "\n", @_;
222 if ($name =~ m/$type_constant/) {
224 # print STDERR "constant section '$1' = '$contents'\n";
225 $constants{$name} = $contents;
226 } elsif ($name =~ m/$type_param/) {
227 # print STDERR "parameter def '$1' = '$contents'\n";
229 $parameters{$name} = $contents;
231 # print STDERR "other section '$name' = '$contents'\n";
232 $sections{$name} = $contents;
233 push @sectionlist, $name;
240 # parameters, a hash.
241 # function => "function name"
242 # parameterlist => @list of parameters
243 # parameters => %parameter descriptions
244 # sectionlist => @list of sections
245 # sections => %descriont descriptions
248 sub output_highlight
{
249 my $contents = join "\n", @_;
252 if (substr($contents, 0, 1) eq " ") {
253 $contents = substr($contents, 1);
256 $contents =~ s
:{:\@
{:gs
if ($output_mode eq "texinfo");
257 $contents =~ s
:}:\@
}:gs
if ($output_mode eq "texinfo");
259 $contents =~ s
:CMD
:@
:gs
if ($output_mode eq "texinfo");
260 foreach $line (split "\n", $contents) {
262 print $lineprefix, $blankline;
264 print $lineprefix, $line;
273 my ($parameter, $section);
276 print "\@deftypefun {";
277 print $args{'functiontype'};
278 print "} ".$args{'function'}." ";
281 foreach $parameter (@
{$args{'parameterlist'}}) {
282 print $args{'parametertypes'}{$parameter}." \@var{".$parameter."}";
283 if ($count != $#{$args{'parameterlist'}}) {
289 foreach $parameter (@
{$args{'parameterlist'}}) {
290 if ($args{'parameters'}{$parameter}) {
291 print "\@var{".$parameter."}: ";
292 output_highlight
($args{'parameters'}{$parameter});
296 foreach $section (@
{$args{'sectionlist'}}) {
297 output_highlight
($args{'sections'}{$section});
300 print "\@end deftypefun\n\n";
306 my ($parameter, $section);
308 print "\n\n<a name=\"". $args{'function'} . "\"> </a><h2>Function</h2>\n";
310 print "<i>".$args{'functiontype'}."</i>\n";
311 print "<b>".$args{'function'}."</b>\n";
314 foreach $parameter (@
{$args{'parameterlist'}}) {
315 print "<i>".$args{'parametertypes'}{$parameter}."</i> <b>".$parameter."</b>\n";
316 if ($count != $#{$args{'parameterlist'}}) {
323 print "<h3>Arguments</h3>\n";
325 foreach $parameter (@
{$args{'parameterlist'}}) {
326 print "<dt><i>".$args{'parametertypes'}{$parameter}."</i> <b>".$parameter."</b>\n";
328 output_highlight
($args{'parameters'}{$parameter});
331 foreach $section (@
{$args{'sectionlist'}}) {
332 print "<h3>$section</h3>\n";
334 output_highlight
($args{'sections'}{$section});
343 my ($parameter, $section);
345 my $func = $args{'function'};
354 print "\n\n\\subsection{". $func . "}\n\\label{" . $args{'function'} . "}\n";
356 $type = $args{'functiontype'};
359 print "{\\it ".$type."}\n";
360 print "{\\bf ".$func."}\n";
363 foreach $parameter (@
{$args{'parameterlist'}}) {
364 $param = $args{'parametertypes'}{$parameter};
365 $param2 = $parameter;
367 $param2 =~ s/_/\\_/g;
369 print "{\\it ".$param."} {\\bf ".$param2."}\n";
370 if ($count != $#{$args{'parameterlist'}}) {
377 print "\n{\\large{Arguments}}\n";
379 print "\\begin{itemize}\n";
381 foreach $parameter (@
{$args{'parameterlist'}}) {
382 $param1 = $args{'parametertypes'}{$parameter};
383 $param1 =~ s/_/\\_/g;
384 $param2 = $parameter;
385 $param2 =~ s/_/\\_/g;
388 print "\\item {\\it ".$param1."} {\\bf ".$param2."}: \n";
391 $param3 = $args{'parameters'}{$parameter};
392 $param3 =~ s/_/\\_/g;
393 $param3 =~ s/&([a-zA-Z\_]+)/{\\it \1}/g;
395 output_highlight
($param3);
398 print "\\item void\n";
400 print "\\end{itemize}\n";
402 foreach $section (@
{$args{'sectionlist'}}) {
405 $sec =~ s/&([a-zA-Z\_]+)/{\\it \1}/g;
407 print "\n\\par{\\large{$sec}}\\par\n";
408 print "\\begin{rmfamily}\n";
410 $sec = $args{'sections'}{$section};
413 $sec =~ s/&([a-zA-Z\_]+)/{\\it \1}/g;
414 $sec =~ s/->/\$\\rightarrow\$/g;
415 $sec =~ s/([0-9]+)\^([0-9]+)/\$\{\1\}\^\{\2\}\$/g;
417 output_highlight
($sec);
418 print "\\end{rmfamily}\n";
424 # output in sgml DocBook
427 my ($parameter, $section);
431 $id = $args{'module'}."-".$args{'function'};
432 $id =~ s/[^A-Za-z0-9]/-/g;
434 print "<refentry>\n";
436 print "<refentrytitle><phrase id=\"$id\">".$args{'function'}."</phrase></refentrytitle>\n";
437 print "</refmeta>\n";
438 print "<refnamediv>\n";
439 print " <refname>".$args{'function'}."</refname>\n";
440 print " <refpurpose>\n";
441 print " ".$args{'purpose'}."\n";
442 print " </refpurpose>\n";
443 print "</refnamediv>\n";
445 print "<refsynopsisdiv>\n";
446 print " <title>Synopsis</title>\n";
447 print " <funcsynopsis>\n";
448 print " <funcdef>".$args{'functiontype'}." ";
449 print "<function>".$args{'function'}." ";
450 print "</function></funcdef>\n";
452 # print "<refsect1>\n";
453 # print " <title>Synopsis</title>\n";
454 # print " <funcsynopsis>\n";
455 # print " <funcdef>".$args{'functiontype'}." ";
456 # print "<function>".$args{'function'}." ";
457 # print "</function></funcdef>\n";
460 if ($#{$args{'parameterlist'}} >= 0) {
461 foreach $parameter (@
{$args{'parameterlist'}}) {
462 print " <paramdef>".$args{'parametertypes'}{$parameter};
463 print " <parameter>$parameter</parameter></paramdef>\n";
468 print " </funcsynopsis>\n";
469 print "</refsynopsisdiv>\n";
470 # print "</refsect1>\n";
473 print "<refsect1>\n <title>Arguments</title>\n";
474 # print "<para>\nArguments\n";
475 if ($#{$args{'parameterlist'}} >= 0) {
476 print " <variablelist>\n";
477 foreach $parameter (@
{$args{'parameterlist'}}) {
478 print " <varlistentry>\n <term><parameter>$parameter</parameter></term>\n";
479 print " <listitem>\n <para>\n";
481 output_highlight
($args{'parameters'}{$parameter});
482 print " </para>\n </listitem>\n </varlistentry>\n";
484 print " </variablelist>\n";
486 print " <para>\n None\n </para>\n";
488 print "</refsect1>\n";
490 # print out each section
492 foreach $section (@
{$args{'sectionlist'}}) {
493 print "<refsect1>\n <title>$section</title>\n <para>\n";
494 # print "<para>\n$section\n";
495 if ($section =~ m/EXAMPLE/i) {
496 print "<example><para>\n";
498 output_highlight
($args{'sections'}{$section});
500 if ($section =~ m/EXAMPLE/i) {
501 print "</para></example>\n";
503 print " </para>\n</refsect1>\n";
513 my ($parameter, $section);
516 print ".TH \"$args{'function'}\" 3 \"$args{'version'}\" \"GNU\" \"". uc($args{'module'}) . "\"\n";
520 print $args{'function'}."\n";
522 print ".SH SYNOPSIS\n";
523 print ".B #include <". lc($args{'module'}) . ".h>\n";
525 print ".BI \"".$args{'functiontype'}." ".$args{'function'}."(";
527 foreach $parameter (@
{$args{'parameterlist'}}) {
528 print $args{'parametertypes'}{$parameter}." \" ".$parameter." \"";
529 if ($count != $#{$args{'parameterlist'}}) {
536 print ".SH ARGUMENTS\n";
537 foreach $parameter (@
{$args{'parameterlist'}}) {
538 print ".IP \"".$args{'parametertypes'}{$parameter}." ".$parameter."\" 12\n";
539 output_highlight
($args{'parameters'}{$parameter});
541 foreach $section (@
{$args{'sectionlist'}}) {
542 print ".SH \"" . uc($section) . "\"\n";
543 output_highlight
($args{'sections'}{$section});
545 print ".SH \"REPORTING BUGS\"\n";
546 print "Report bugs to <bug-shishi\@josefsson.org>.\n";
547 print ".SH COPYRIGHT\n";
548 print "Copyright \\(co 2002, 2003 Simon Josefsson.\n";
550 print "Permission is granted to copy, distribute and/or modify this document\n";
551 print "under the terms of the GNU Free Documentation License, Version 1.1\n";
552 print "or any later version published by the Free Software Foundation.\n";
553 print ".SH \"SEE ALSO\"\n";
554 print "The full documentation for\n";
555 print ".B " . ucfirst($args{'module'}) . "\n";
556 print "is maintained as a Texinfo manual. If the\n";
559 print ".B " . lc($args{'module'}) . "\n";
560 print "programs are properly installed at your site, the command\n";
562 print ".B info " . lc($args{'module'}) . "\n";
564 print "should give you access to the complete manual.\n";
571 my ($parameter, $section);
573 print "Function = ".$args{'function'}."\n";
574 print " return type: ".$args{'functiontype'}."\n\n";
575 foreach $parameter (@
{$args{'parameterlist'}}) {
576 print " ".$args{'parametertypes'}{$parameter}." ".$parameter."\n";
577 print " -> ".$args{'parameters'}{$parameter}."\n";
579 foreach $section (@
{$args{'sectionlist'}}) {
580 print " $section:\n";
582 output_highlight
($args{'sections'}{$section});
587 # generic output function - calls the right one based
588 # on current output mode.
589 sub output_function
{
591 eval "output_".$output_mode."(\@_);";
596 # takes a function prototype and spits out all the details
597 # stored in the global arrays/hsahes.
599 my $prototype = shift @_;
601 if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
602 $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
603 $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
604 $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
605 $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/) {
610 # print STDERR "ARGS = '$args'\n";
612 foreach $arg (split ',', $args) {
613 # strip leading/trailing spaces
616 # print STDERR "SCAN ARG: '$arg'\n";
617 @args = split('\s', $arg);
619 # print STDERR " -> @args\n";
621 # print STDERR " -> @args\n";
622 if ($param =~ m/^(\*+)(.*)/) {
626 $type = join " ", @args;
628 if ($parameters{$param} eq "" && $param != "void") {
629 $parameters{$param} = "-- undescribed --";
630 print STDERR
"Warning($lineno): Function parameter '$param' not described in '$function_name'\n";
633 push @parameterlist, $param;
634 $parametertypes{$param} = $type;
636 # print STDERR "param = '$param', type = '$type'\n";
639 print STDERR
"Error($lineno): cannot understand prototype: '$prototype'\n";
643 if ($function_only==0 || defined($function_table{$function_name})) {
644 output_function
({'function' => $function_name,
645 'module' => $modulename,
646 'version' => $version,
647 'functiontype' => $return_type,
648 'parameterlist' => \
@parameterlist,
649 'parameters' => \
%parameters,
650 'parametertypes' => \
%parametertypes,
651 'sectionlist' => \
@sectionlist,
652 'sections' => \
%sections,
653 'purpose' => $function_purpose
658 ######################################################################
662 # 1 - looking for function name
663 # 2 - scanning field start.
664 # 3 - scanning prototype.
668 $doc_special = "\@\%\$\&";
670 $doc_start = "^/\\*\\*\$";
672 $doc_com = "\\s*\\*\\s*";
673 $doc_func = $doc_com."(\\w+):?";
674 $doc_sect = $doc_com."([".$doc_special."]?[\\w ]+):(.*)";
675 $doc_content = $doc_com."(.*)";
684 $section_default = "Description"; # default section
685 $section = $section_default;
688 foreach $file (@ARGV) {
689 if (!open(IN
,"<$file")) {
690 print STDERR
"Error: Cannot open file $file\n";
698 $state = 1; # next line is always the function name
700 } elsif ($state == 1) { # this line is the function name (always)
705 $function_purpose = $1;
707 $function_purpose = "";
710 print STDERR
"Info($lineno): Scanning doc for $function\n";
713 print STDERR
"WARN($lineno): Cannot understand $_ on line $lineno",
714 " - I thought it was a doc line\n";
717 } elsif ($state == 2) { # look for head: lines, and include content
722 if ($contents ne "") {
723 dump_section
($section, $contents);
724 $section = $section_default;
727 $contents = $newcontents;
728 if ($contents ne "") {
731 $section = $newsection;
732 } elsif (/$doc_end/) {
734 if ($contents ne "") {
735 dump_section
($section, $contents);
736 $section = $section_default;
740 # print STDERR "end of doc comment, looking for prototype\n";
743 } elsif (/$doc_content/) {
744 # miguel-style comment kludge, look for blank lines after
745 # @parameter line to signify start of description
746 if ($1 eq "" && $section =~ m/^@/) {
747 dump_section
($section, $contents);
748 $section = $section_default;
751 $contents .= $1."\n";
754 # i dont know - bad line? ignore.
755 print STDERR
"WARNING($lineno): bad line: $_";
757 } elsif ($state == 3) { # scanning for function { (end of prototype)
758 if (m
#\s*/\*\s+MACDOC\s*#io) {
765 $prototype =~ s@
/\*.*?\*/@
@gos; # strip comments.
766 $prototype =~ s@
[\r\n]+@
@gos; # strip newlines/cr's.
767 $prototype =~ s@
^ +@
@gos; # strip leading spaces
768 dump_function
($prototype);
773 %parametertypes = ();