xref: /openbsd/gnu/usr.bin/texinfo/util/gdoc (revision 771fbea0)
1#!/usr/bin/perl
2
3## Copyright (c) 2002, 2003 Simon Josefsson                      ##
4##                    added -texinfo, -listfunc                  ##
5##                    man page revamp                            ##
6##                    various improvements                       ##
7## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
8##                    hacked to allow -tex option --nmav         ##
9##                                                               ##
10## This software falls under the GNU Public License. Please read ##
11##              the COPYING file for more information            ##
12
13#
14# This will read a 'c' file and scan for embedded comments in the
15# style of gnome comments (+minor extensions - see below).
16#
17# This program is modified by Nikos Mavroyanopoulos, for the gnutls
18# project.
19
20# Note: This only supports 'c'.
21
22# usage:
23# gdoc [ -docbook | -html | -text | -man | -tex | -texinfo | -listfunc ]
24#      [ -sourceversion verno ] [ -includefuncprefix ] [ -bugsto address ]
25#      [ -seeinfo infonode ] [ -copyright notice ] [ -verbatimcopying ]
26#      [ -function funcname [ -function funcname ...] ] c file(s)s > outputfil
27e
28#
29#  Set output format using one of -docbook, -html, -text, -man, -tex,
30#  -texinfo, or -listfunc.  Default is man.
31#
32#  -sourceversion
33#       Version number for source code, e.g. '1.0.4'.  Used in 'man' headers.
34#       Defaults to using current date.
35#
36#  -includefuncprefix
37#       For man pages, generate a #include <FILE.h> based on the function
38#       prefix.  For example, a function gss_init_sec_context will generate
39#       an include statement of #include <gss.h>.
40#
41#  -bugsto address
42#       For man pages, include a section about reporting bugs and mention
43#       the given e-mail address, e.g 'bug-libidn@gnu.org'.
44#
45#  -seeinfo infonode
46#       For man pages, include a section that point to an info manual
47#       for more information.
48#
49#  -copyright notice
50#       For man pages, include a copyright section with the given
51#       notice after a preamble.  Use, e.g., '2002, 2003 Simon Josefsson'.
52#
53#  -verbatimcopying
54#       For man pages, and when the -copyright parameter is used,
55#       add a licensing statement that say verbatim copying is permitted.
56#
57#  -function funcname
58#       If set, then only generate documentation for the given function(s).  A
59ll
60#       other functions are ignored.
61#
62#  c files - list of 'c' files to process
63#
64#  All output goes to stdout, with errors to stderr.
65
66#
67# format of comments.
68# In the following table, (...)? signifies optional structure.
69#                         (...)* signifies 0 or more structure elements
70# /**
71#  * function_name(:)? (- short description)?
72# (* @parameterx: (description of parameter x)?)*
73# (* a blank line)?
74#  * (Description:)? (Description of function)?
75#  * (Section header: (section description)? )*
76#  (*)?*/
77#
78# So .. the trivial example would be:
79#
80# /**
81#  * my_function
82#  **/
83#
84# If the Description: header tag is ommitted, then there must be a blank line
85# after the last parameter specification.
86# e.g.
87# /**
88#  * my_function - does my stuff
89#  * @my_arg: its mine damnit
90#  *
91#  * Does my stuff explained.
92#  */
93#
94#  or, could also use:
95# /**
96#  * my_function - does my stuff
97#  * @my_arg: its mine damnit
98#  * Description: Does my stuff explained.
99#  */
100# etc.
101#
102# All descriptions can be multiline, apart from the short function description
103.
104#
105# All descriptive text is further processed, scanning for the following specia
106l
107# patterns, which are highlighted appropriately.
108#
109# 'funcname()' - function
110# '$ENVVAR' - environmental variable
111# '&struct_name' - name of a structure
112# '@parameter' - name of a parameter
113# '%CONST' - name of a constant.
114
115#
116# Extensions for LaTeX:
117#
118# 1. the symbol '->' will be replaced with a rightarrow
119# 2. x^y with ${x}^{y}$.
120# 3. xxx\: with xxx:
121
122use POSIX qw(strftime);
123
124# match expressions used to find embedded type information
125$type_constant = "\\\%(\\w+)";
126$type_func = "(\\w+\\(\\))";
127$type_param = "\\\@(\\w+)";
128$type_struct = "\\\&(\\w+)";
129$type_env = "(\\\$\\w+)";
130
131
132# Output conversion substitutions.
133#  One for each output format
134
135# these work fairly well
136%highlights_html = ( $type_constant, "<i>\$1</i>",
137                     $type_func, "<b>\$1</b>",
138                     $type_struct, "<i>\$1</i>",
139                     $type_param, "<tt><b>\$1</b></tt>" );
140$blankline_html = "<p>";
141
142%highlights_texinfo = ( $type_constant, "\\\@var{\$1}",
143                        $type_func, "\\\@code{\$1}",
144                        $type_struct, "\\\@code{\$1}",
145                        $type_param, "\\\@code{\$1}" );
146$blankline_texinfo = "";
147
148%highlights_tex = ( $type_constant, "{\\\\it \$1}",
149                     $type_func, "{\\\\bf \$1}",
150                     $type_struct, "{\\\\it \$1}",
151                     $type_param, "{\\\\bf \$1}" );
152$blankline_tex = "\\\\";
153
154# sgml, docbook format
155%highlights_sgml = ( $type_constant, "<replaceable class=\"option\">\$1</repla
156ceable>",
157                     $type_func, "<function>\$1</function>",
158                     $type_struct, "<structname>\$1</structname>",
159                     $type_env, "<envar>\$1</envar>",
160                     $type_param, "<parameter>\$1</parameter>" );
161$blankline_sgml = "</para><para>\n";
162
163# these are pretty rough
164%highlights_man = ( $type_constant, "\\n.I \\\"\$1\\\"\\n",
165                    $type_func, "\\n.B \\\"\$1\\\"\\n",
166                    $type_struct, "\\n.I \\\"\$1\\\"\\n",
167                    $type_param."([\.\, ]*)\n?", "\\n.I \\\"\$1\$2\\\"\\n" );
168$blankline_man = "";
169
170# text-mode
171%highlights_text = ( $type_constant, "\$1",
172                     $type_func, "\$1",
173                     $type_struct, "\$1",
174                     $type_param, "\$1" );
175$blankline_text = "";
176
177
178sub usage {
179    print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -tex | -texinf
180o  -listfunc ]\n";
181    print "         [ -sourceversion verno ] [ -includefuncprefix ]\n";
182    print "         [ -bugsto address ] [ -seeinfo infonode ] [ -copyright not
183ice]\n";
184    print "         [ -verbatimcopying ]\n";
185    print "         [ -function funcname [ -function funcname ...] ]\n";
186    print "         c source file(s) > outputfile\n";
187    exit 1;
188}
189
190# read arguments
191if ($#ARGV==-1) {
192    usage();
193}
194
195$verbose = 0;
196$output_mode = "man";
197%highlights = %highlights_man;
198$blankline = $blankline_man;
199$modulename = "API Documentation";
200$sourceversion = strftime "%Y-%m-%d", localtime;
201$function_only = 0;
202while ($ARGV[0] =~ m/^-(.*)/) {
203    $cmd = shift @ARGV;
204    if ($cmd eq "-html") {
205        $output_mode = "html";
206        %highlights = %highlights_html;
207        $blankline = $blankline_html;
208    } elsif ($cmd eq "-man") {
209        $output_mode = "man";
210        %highlights = %highlights_man;
211        $blankline = $blankline_man;
212    } elsif ($cmd eq "-tex") {
213        $output_mode = "tex";
214        %highlights = %highlights_tex;
215        $blankline = $blankline_tex;
216    } elsif ($cmd eq "-texinfo") {
217        $output_mode = "texinfo";
218        %highlights = %highlights_texinfo;
219        $blankline = $blankline_texinfo;
220    } elsif ($cmd eq "-text") {
221        $output_mode = "text";
222        %highlights = %highlights_text;
223        $blankline = $blankline_text;
224    } elsif ($cmd eq "-docbook") {
225        $output_mode = "sgml";
226        %highlights = %highlights_sgml;
227        $blankline = $blankline_sgml;
228    } elsif ($cmd eq "-listfunc") {
229        $output_mode = "listfunc";
230    } elsif ($cmd eq "-module") { # not needed for sgml, inherits from calling
231 document
232        $modulename = shift @ARGV;
233    } elsif ($cmd eq "-sourceversion") {
234        $sourceversion = shift @ARGV;
235    } elsif ($cmd eq "-includefuncprefix") {
236        $includefuncprefix = 1;
237    } elsif ($cmd eq "-bugsto") {
238        $bugsto = shift @ARGV;
239    } elsif ($cmd eq "-copyright") {
240        $copyright = shift @ARGV;
241    } elsif ($cmd eq "-verbatimcopying") {
242        $verbatimcopying = 1;
243    } elsif ($cmd eq "-seeinfo") {
244        $seeinfo = shift @ARGV;
245    } elsif ($cmd eq "-function") { # to only output specific functions
246        $function_only = 1;
247        $function = shift @ARGV;
248        $function_table{$function} = 1;
249    } elsif ($cmd eq "-v") {
250        $verbose = 1;
251    } elsif (($cmd eq "-h") || ($cmd eq "--help")) {
252        usage();
253    }
254}
255
256##
257# dumps section contents to arrays/hashes intended for that purpose.
258#
259sub dump_section {
260    my $name = shift @_;
261    my $contents = join "\n", @_;
262
263    if ($name =~ m/$type_constant/) {
264        $name = $1;
265#       print STDERR "constant section '$1' = '$contents'\n";
266        $constants{$name} = $contents;
267    } elsif ($name =~ m/$type_param/) {
268#       print STDERR "parameter def '$1' = '$contents'\n";
269        $name = $1;
270        $parameters{$name} = $contents;
271    } else {
272#       print STDERR "other section '$name' = '$contents'\n";
273        $sections{$name} = $contents;
274        push @sectionlist, $name;
275    }
276}
277
278##
279# output function
280#
281# parameters, a hash.
282#  function => "function name"
283#  parameterlist => @list of parameters
284#  parameters => %parameter descriptions
285#  sectionlist => @list of sections
286#  sections => %descriont descriptions
287#
288
289sub repstr {
290    $pattern = shift;
291    $repl = shift;
292    $match1 = shift;
293    $match2 = shift;
294    $match3 = shift;
295    $match4 = shift;
296
297    $output = $repl;
298    $output =~ s,\$1,$match1,g;
299    $output =~ s,\$2,$match2,g;
300    $output =~ s,\$3,$match3,g;
301    $output =~ s,\$4,$match4,g;
302
303    eval "\$return = qq/$output/";
304
305#    print "pattern $pattern matched 1=$match1 2=$match2 3=$match3 4=$match4 r
306eplace $repl yielded $output interpolated $return\n";
307
308    $return;
309}
310
311sub output_highlight {
312    my $contents = join "\n", @_;
313    my $line;
314
315    foreach $pattern (keys %highlights) {
316#       print "scanning pattern $pattern ($highlights{$pattern})\n";
317        $contents =~ s:$pattern:repstr($pattern, $highlights{$pattern}, $1, $2
318, $3, $4):gse;
319    }
320    foreach $line (split "\n", $contents) {
321        if ($line eq ""){
322            print $lineprefix, $blankline;
323        } else {
324            print $lineprefix, $line;
325        }
326        print "\n";
327    }
328}
329
330sub just_highlight {
331    my $contents = join "\n", @_;
332    my $line;
333    my $ret = "";
334
335    foreach $pattern (keys %highlights) {
336#       print "scanning pattern $pattern ($highlights{$pattern})\n";
337        $contents =~ s:$pattern:repstr($pattern, $highlights{$pattern}, $1, $2
338, $3, $4):gse;
339    }
340    foreach $line (split "\n", $contents) {
341        if ($line eq ""){
342            $ret = $ret . $lineprefix . $blankline;
343        } else {
344            $ret = $ret . $lineprefix . $line;
345        }
346        $ret = $ret . "\n";
347    }
348
349    return $ret;
350}
351
352# output in texinfo
353sub output_texinfo {
354    my %args = %{$_[0]};
355    my ($parameter, $section);
356    my $count;
357
358    print "\@deftypefun {" . $args{'functiontype'} . "} ";
359    print "{".$args{'function'}."} ";
360    print "(";
361    $count = 0;
362    foreach $parameter (@{$args{'parameterlist'}}) {
363        print $args{'parametertypes'}{$parameter}." \@var{".$parameter."}";
364        if ($count != $#{$args{'parameterlist'}}) {
365            $count++;
366            print ", ";
367        }
368    }
369    print ")\n";
370    foreach $parameter (@{$args{'parameterlist'}}) {
371        if ($args{'parameters'}{$parameter}) {
372            print "\@var{".$parameter."}: ";
373            output_highlight($args{'parameters'}{$parameter});
374            print "\n";
375        }
376    }
377    foreach $section (@{$args{'sectionlist'}}) {
378        print "\n\@strong{$section:} " if $section ne $section_default;
379        $args{'sections'}{$section} =~ s:([{}]):\@\1:gs;
380        output_highlight($args{'sections'}{$section});
381    }
382    print "\@end deftypefun\n\n";
383}
384
385# output in html
386sub output_html {
387    my %args = %{$_[0]};
388    my ($parameter, $section);
389    my $count;
390    print "\n\n<a name=\"". $args{'function'} . "\">&nbsp</a><h2>Function</h2>
391\n";
392
393    print "<i>".$args{'functiontype'}."</i>\n";
394    print "<b>".$args{'function'}."</b>\n";
395    print "(";
396    $count = 0;
397    foreach $parameter (@{$args{'parameterlist'}}) {
398        print "<i>".$args{'parametertypes'}{$parameter}."</i> <b>".$parameter.
399"</b>\n";
400        if ($count != $#{$args{'parameterlist'}}) {
401            $count++;
402            print ", ";
403        }
404    }
405    print ")\n";
406
407    print "<h3>Arguments</h3>\n";
408    print "<dl>\n";
409    foreach $parameter (@{$args{'parameterlist'}}) {
410        print "<dt><i>".$args{'parametertypes'}{$parameter}."</i> <b>".$parame
411ter."</b>\n";
412        print "<dd>";
413        output_highlight($args{'parameters'}{$parameter});
414    }
415    print "</dl>\n";
416    foreach $section (@{$args{'sectionlist'}}) {
417        print "<h3>$section</h3>\n";
418        print "<ul>\n";
419        output_highlight($args{'sections'}{$section});
420        print "</ul>\n";
421    }
422    print "<hr>\n";
423}
424
425# output in tex
426sub output_tex {
427    my %args = %{$_[0]};
428    my ($parameter, $section);
429    my $count;
430    my $func = $args{'function'};
431    my $param;
432    my $param2;
433    my $sec;
434    my $check;
435    my $type;
436
437    $func =~ s/_/\\_/g;
438
439    print "\n\n\\subsection{". $func . "}\n\\label{" . $args{'function'} . "}\
440n";
441
442    $type = $args{'functiontype'};
443    $type =~ s/_/\\_/g;
444
445    print "{\\it ".$type."}\n";
446    print "{\\bf ".$func."}\n";
447    print "(";
448    $count = 0;
449    foreach $parameter (@{$args{'parameterlist'}}) {
450        $param = $args{'parametertypes'}{$parameter};
451        $param2 = $parameter;
452        $param =~ s/_/\\_/g;
453        $param2 =~ s/_/\\_/g;
454
455        print "{\\it ".$param."} {\\bf ".$param2."}";
456        if ($count != $#{$args{'parameterlist'}}) {
457            $count++;
458            print ", ";
459        }
460    }
461    print ")\n";
462
463    print "\n{\\large{Arguments}}\n";
464
465    print "\\begin{itemize}\n";
466    $check=0;
467    foreach $parameter (@{$args{'parameterlist'}}) {
468        $param1 = $args{'parametertypes'}{$parameter};
469        $param1 =~ s/_/\\_/g;
470        $param2 = $parameter;
471        $param2 =~ s/_/\\_/g;
472
473        $check = 1;
474        print "\\item {\\it ".$param1."} {\\bf ".$param2."}: \n";
475#       print "\n";
476
477        $param3 = $args{'parameters'}{$parameter};
478        $param3 =~ s/&([a-zA-Z\_]+)/{\\it \1}/g;
479
480        $out = just_highlight($param3);
481        $out =~ s/_/\\_/g;
482        print $out;
483    }
484    if ($check==0) {
485        print "\\item void\n";
486    }
487    print "\\end{itemize}\n";
488
489    foreach $section (@{$args{'sectionlist'}}) {
490        $sec = $section;
491        $sec =~ s/_/\\_/g;
492        $sec =~ s/&([a-zA-Z\_]+)/{\\it \1}/g;
493
494        print "\n{\\large{$sec}}\\\\\n";
495        print "\\begin{rmfamily}\n";
496
497        $sec = $args{'sections'}{$section};
498        $sec =~ s/\\:/:/g;
499        $sec =~ s/&([a-zA-Z\_]+)/{\\it \1}/g;
500        $sec =~ s/->/\$\\rightarrow\$/g;
501        $sec =~ s/([0-9]+)\^([0-9]+)/\$\{\1\}\^\{\2\}\$/g;
502
503        $out = just_highlight($sec);
504        $out =~ s/_/\\_/g;
505
506        print $out;
507        print "\\end{rmfamily}\n";
508    }
509    print "\n";
510}
511
512
513# output in sgml DocBook
514sub output_sgml {
515    my %args = %{$_[0]};
516    my ($parameter, $section);
517    my $count;
518    my $id;
519
520    $id = $args{'module'}."-".$args{'function'};
521    $id =~ s/[^A-Za-z0-9]/-/g;
522
523    print "<refentry>\n";
524    print "<refmeta>\n";
525    print "<refentrytitle><phrase id=\"$id\">".$args{'function'}."</phrase></r
526efentrytitle>\n";
527    print "</refmeta>\n";
528    print "<refnamediv>\n";
529    print " <refname>".$args{'function'}."</refname>\n";
530    print " <refpurpose>\n";
531    print "  ".$args{'purpose'}."\n";
532    print " </refpurpose>\n";
533    print "</refnamediv>\n";
534
535    print "<refsynopsisdiv>\n";
536    print " <title>Synopsis</title>\n";
537    print "  <funcsynopsis>\n";
538    print "   <funcdef>".$args{'functiontype'}." ";
539    print "<function>".$args{'function'}." ";
540    print "</function></funcdef>\n";
541
542#    print "<refsect1>\n";
543#    print " <title>Synopsis</title>\n";
544#    print "  <funcsynopsis>\n";
545#    print "   <funcdef>".$args{'functiontype'}." ";
546#    print "<function>".$args{'function'}." ";
547#    print "</function></funcdef>\n";
548
549    $count = 0;
550    if ($#{$args{'parameterlist'}} >= 0) {
551        foreach $parameter (@{$args{'parameterlist'}}) {
552            print "   <paramdef>".$args{'parametertypes'}{$parameter};
553            print " <parameter>$parameter</parameter></paramdef>\n";
554        }
555    } else {
556        print "  <void>\n";
557    }
558    print "  </funcsynopsis>\n";
559    print "</refsynopsisdiv>\n";
560#    print "</refsect1>\n";
561
562    # print parameters
563    print "<refsect1>\n <title>Arguments</title>\n";
564#    print "<para>\nArguments\n";
565    if ($#{$args{'parameterlist'}} >= 0) {
566        print " <variablelist>\n";
567        foreach $parameter (@{$args{'parameterlist'}}) {
568            print "  <varlistentry>\n   <term><parameter>$parameter</parameter
569></term>\n";
570            print "   <listitem>\n    <para>\n";
571            $lineprefix="     ";
572            output_highlight($args{'parameters'}{$parameter});
573            print "    </para>\n   </listitem>\n  </varlistentry>\n";
574        }
575        print " </variablelist>\n";
576    } else {
577        print " <para>\n  None\n </para>\n";
578    }
579    print "</refsect1>\n";
580
581    # print out each section
582    $lineprefix="   ";
583    foreach $section (@{$args{'sectionlist'}}) {
584        print "<refsect1>\n <title>$section</title>\n <para>\n";
585#       print "<para>\n$section\n";
586        if ($section =~ m/EXAMPLE/i) {
587            print "<example><para>\n";
588        }
589        output_highlight($args{'sections'}{$section});
590#       print "</para>";
591        if ($section =~ m/EXAMPLE/i) {
592            print "</para></example>\n";
593        }
594        print " </para>\n</refsect1>\n";
595    }
596
597    print "\n\n";
598}
599
600##
601# output in man
602sub output_man {
603    my %args = %{$_[0]};
604    my ($parameter, $section);
605    my $count;
606
607    print ".TH \"$args{'function'}\" 3 \"$args{'sourceversion'}\" \"". $args{'
608module'} . "\" \"". $args{'module'} . "\"\n";
609
610    print ".SH NAME\n";
611
612    print $args{'function'}."\n";
613
614    print ".SH SYNOPSIS\n";
615    print ".B #include <". lc((split /_/, $args{'function'})[0]) . ".h>\n"
616        if $args{'includefuncprefix'};
617    print ".sp\n";
618    print ".BI \"".$args{'functiontype'}." ".$args{'function'}."(";
619    $count = 0;
620    foreach $parameter (@{$args{'parameterlist'}}) {
621        print $args{'parametertypes'}{$parameter}." \" ".$parameter." \"";
622        if ($count != $#{$args{'parameterlist'}}) {
623            $count++;
624            print ", ";
625        }
626    }
627    print ");\"\n";
628
629    print ".SH ARGUMENTS\n";
630    foreach $parameter (@{$args{'parameterlist'}}) {
631        print ".IP \"".$args{'parametertypes'}{$parameter}." ".$parameter."\"
63212\n";
633        output_highlight($args{'parameters'}{$parameter});
634    }
635    foreach $section (@{$args{'sectionlist'}}) {
636        print ".SH \"" . uc($section) . "\"\n";
637        output_highlight($args{'sections'}{$section});
638    }
639
640    if ($args{'bugsto'}) {
641        print ".SH \"REPORTING BUGS\"\n";
642        print "Report bugs to <". $args{'bugsto'} . ">.\n";
643    }
644
645    if ($args{'copyright'}) {
646        print ".SH COPYRIGHT\n";
647        print "Copyright \\(co ". $args{'copyright'} . ".\n";
648        if ($args{'verbatimcopying'}) {
649            print ".br\n";
650            print "Permission is granted to make and distribute verbatim copie
651s of this\n";
652            print "manual provided the copyright notice and this permission no
653tice are\n";
654            print "preserved on all copies.\n";
655        }
656    }
657
658    if ($args{'seeinfo'}) {
659        print ".SH \"SEE ALSO\"\n";
660        print "The full documentation for\n";
661        print ".B " . $args{'module'} . "\n";
662        print "is maintained as a Texinfo manual.  If the\n";
663        print ".B info\n";
664        print "and\n";
665        print ".B " . $args{'module'} . "\n";
666        print "programs are properly installed at your site, the command\n";
667        print ".IP\n";
668        print ".B info " . $args{'seeinfo'} . "\n";
669        print ".PP\n";
670        print "should give you access to the complete manual.\n";
671    }
672}
673
674sub output_listfunc {
675    my %args = %{$_[0]};
676    print $args{'function'} . "\n";
677}
678
679##
680# output in text
681sub output_text {
682    my %args = %{$_[0]};
683    my ($parameter, $section);
684
685    print "Function = ".$args{'function'}."\n";
686    print "  return type: ".$args{'functiontype'}."\n\n";
687    foreach $parameter (@{$args{'parameterlist'}}) {
688        print " ".$args{'parametertypes'}{$parameter}." ".$parameter."\n";
689        print "    -> ".$args{'parameters'}{$parameter}."\n";
690    }
691    foreach $section (@{$args{'sectionlist'}}) {
692        print " $section:\n";
693        print "    -> ";
694        output_highlight($args{'sections'}{$section});
695    }
696}
697
698##
699# generic output function - calls the right one based
700# on current output mode.
701sub output_function {
702#    output_html(@_);
703    eval "output_".$output_mode."(\@_);";
704}
705
706
707##
708# takes a function prototype and spits out all the details
709# stored in the global arrays/hsahes.
710sub dump_function {
711    my $prototype = shift @_;
712
713    if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
714        $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
715        $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
716        $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/ ||
717        $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\)]*)\)/)
718  {
719        $return_type = $1;
720        $function_name = $2;
721        $args = $3;
722
723#       print STDERR "ARGS = '$args'\n";
724
725        foreach $arg (split ',', $args) {
726            # strip leading/trailing spaces
727            $arg =~ s/^\s*//;
728            $arg =~ s/\s*$//;
729#           print STDERR "SCAN ARG: '$arg'\n";
730            @args = split('\s', $arg);
731
732#           print STDERR " -> @args\n";
733            $param = pop @args;
734#           print STDERR " -> @args\n";
735            if ($param =~ m/^(\*+)(.*)/) {
736                $param = $2;
737                push @args, $1;
738            }
739            if ($param =~ m/^(.*)(\[\])$/) {
740                $param = $1;
741                push @args, $2;
742            }
743#           print STDERR " :> @args\n";
744            $type = join " ", @args;
745
746            if ($parameters{$param} eq "" && $param != "void") {
747                $parameters{$param} = "-- undescribed --";
748                print STDERR "Warning($lineno): Function parameter '$param' no
749t described in '$function_name'\n";
750            }
751
752            push @parameterlist, $param;
753            $parametertypes{$param} = $type;
754
755#           print STDERR "param = '$param', type = '$type'\n";
756        }
757    } else {
758        print STDERR "Error($lineno): cannot understand prototype: '$prototype
759'\n";
760        return;
761    }
762
763    if ($function_only==0 || defined($function_table{$function_name})) {
764        output_function({'function' => $function_name,
765                         'module' => $modulename,
766                         'sourceversion' => $sourceversion,
767                         'includefuncprefix' => $includefuncprefix,
768                         'bugsto' => $bugsto,
769                         'copyright' => $copyright,
770                         'verbatimcopying' => $verbatimcopying,
771                         'seeinfo' => $seeinfo,
772                         'functiontype' => $return_type,
773                         'parameterlist' => \@parameterlist,
774                         'parameters' => \%parameters,
775                         'parametertypes' => \%parametertypes,
776                         'sectionlist' => \@sectionlist,
777                         'sections' => \%sections,
778                         'purpose' => $function_purpose
779                         });
780    }
781}
782
783######################################################################
784# main
785# states
786# 0 - normal code
787# 1 - looking for function name
788# 2 - scanning field start.
789# 3 - scanning prototype.
790$state = 0;
791$section = "";
792
793$doc_special = "\@\%\$\&";
794
795$doc_start = "^/\\*\\*\$";
796$doc_end = "\\*/";
797$doc_com = "\\s*\\*\\s*";
798$doc_func = $doc_com."(\\w+):?";
799$doc_sect = $doc_com."([".$doc_special."[:upper:]][\\w ]+):(.*)";
800$doc_content = $doc_com."(.*)";
801
802%constants = ();
803%parameters = ();
804@parameterlist = ();
805%sections = ();
806@sectionlist = ();
807
808$contents = "";
809$section_default = "Description";       # default section
810$section = $section_default;
811
812$lineno = 0;
813foreach $file (@ARGV) {
814    if (!open(IN,"<$file")) {
815        print STDERR "Error: Cannot open file $file\n";
816        next;
817    }
818    while (<IN>) {
819        $lineno++;
820
821        if ($state == 0) {
822            if (/$doc_start/o) {
823                $state = 1;             # next line is always the function nam
824e
825            }
826        } elsif ($state == 1) { # this line is the function name (always)
827            if (/$doc_func/o) {
828                $function = $1;
829                $state = 2;
830                if (/-(.*)/) {
831                    $function_purpose = $1;
832                } else {
833                    $function_purpose = "";
834                }
835                if ($verbose) {
836                    print STDERR "Info($lineno): Scanning doc for $function\n"
837;
838                }
839            } else {
840                print STDERR "WARN($lineno): Cannot understand $_ on line $lin
841eno",
842                " - I thought it was a doc line\n";
843                $state = 0;
844            }
845        } elsif ($state == 2) { # look for head: lines, and include content
846            if (/$doc_sect/o) {
847                $newsection = $1;
848                $newcontents = $2;
849
850                if ($contents ne "") {
851                    dump_section($section, $contents);
852                    $section = $section_default;
853                }
854
855                $contents = $newcontents;
856                if ($contents ne "") {
857                    $contents .= "\n";
858                }
859                $section = $newsection;
860            } elsif (/$doc_end/) {
861
862                if ($contents ne "") {
863                    dump_section($section, $contents);
864                    $section = $section_default;
865                    $contents = "";
866                }
867
868#           print STDERR "end of doc comment, looking for prototype\n";
869                $prototype = "";
870                $state = 3;
871            } elsif (/$doc_content/) {
872                # miguel-style comment kludge, look for blank lines after
873                # @parameter line to signify start of description
874                if ($1 eq "" && $section =~ m/^@/) {
875                    dump_section($section, $contents);
876                    $section = $section_default;
877                    $contents = "";
878                } else {
879                    $contents .= $1."\n";
880                }
881            } else {
882                # i dont know - bad line?  ignore.
883                print STDERR "WARNING($lineno): bad line: $_";
884            }
885        } elsif ($state == 3) { # scanning for function { (end of prototype)
886            if (m#\s*/\*\s+MACDOC\s*#io) {
887              # do nothing
888            }
889            elsif (/([^\{]*)/) {
890                $prototype .= $1;
891            }
892            if (/\{/) {
893                $prototype =~ s@/\*.*?\*/@@gos; # strip comments.
894                $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
895                $prototype =~ s@^ +@@gos; # strip leading spaces
896                dump_function($prototype);
897
898                $function = "";
899                %constants = ();
900                %parameters = ();
901                %parametertypes = ();
902                @parameterlist = ();
903                %sections = ();
904                @sectionlist = ();
905                $prototype = "";
906
907                $state = 0;
908            }
909        }
910    }
911}
912
913
914
915