[PATCH] DocBook: warn for missing macro parameters
[linux-2.6.git] / scripts / kernel-doc
1 #!/usr/bin/perl -w
2
3 use strict;
4
5 ## Copyright (c) 1998 Michael Zucchi, All Rights Reserved        ##
6 ## Copyright (C) 2000, 1  Tim Waugh <twaugh@redhat.com>          ##
7 ## Copyright (C) 2001  Simon Huggins                             ##
8 ##                                                               ##
9 ## #define enhancements by Armin Kuster <akuster@mvista.com>     ##
10 ## Copyright (c) 2000 MontaVista Software, Inc.                  ##
11 ##                                                               ##
12 ## This software falls under the GNU General Public License.     ##
13 ## Please read the COPYING file for more information             ##
14
15 # w.o. 03-11-2000: added the '-filelist' option.
16
17 # 18/01/2001 -  Cleanups
18 #               Functions prototyped as foo(void) same as foo()
19 #               Stop eval'ing where we don't need to.
20 # -- huggie@earth.li
21
22 # 27/06/2001 -  Allowed whitespace after initial "/**" and
23 #               allowed comments before function declarations.
24 # -- Christian Kreibich <ck@whoop.org>
25
26 # Still to do:
27 #       - add perldoc documentation
28 #       - Look more closely at some of the scarier bits :)
29
30 # 26/05/2001 -  Support for separate source and object trees.
31 #               Return error code.
32 #               Keith Owens <kaos@ocs.com.au>
33
34 # 23/09/2001 - Added support for typedefs, structs, enums and unions
35 #              Support for Context section; can be terminated using empty line
36 #              Small fixes (like spaces vs. \s in regex)
37 # -- Tim Jansen <tim@tjansen.de>
38
39
40 #
41 # This will read a 'c' file and scan for embedded comments in the
42 # style of gnome comments (+minor extensions - see below).
43 #
44
45 # Note: This only supports 'c'.
46
47 # usage:
48 # kerneldoc [ -docbook | -html | -text | -man ]
49 #           [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile
50 # or
51 #           [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile
52 #
53 #  Set output format using one of -docbook -html -text or -man.  Default is man.
54 #
55 #  -function funcname
56 #       If set, then only generate documentation for the given function(s).  All
57 #       other functions are ignored.
58 #
59 #  -nofunction funcname
60 #       If set, then only generate documentation for the other function(s).  All
61 #       other functions are ignored. Cannot be used with -function together
62 #       (yes thats a bug - perl hackers can fix it 8))
63 #
64 #  c files - list of 'c' files to process
65 #
66 #  All output goes to stdout, with errors to stderr.
67
68 #
69 # format of comments.
70 # In the following table, (...)? signifies optional structure.
71 #                         (...)* signifies 0 or more structure elements
72 # /**
73 #  * function_name(:)? (- short description)?
74 # (* @parameterx: (description of parameter x)?)*
75 # (* a blank line)?
76 #  * (Description:)? (Description of function)?
77 #  * (section header: (section description)? )*
78 #  (*)?*/
79 #
80 # So .. the trivial example would be:
81 #
82 # /**
83 #  * my_function
84 #  **/
85 #
86 # If the Description: header tag is ommitted, then there must be a blank line
87 # after the last parameter specification.
88 # e.g.
89 # /**
90 #  * my_function - does my stuff
91 #  * @my_arg: its mine damnit
92 #  *
93 #  * Does my stuff explained. 
94 #  */
95 #
96 #  or, could also use:
97 # /**
98 #  * my_function - does my stuff
99 #  * @my_arg: its mine damnit
100 #  * Description: Does my stuff explained. 
101 #  */
102 # etc.
103 #
104 # Beside functions you can also write documentation for structs, unions, 
105 # enums and typedefs. Instead of the function name you must write the name 
106 # of the declaration;  the struct/union/enum/typedef must always precede 
107 # the name. Nesting of declarations is not supported. 
108 # Use the argument mechanism to document members or constants.
109 # e.g.
110 # /**
111 #  * struct my_struct - short description
112 #  * @a: first member
113 #  * @b: second member
114 #  * 
115 #  * Longer description
116 #  */
117 # struct my_struct {
118 #     int a;
119 #     int b;
120 # /* private: */
121 #     int c;
122 # };
123 #
124 # All descriptions can be multiline, except the short function description.
125
126 # You can also add additional sections. When documenting kernel functions you 
127 # should document the "Context:" of the function, e.g. whether the functions 
128 # can be called form interrupts. Unlike other sections you can end it with an
129 # empty line. 
130 # Example-sections should contain the string EXAMPLE so that they are marked 
131 # appropriately in DocBook.
132 #
133 # Example:
134 # /**
135 #  * user_function - function that can only be called in user context
136 #  * @a: some argument
137 #  * Context: !in_interrupt()
138 #  * 
139 #  * Some description
140 #  * Example:
141 #  *    user_function(22);
142 #  */
143 # ...
144 #
145 #
146 # All descriptive text is further processed, scanning for the following special
147 # patterns, which are highlighted appropriately.
148 #
149 # 'funcname()' - function
150 # '$ENVVAR' - environmental variable
151 # '&struct_name' - name of a structure (up to two words including 'struct')
152 # '@parameter' - name of a parameter
153 # '%CONST' - name of a constant.
154
155 my $errors = 0;
156 my $warnings = 0;
157
158 # match expressions used to find embedded type information
159 my $type_constant = '\%([-_\w]+)';
160 my $type_func = '(\w+)\(\)';
161 my $type_param = '\@(\w+)';
162 my $type_struct = '\&((struct\s*)?[_\w]+)';
163 my $type_env = '(\$\w+)';
164
165 # Output conversion substitutions.
166 #  One for each output format
167
168 # these work fairly well
169 my %highlights_html = ( $type_constant, "<i>\$1</i>",
170                         $type_func, "<b>\$1</b>",
171                         $type_struct, "<i>\$1</i>",
172                         $type_param, "<tt><b>\$1</b></tt>" );
173 my $blankline_html = "<p>";
174
175 # XML, docbook format
176 my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
177                         $type_constant, "<constant>\$1</constant>",
178                         $type_func, "<function>\$1</function>",
179                         $type_struct, "<structname>\$1</structname>",
180                         $type_env, "<envar>\$1</envar>",
181                         $type_param, "<parameter>\$1</parameter>" );
182 my $blankline_xml = "</para><para>\n";
183
184 # gnome, docbook format
185 my %highlights_gnome = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
186                          $type_func, "<function>\$1</function>",
187                          $type_struct, "<structname>\$1</structname>",
188                          $type_env, "<envar>\$1</envar>",
189                          $type_param, "<parameter>\$1</parameter>" );
190 my $blankline_gnome = "</para><para>\n";
191
192 # these are pretty rough
193 my %highlights_man = ( $type_constant, "\$1",
194                        $type_func, "\\\\fB\$1\\\\fP",
195                        $type_struct, "\\\\fI\$1\\\\fP",
196                        $type_param, "\\\\fI\$1\\\\fP" );
197 my $blankline_man = "";
198
199 # text-mode
200 my %highlights_text = ( $type_constant, "\$1",
201                         $type_func, "\$1",
202                         $type_struct, "\$1",
203                         $type_param, "\$1" );
204 my $blankline_text = "";
205
206
207 sub usage {
208     print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man ]\n";
209     print "         [ -function funcname [ -function funcname ...] ]\n";
210     print "         [ -nofunction funcname [ -nofunction funcname ...] ]\n";
211     print "         c source file(s) > outputfile\n";
212     exit 1;
213 }
214
215 # read arguments
216 if ($#ARGV==-1) {
217     usage();
218 }
219
220 my $verbose = 0;
221 my $output_mode = "man";
222 my %highlights = %highlights_man;
223 my $blankline = $blankline_man;
224 my $modulename = "Kernel API";
225 my $function_only = 0;
226 my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', 
227                 'July', 'August', 'September', 'October', 
228                 'November', 'December')[(localtime)[4]] . 
229   " " . ((localtime)[5]+1900);
230
231 # Essentially these are globals
232 # They probably want to be tidied up made more localised or summat.
233 # CAVEAT EMPTOR!  Some of the others I localised may not want to be which
234 # could cause "use of undefined value" or other bugs.
235 my ($function, %function_table,%parametertypes,$declaration_purpose);
236 my ($type,$declaration_name,$return_type);
237 my ($newsection,$newcontents,$prototype,$filelist, $brcount, %source_map);
238
239 # Generated docbook code is inserted in a template at a point where 
240 # docbook v3.1 requires a non-zero sequence of RefEntry's; see:
241 # http://www.oasis-open.org/docbook/documentation/reference/html/refentry.html
242 # We keep track of number of generated entries and generate a dummy
243 # if needs be to ensure the expanded template can be postprocessed
244 # into html.
245 my $section_counter = 0;
246
247 my $lineprefix="";
248
249 # states
250 # 0 - normal code
251 # 1 - looking for function name
252 # 2 - scanning field start.
253 # 3 - scanning prototype.
254 # 4 - documentation block
255 my $state;
256
257 #declaration types: can be
258 # 'function', 'struct', 'union', 'enum', 'typedef'
259 my $decl_type;
260
261 my $doc_special = "\@\%\$\&";
262
263 my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start.
264 my $doc_end = '\*/';
265 my $doc_com = '\s*\*\s*';
266 my $doc_decl = $doc_com.'(\w+)';
267 my $doc_sect = $doc_com.'(['.$doc_special.']?[\w ]+):(.*)';
268 my $doc_content = $doc_com.'(.*)';
269 my $doc_block = $doc_com.'DOC:\s*(.*)?';
270
271 my %constants;
272 my %parameterdescs;
273 my @parameterlist;
274 my %sections;
275 my @sectionlist;
276
277 my $contents = "";
278 my $section_default = "Description";    # default section
279 my $section_intro = "Introduction";
280 my $section = $section_default;
281 my $section_context = "Context";
282
283 my $undescribed = "-- undescribed --";
284
285 reset_state();
286
287 while ($ARGV[0] =~ m/^-(.*)/) {
288     my $cmd = shift @ARGV;
289     if ($cmd eq "-html") {
290         $output_mode = "html";
291         %highlights = %highlights_html;
292         $blankline = $blankline_html;
293     } elsif ($cmd eq "-man") {
294         $output_mode = "man";
295         %highlights = %highlights_man;
296         $blankline = $blankline_man;
297     } elsif ($cmd eq "-text") {
298         $output_mode = "text";
299         %highlights = %highlights_text;
300         $blankline = $blankline_text;
301     } elsif ($cmd eq "-docbook") {
302         $output_mode = "xml";
303         %highlights = %highlights_xml;
304         $blankline = $blankline_xml;
305     } elsif ($cmd eq "-gnome") {
306         $output_mode = "gnome";
307         %highlights = %highlights_gnome;
308         $blankline = $blankline_gnome;
309     } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document
310         $modulename = shift @ARGV;
311     } elsif ($cmd eq "-function") { # to only output specific functions
312         $function_only = 1;
313         $function = shift @ARGV;
314         $function_table{$function} = 1;
315     } elsif ($cmd eq "-nofunction") { # to only output specific functions
316         $function_only = 2;
317         $function = shift @ARGV;
318         $function_table{$function} = 1;
319     } elsif ($cmd eq "-v") {
320         $verbose = 1;
321     } elsif (($cmd eq "-h") || ($cmd eq "--help")) {
322         usage();
323     } elsif ($cmd eq '-filelist') {
324             $filelist = shift @ARGV;
325     }
326 }
327
328
329 # generate a sequence of code that will splice in highlighting information
330 # using the s// operator.
331 my $dohighlight = "";
332 foreach my $pattern (keys %highlights) {
333 #    print "scanning pattern $pattern ($highlights{$pattern})\n";
334     $dohighlight .=  "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n";
335 }
336
337 ##
338 # dumps section contents to arrays/hashes intended for that purpose.
339 #
340 sub dump_section {
341     my $name = shift;
342     my $contents = join "\n", @_;
343
344     if ($name =~ m/$type_constant/) {
345         $name = $1;
346 #       print STDERR "constant section '$1' = '$contents'\n";
347         $constants{$name} = $contents;
348     } elsif ($name =~ m/$type_param/) {
349 #       print STDERR "parameter def '$1' = '$contents'\n";
350         $name = $1;
351         $parameterdescs{$name} = $contents;
352     } else {
353 #       print STDERR "other section '$name' = '$contents'\n";
354         $sections{$name} = $contents;
355         push @sectionlist, $name;
356     }
357 }
358
359 ##
360 # output function
361 #
362 # parameterdescs, a hash.
363 #  function => "function name"
364 #  parameterlist => @list of parameters
365 #  parameterdescs => %parameter descriptions
366 #  sectionlist => @list of sections
367 #  sections => %descriont descriptions
368 #  
369
370 sub output_highlight {
371     my $contents = join "\n",@_;
372     my $line;
373
374 #   DEBUG
375 #   if (!defined $contents) {
376 #       use Carp;
377 #       confess "output_highlight got called with no args?\n";
378 #   }
379
380     eval $dohighlight;
381     die $@ if $@;
382     foreach $line (split "\n", $contents) {
383       if ($line eq ""){
384             print $lineprefix, $blankline;
385         } else {
386             $line =~ s/\\\\\\/\&/g;
387             print $lineprefix, $line;
388         }
389         print "\n";
390     }
391 }
392
393 #output sections in html
394 sub output_section_html(%) {
395     my %args = %{$_[0]};
396     my $section;
397
398     foreach $section (@{$args{'sectionlist'}}) {
399         print "<h3>$section</h3>\n";
400         print "<blockquote>\n";
401         output_highlight($args{'sections'}{$section});
402         print "</blockquote>\n";
403     }  
404 }
405
406 # output enum in html
407 sub output_enum_html(%) {
408     my %args = %{$_[0]};
409     my ($parameter);
410     my $count;
411     print "<h2>enum ".$args{'enum'}."</h2>\n";
412
413     print "<b>enum ".$args{'enum'}."</b> {<br>\n";
414     $count = 0;
415     foreach $parameter (@{$args{'parameterlist'}}) {
416         print " <b>".$parameter."</b>";
417         if ($count != $#{$args{'parameterlist'}}) {
418             $count++;
419             print ",\n";
420         }
421         print "<br>";
422     }
423     print "};<br>\n";
424
425     print "<h3>Constants</h3>\n";
426     print "<dl>\n";
427     foreach $parameter (@{$args{'parameterlist'}}) {
428         print "<dt><b>".$parameter."</b>\n";
429         print "<dd>";
430         output_highlight($args{'parameterdescs'}{$parameter});
431     }
432     print "</dl>\n";
433     output_section_html(@_);
434     print "<hr>\n";
435 }
436
437 # output tyepdef in html
438 sub output_typedef_html(%) {
439     my %args = %{$_[0]};
440     my ($parameter);
441     my $count;
442     print "<h2>typedef ".$args{'typedef'}."</h2>\n";
443
444     print "<b>typedef ".$args{'typedef'}."</b>\n";
445     output_section_html(@_);
446     print "<hr>\n";
447 }
448
449 # output struct in html
450 sub output_struct_html(%) {
451     my %args = %{$_[0]};
452     my ($parameter);
453
454     print "<h2>".$args{'type'}." ".$args{'struct'}."</h2>\n";
455     print "<b>".$args{'type'}." ".$args{'struct'}."</b> {<br>\n";
456     foreach $parameter (@{$args{'parameterlist'}}) {
457         if ($parameter =~ /^#/) {
458                 print "$parameter<br>\n";
459                 next;
460         }
461         my $parameter_name = $parameter;
462         $parameter_name =~ s/\[.*//;
463
464         ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
465         $type = $args{'parametertypes'}{$parameter};
466         if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
467             # pointer-to-function
468             print " <i>$1</i><b>$parameter</b>) <i>($2)</i>;<br>\n";
469         } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
470             print " <i>$1</i> <b>$parameter</b>$2;<br>\n";
471         } else {
472             print " <i>$type</i> <b>$parameter</b>;<br>\n";
473         }
474     }
475     print "};<br>\n";
476
477     print "<h3>Members</h3>\n";
478     print "<dl>\n";
479     foreach $parameter (@{$args{'parameterlist'}}) {
480         ($parameter =~ /^#/) && next;
481
482         my $parameter_name = $parameter;
483         $parameter_name =~ s/\[.*//;
484
485         ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
486         print "<dt><b>".$parameter."</b>\n";
487         print "<dd>";
488         output_highlight($args{'parameterdescs'}{$parameter_name});
489     }
490     print "</dl>\n";
491     output_section_html(@_);
492     print "<hr>\n";
493 }
494
495 # output function in html
496 sub output_function_html(%) {
497     my %args = %{$_[0]};
498     my ($parameter, $section);
499     my $count;
500     print "<h2>Function</h2>\n";
501
502     print "<i>".$args{'functiontype'}."</i>\n";
503     print "<b>".$args{'function'}."</b>\n";
504     print "(";
505     $count = 0;
506     foreach $parameter (@{$args{'parameterlist'}}) {
507         $type = $args{'parametertypes'}{$parameter};
508         if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
509             # pointer-to-function
510             print "<i>$1</i><b>$parameter</b>) <i>($2)</i>";
511         } else {
512             print "<i>".$type."</i> <b>".$parameter."</b>";
513         }
514         if ($count != $#{$args{'parameterlist'}}) {
515             $count++;
516             print ",\n";
517         }
518     }
519     print ")\n";
520
521     print "<h3>Arguments</h3>\n";
522     print "<dl>\n";
523     foreach $parameter (@{$args{'parameterlist'}}) {
524         my $parameter_name = $parameter;
525         $parameter_name =~ s/\[.*//;
526
527         ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
528         print "<dt><b>".$parameter."</b>\n";
529         print "<dd>";
530         output_highlight($args{'parameterdescs'}{$parameter_name});
531     }
532     print "</dl>\n";
533     output_section_html(@_);
534     print "<hr>\n";
535 }
536
537 # output intro in html
538 sub output_intro_html(%) {
539     my %args = %{$_[0]};
540     my ($parameter, $section);
541     my $count;
542
543     foreach $section (@{$args{'sectionlist'}}) {
544         print "<h3>$section</h3>\n";
545         print "<ul>\n";
546         output_highlight($args{'sections'}{$section});
547         print "</ul>\n";
548     }
549     print "<hr>\n";
550 }
551
552 sub output_section_xml(%) {
553     my %args = %{$_[0]};
554     my $section;    
555     # print out each section
556     $lineprefix="   ";
557     foreach $section (@{$args{'sectionlist'}}) {
558         print "<refsect1>\n";
559         print "<title>$section</title>\n";
560         if ($section =~ m/EXAMPLE/i) {
561             print "<informalexample><programlisting>\n";
562         } else {
563             print "<para>\n";
564         }
565         output_highlight($args{'sections'}{$section});
566         if ($section =~ m/EXAMPLE/i) {
567             print "</programlisting></informalexample>\n";
568         } else {
569             print "</para>\n";
570         }
571         print "</refsect1>\n";
572     }
573 }
574
575 # output function in XML DocBook
576 sub output_function_xml(%) {
577     my %args = %{$_[0]};
578     my ($parameter, $section);
579     my $count;
580     my $id;
581
582     $id = "API-".$args{'function'};
583     $id =~ s/[^A-Za-z0-9]/-/g;
584
585     print "<refentry>\n";
586     print "<refentryinfo>\n";
587     print " <title>LINUX</title>\n";
588     print " <productname>Kernel Hackers Manual</productname>\n";
589     print " <date>$man_date</date>\n";
590     print "</refentryinfo>\n";
591     print "<refmeta>\n";
592     print " <refentrytitle><phrase id=\"$id\">".$args{'function'}."</phrase></refentrytitle>\n";
593     print " <manvolnum>9</manvolnum>\n";
594     print "</refmeta>\n";
595     print "<refnamediv>\n";
596     print " <refname>".$args{'function'}."</refname>\n";
597     print " <refpurpose>\n";
598     print "  ";
599     output_highlight ($args{'purpose'});
600     print " </refpurpose>\n";
601     print "</refnamediv>\n";
602
603     print "<refsynopsisdiv>\n";
604     print " <title>Synopsis</title>\n";
605     print "  <funcsynopsis><funcprototype>\n";
606     print "   <funcdef>".$args{'functiontype'}." ";
607     print "<function>".$args{'function'}." </function></funcdef>\n";
608
609     $count = 0;
610     if ($#{$args{'parameterlist'}} >= 0) {
611         foreach $parameter (@{$args{'parameterlist'}}) {
612             $type = $args{'parametertypes'}{$parameter};
613             if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
614                 # pointer-to-function
615                 print "   <paramdef>$1<parameter>$parameter</parameter>)\n";
616                 print "     <funcparams>$2</funcparams></paramdef>\n";
617             } else {
618                 print "   <paramdef>".$type;
619                 print " <parameter>$parameter</parameter></paramdef>\n";
620             }
621         }
622     } else {
623         print "  <void/>\n";
624     }
625     print "  </funcprototype></funcsynopsis>\n";
626     print "</refsynopsisdiv>\n";
627
628     # print parameters
629     print "<refsect1>\n <title>Arguments</title>\n";
630     if ($#{$args{'parameterlist'}} >= 0) {
631         print " <variablelist>\n";
632         foreach $parameter (@{$args{'parameterlist'}}) {
633             my $parameter_name = $parameter;
634             $parameter_name =~ s/\[.*//;
635
636             print "  <varlistentry>\n   <term><parameter>$parameter</parameter></term>\n";
637             print "   <listitem>\n    <para>\n";
638             $lineprefix="     ";
639             output_highlight($args{'parameterdescs'}{$parameter_name});
640             print "    </para>\n   </listitem>\n  </varlistentry>\n";
641         }
642         print " </variablelist>\n";
643     } else {
644         print " <para>\n  None\n </para>\n";
645     }
646     print "</refsect1>\n";
647
648     output_section_xml(@_);
649     print "</refentry>\n\n";
650 }
651
652 # output struct in XML DocBook
653 sub output_struct_xml(%) {
654     my %args = %{$_[0]};
655     my ($parameter, $section);
656     my $id;
657
658     $id = "API-struct-".$args{'struct'};
659     $id =~ s/[^A-Za-z0-9]/-/g;
660
661     print "<refentry>\n";
662     print "<refentryinfo>\n";
663     print " <title>LINUX</title>\n";
664     print " <productname>Kernel Hackers Manual</productname>\n";
665     print " <date>$man_date</date>\n";
666     print "</refentryinfo>\n";
667     print "<refmeta>\n";
668     print " <refentrytitle><phrase id=\"$id\">".$args{'type'}." ".$args{'struct'}."</phrase></refentrytitle>\n";
669     print " <manvolnum>9</manvolnum>\n";
670     print "</refmeta>\n";
671     print "<refnamediv>\n";
672     print " <refname>".$args{'type'}." ".$args{'struct'}."</refname>\n";
673     print " <refpurpose>\n";
674     print "  ";
675     output_highlight ($args{'purpose'});
676     print " </refpurpose>\n";
677     print "</refnamediv>\n";
678
679     print "<refsynopsisdiv>\n";
680     print " <title>Synopsis</title>\n";
681     print "  <programlisting>\n";
682     print $args{'type'}." ".$args{'struct'}." {\n";
683     foreach $parameter (@{$args{'parameterlist'}}) {
684         if ($parameter =~ /^#/) {
685             print "$parameter\n";
686             next;
687         }
688
689         my $parameter_name = $parameter;
690         $parameter_name =~ s/\[.*//;
691
692         defined($args{'parameterdescs'}{$parameter_name}) || next;
693         ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
694         $type = $args{'parametertypes'}{$parameter};
695         if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
696             # pointer-to-function
697             print "  $1 $parameter) ($2);\n";
698         } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
699             print "  $1 $parameter$2;\n";
700         } else {
701             print "  ".$type." ".$parameter.";\n";
702         }
703     }
704     print "};";
705     print "  </programlisting>\n";
706     print "</refsynopsisdiv>\n";
707
708     print " <refsect1>\n";
709     print "  <title>Members</title>\n";
710
711     print "  <variablelist>\n";
712     foreach $parameter (@{$args{'parameterlist'}}) {
713       ($parameter =~ /^#/) && next;
714
715       my $parameter_name = $parameter;
716       $parameter_name =~ s/\[.*//;
717
718       defined($args{'parameterdescs'}{$parameter_name}) || next;
719       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
720       print "    <varlistentry>";
721       print "      <term>$parameter</term>\n";
722       print "      <listitem><para>\n";
723       output_highlight($args{'parameterdescs'}{$parameter_name});
724       print "      </para></listitem>\n";
725       print "    </varlistentry>\n";
726     }
727     print "  </variablelist>\n";
728     print " </refsect1>\n";
729
730     output_section_xml(@_);
731
732     print "</refentry>\n\n";
733 }
734
735 # output enum in XML DocBook
736 sub output_enum_xml(%) {
737     my %args = %{$_[0]};
738     my ($parameter, $section);
739     my $count;
740     my $id;
741
742     $id = "API-enum-".$args{'enum'};
743     $id =~ s/[^A-Za-z0-9]/-/g;
744
745     print "<refentry>\n";
746     print "<refentryinfo>\n";
747     print " <title>LINUX</title>\n";
748     print " <productname>Kernel Hackers Manual</productname>\n";
749     print " <date>$man_date</date>\n";
750     print "</refentryinfo>\n";
751     print "<refmeta>\n";
752     print " <refentrytitle><phrase id=\"$id\">enum ".$args{'enum'}."</phrase></refentrytitle>\n";
753     print " <manvolnum>9</manvolnum>\n";
754     print "</refmeta>\n";
755     print "<refnamediv>\n";
756     print " <refname>enum ".$args{'enum'}."</refname>\n";
757     print " <refpurpose>\n";
758     print "  ";
759     output_highlight ($args{'purpose'});
760     print " </refpurpose>\n";
761     print "</refnamediv>\n";
762
763     print "<refsynopsisdiv>\n";
764     print " <title>Synopsis</title>\n";
765     print "  <programlisting>\n";
766     print "enum ".$args{'enum'}." {\n";
767     $count = 0;
768     foreach $parameter (@{$args{'parameterlist'}}) {
769         print "  $parameter";
770         if ($count != $#{$args{'parameterlist'}}) {
771             $count++;
772             print ",";
773         }
774         print "\n";
775     }
776     print "};";
777     print "  </programlisting>\n";
778     print "</refsynopsisdiv>\n";
779
780     print "<refsect1>\n";
781     print " <title>Constants</title>\n";    
782     print "  <variablelist>\n";
783     foreach $parameter (@{$args{'parameterlist'}}) {
784       my $parameter_name = $parameter;
785       $parameter_name =~ s/\[.*//;
786
787       print "    <varlistentry>";
788       print "      <term>$parameter</term>\n";
789       print "      <listitem><para>\n";
790       output_highlight($args{'parameterdescs'}{$parameter_name});
791       print "      </para></listitem>\n";
792       print "    </varlistentry>\n";
793     }
794     print "  </variablelist>\n";
795     print "</refsect1>\n";
796
797     output_section_xml(@_);
798
799     print "</refentry>\n\n";
800 }
801
802 # output typedef in XML DocBook
803 sub output_typedef_xml(%) {
804     my %args = %{$_[0]};
805     my ($parameter, $section);
806     my $id;
807
808     $id = "API-typedef-".$args{'typedef'};
809     $id =~ s/[^A-Za-z0-9]/-/g;
810
811     print "<refentry>\n";
812     print "<refentryinfo>\n";
813     print " <title>LINUX</title>\n";
814     print " <productname>Kernel Hackers Manual</productname>\n";
815     print " <date>$man_date</date>\n";
816     print "</refentryinfo>\n";
817     print "<refmeta>\n";
818     print " <refentrytitle><phrase id=\"$id\">typedef ".$args{'typedef'}."</phrase></refentrytitle>\n";
819     print " <manvolnum>9</manvolnum>\n";
820     print "</refmeta>\n";
821     print "<refnamediv>\n";
822     print " <refname>typedef ".$args{'typedef'}."</refname>\n";
823     print " <refpurpose>\n";
824     print "  ";
825     output_highlight ($args{'purpose'});
826     print " </refpurpose>\n";
827     print "</refnamediv>\n";
828
829     print "<refsynopsisdiv>\n";
830     print " <title>Synopsis</title>\n";
831     print "  <synopsis>typedef ".$args{'typedef'}.";</synopsis>\n";
832     print "</refsynopsisdiv>\n";
833
834     output_section_xml(@_);
835
836     print "</refentry>\n\n";
837 }
838
839 # output in XML DocBook
840 sub output_intro_xml(%) {
841     my %args = %{$_[0]};
842     my ($parameter, $section);
843     my $count;
844
845     my $id = $args{'module'};
846     $id =~ s/[^A-Za-z0-9]/-/g;
847
848     # print out each section
849     $lineprefix="   ";
850     foreach $section (@{$args{'sectionlist'}}) {
851         print "<refsect1>\n <title>$section</title>\n <para>\n";
852         if ($section =~ m/EXAMPLE/i) {
853             print "<example><para>\n";
854         }
855         output_highlight($args{'sections'}{$section});
856         if ($section =~ m/EXAMPLE/i) {
857             print "</para></example>\n";
858         }
859         print " </para>\n</refsect1>\n";
860     }
861
862     print "\n\n";
863 }
864
865 # output in XML DocBook
866 sub output_function_gnome {
867     my %args = %{$_[0]};
868     my ($parameter, $section);
869     my $count;
870     my $id;
871
872     $id = $args{'module'}."-".$args{'function'};
873     $id =~ s/[^A-Za-z0-9]/-/g;
874
875     print "<sect2>\n";
876     print " <title id=\"$id\">".$args{'function'}."</title>\n";
877
878     print "  <funcsynopsis>\n";
879     print "   <funcdef>".$args{'functiontype'}." ";
880     print "<function>".$args{'function'}." ";
881     print "</function></funcdef>\n";
882
883     $count = 0;
884     if ($#{$args{'parameterlist'}} >= 0) {
885         foreach $parameter (@{$args{'parameterlist'}}) {
886             $type = $args{'parametertypes'}{$parameter};
887             if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
888                 # pointer-to-function
889                 print "   <paramdef>$1 <parameter>$parameter</parameter>)\n";
890                 print "     <funcparams>$2</funcparams></paramdef>\n";
891             } else {
892                 print "   <paramdef>".$type;
893                 print " <parameter>$parameter</parameter></paramdef>\n";
894             }
895         }
896     } else {
897         print "  <void>\n";
898     }
899     print "  </funcsynopsis>\n";
900     if ($#{$args{'parameterlist'}} >= 0) {
901         print " <informaltable pgwide=\"1\" frame=\"none\" role=\"params\">\n";
902         print "<tgroup cols=\"2\">\n";
903         print "<colspec colwidth=\"2*\">\n";
904         print "<colspec colwidth=\"8*\">\n";
905         print "<tbody>\n";
906         foreach $parameter (@{$args{'parameterlist'}}) {
907             my $parameter_name = $parameter;
908             $parameter_name =~ s/\[.*//;
909
910             print "  <row><entry align=\"right\"><parameter>$parameter</parameter></entry>\n";
911             print "   <entry>\n";
912             $lineprefix="     ";
913             output_highlight($args{'parameterdescs'}{$parameter_name});
914             print "    </entry></row>\n";
915         }
916         print " </tbody></tgroup></informaltable>\n";
917     } else {
918         print " <para>\n  None\n </para>\n";
919     }
920
921     # print out each section
922     $lineprefix="   ";
923     foreach $section (@{$args{'sectionlist'}}) {
924         print "<simplesect>\n <title>$section</title>\n";
925         if ($section =~ m/EXAMPLE/i) {
926             print "<example><programlisting>\n";
927         } else {
928         }
929         print "<para>\n";
930         output_highlight($args{'sections'}{$section});
931         print "</para>\n";
932         if ($section =~ m/EXAMPLE/i) {
933             print "</programlisting></example>\n";
934         } else {
935         }
936         print " </simplesect>\n";
937     }
938
939     print "</sect2>\n\n";
940 }
941
942 ##
943 # output function in man
944 sub output_function_man(%) {
945     my %args = %{$_[0]};
946     my ($parameter, $section);
947     my $count;
948
949     print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Kernel Hacker's Manual\" LINUX\n";
950
951     print ".SH NAME\n";
952     print $args{'function'}." \\- ".$args{'purpose'}."\n";
953
954     print ".SH SYNOPSIS\n";
955     print ".B \"".$args{'functiontype'}."\" ".$args{'function'}."\n";
956     $count = 0;
957     my $parenth = "(";
958     my $post = ",";
959     foreach my $parameter (@{$args{'parameterlist'}}) {
960         if ($count == $#{$args{'parameterlist'}}) {
961             $post = ");";
962         }
963         $type = $args{'parametertypes'}{$parameter};
964         if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
965             # pointer-to-function
966             print ".BI \"".$parenth.$1."\" ".$parameter." \") (".$2.")".$post."\"\n";
967         } else {
968             $type =~ s/([^\*])$/$1 /;
969             print ".BI \"".$parenth.$type."\" ".$parameter." \"".$post."\"\n";
970         }
971         $count++;
972         $parenth = "";
973     }
974
975     print ".SH ARGUMENTS\n";
976     foreach $parameter (@{$args{'parameterlist'}}) {
977         my $parameter_name = $parameter;
978         $parameter_name =~ s/\[.*//;
979
980         print ".IP \"".$parameter."\" 12\n";
981         output_highlight($args{'parameterdescs'}{$parameter_name});
982     }
983     foreach $section (@{$args{'sectionlist'}}) {
984         print ".SH \"", uc $section, "\"\n";
985         output_highlight($args{'sections'}{$section});
986     }
987 }
988
989 ##
990 # output enum in man
991 sub output_enum_man(%) {
992     my %args = %{$_[0]};
993     my ($parameter, $section);
994     my $count;
995
996     print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" LINUX\n";
997
998     print ".SH NAME\n";
999     print "enum ".$args{'enum'}." \\- ".$args{'purpose'}."\n";
1000
1001     print ".SH SYNOPSIS\n";
1002     print "enum ".$args{'enum'}." {\n";
1003     $count = 0;
1004     foreach my $parameter (@{$args{'parameterlist'}}) {
1005         print ".br\n.BI \"    $parameter\"\n";
1006         if ($count == $#{$args{'parameterlist'}}) {
1007             print "\n};\n";
1008             last;
1009         }
1010         else {
1011             print ", \n.br\n";
1012         }
1013         $count++;
1014     }
1015
1016     print ".SH Constants\n";
1017     foreach $parameter (@{$args{'parameterlist'}}) {
1018         my $parameter_name = $parameter;
1019         $parameter_name =~ s/\[.*//;
1020
1021         print ".IP \"".$parameter."\" 12\n";
1022         output_highlight($args{'parameterdescs'}{$parameter_name});
1023     }
1024     foreach $section (@{$args{'sectionlist'}}) {
1025         print ".SH \"$section\"\n";
1026         output_highlight($args{'sections'}{$section});
1027     }
1028 }
1029
1030 ##
1031 # output struct in man
1032 sub output_struct_man(%) {
1033     my %args = %{$_[0]};
1034     my ($parameter, $section);
1035
1036     print ".TH \"$args{'module'}\" 9 \"".$args{'type'}." ".$args{'struct'}."\" \"$man_date\" \"API Manual\" LINUX\n";
1037
1038     print ".SH NAME\n";
1039     print $args{'type'}." ".$args{'struct'}." \\- ".$args{'purpose'}."\n";
1040
1041     print ".SH SYNOPSIS\n";
1042     print $args{'type'}." ".$args{'struct'}." {\n.br\n";
1043
1044     foreach my $parameter (@{$args{'parameterlist'}}) {
1045         if ($parameter =~ /^#/) {
1046             print ".BI \"$parameter\"\n.br\n";
1047             next;
1048         }
1049         my $parameter_name = $parameter;
1050         $parameter_name =~ s/\[.*//;
1051
1052         ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
1053         $type = $args{'parametertypes'}{$parameter};
1054         if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
1055             # pointer-to-function
1056             print ".BI \"    ".$1."\" ".$parameter." \") (".$2.")"."\"\n;\n";
1057         } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
1058             print ".BI \"    ".$1."\" ".$parameter.$2." \""."\"\n;\n";
1059         } else {
1060             $type =~ s/([^\*])$/$1 /;
1061             print ".BI \"    ".$type."\" ".$parameter." \""."\"\n;\n";
1062         }
1063         print "\n.br\n";
1064     }
1065     print "};\n.br\n";
1066
1067     print ".SH Arguments\n";
1068     foreach $parameter (@{$args{'parameterlist'}}) {
1069         ($parameter =~ /^#/) && next;
1070
1071         my $parameter_name = $parameter;
1072         $parameter_name =~ s/\[.*//;
1073
1074         ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
1075         print ".IP \"".$parameter."\" 12\n";
1076         output_highlight($args{'parameterdescs'}{$parameter_name});
1077     }
1078     foreach $section (@{$args{'sectionlist'}}) {
1079         print ".SH \"$section\"\n";
1080         output_highlight($args{'sections'}{$section});
1081     }
1082 }
1083
1084 ##
1085 # output typedef in man
1086 sub output_typedef_man(%) {
1087     my %args = %{$_[0]};
1088     my ($parameter, $section);
1089
1090     print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" LINUX\n";
1091
1092     print ".SH NAME\n";
1093     print "typedef ".$args{'typedef'}." \\- ".$args{'purpose'}."\n";
1094
1095     foreach $section (@{$args{'sectionlist'}}) {
1096         print ".SH \"$section\"\n";
1097         output_highlight($args{'sections'}{$section});
1098     }
1099 }
1100
1101 sub output_intro_man(%) {
1102     my %args = %{$_[0]};
1103     my ($parameter, $section);
1104     my $count;
1105
1106     print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API Manual\" LINUX\n";
1107
1108     foreach $section (@{$args{'sectionlist'}}) {
1109         print ".SH \"$section\"\n";
1110         output_highlight($args{'sections'}{$section});
1111     }
1112 }
1113
1114 ##
1115 # output in text
1116 sub output_function_text(%) {
1117     my %args = %{$_[0]};
1118     my ($parameter, $section);
1119
1120     print "Function:\n\n";
1121     my $start=$args{'functiontype'}." ".$args{'function'}." (";
1122     print $start;
1123     my $count = 0;
1124     foreach my $parameter (@{$args{'parameterlist'}}) {
1125         $type = $args{'parametertypes'}{$parameter};
1126         if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
1127             # pointer-to-function
1128             print $1.$parameter.") (".$2;
1129         } else {
1130             print $type." ".$parameter;
1131         }
1132         if ($count != $#{$args{'parameterlist'}}) {
1133             $count++;
1134             print ",\n";
1135             print " " x length($start);
1136         } else {
1137             print ");\n\n";
1138         }
1139     }
1140
1141     print "Arguments:\n\n";
1142     foreach $parameter (@{$args{'parameterlist'}}) {
1143         my $parameter_name = $parameter;
1144         $parameter_name =~ s/\[.*//;
1145
1146         print $parameter."\n\t".$args{'parameterdescs'}{$parameter_name}."\n";
1147     }
1148     output_section_text(@_);
1149 }
1150
1151 #output sections in text
1152 sub output_section_text(%) {
1153     my %args = %{$_[0]};
1154     my $section;
1155
1156     print "\n";
1157     foreach $section (@{$args{'sectionlist'}}) {
1158         print "$section:\n\n";
1159         output_highlight($args{'sections'}{$section});
1160     }  
1161     print "\n\n";
1162 }
1163
1164 # output enum in text
1165 sub output_enum_text(%) {
1166     my %args = %{$_[0]};
1167     my ($parameter);
1168     my $count;
1169     print "Enum:\n\n";
1170
1171     print "enum ".$args{'enum'}." {\n";
1172     $count = 0;
1173     foreach $parameter (@{$args{'parameterlist'}}) {
1174         print "\t$parameter";
1175         if ($count != $#{$args{'parameterlist'}}) {
1176             $count++;
1177             print ",";
1178         }
1179         print "\n";
1180     }
1181     print "};\n\n";
1182
1183     print "Constants:\n\n";
1184     foreach $parameter (@{$args{'parameterlist'}}) {
1185         print "$parameter\n\t";
1186         print $args{'parameterdescs'}{$parameter}."\n";
1187     }
1188
1189     output_section_text(@_);
1190 }
1191
1192 # output typedef in text
1193 sub output_typedef_text(%) {
1194     my %args = %{$_[0]};
1195     my ($parameter);
1196     my $count;
1197     print "Typedef:\n\n";
1198
1199     print "typedef ".$args{'typedef'}."\n";
1200     output_section_text(@_);
1201 }
1202
1203 # output struct as text
1204 sub output_struct_text(%) {
1205     my %args = %{$_[0]};
1206     my ($parameter);
1207
1208     print $args{'type'}." ".$args{'struct'}.":\n\n";
1209     print $args{'type'}." ".$args{'struct'}." {\n";
1210     foreach $parameter (@{$args{'parameterlist'}}) {
1211         if ($parameter =~ /^#/) {
1212             print "$parameter\n";
1213             next;
1214         }
1215
1216         my $parameter_name = $parameter;
1217         $parameter_name =~ s/\[.*//;
1218
1219         ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
1220         $type = $args{'parametertypes'}{$parameter};
1221         if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
1222             # pointer-to-function
1223             print "\t$1 $parameter) ($2);\n";
1224         } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
1225             print "\t$1 $parameter$2;\n";
1226         } else {
1227             print "\t".$type." ".$parameter.";\n";
1228         }
1229     }
1230     print "};\n\n";
1231
1232     print "Members:\n\n";
1233     foreach $parameter (@{$args{'parameterlist'}}) {
1234         ($parameter =~ /^#/) && next;
1235
1236         my $parameter_name = $parameter;
1237         $parameter_name =~ s/\[.*//;
1238
1239         ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
1240         print "$parameter\n\t";
1241         print $args{'parameterdescs'}{$parameter_name}."\n";
1242     }
1243     print "\n";
1244     output_section_text(@_);
1245 }
1246
1247 sub output_intro_text(%) {
1248     my %args = %{$_[0]};
1249     my ($parameter, $section);
1250
1251     foreach $section (@{$args{'sectionlist'}}) {
1252         print " $section:\n";
1253         print "    -> ";
1254         output_highlight($args{'sections'}{$section});
1255     }
1256 }
1257
1258 ##
1259 # generic output function for typedefs
1260 sub output_declaration {
1261     no strict 'refs';
1262     my $name = shift;
1263     my $functype = shift;
1264     my $func = "output_${functype}_$output_mode";
1265     if (($function_only==0) || 
1266         ( $function_only == 1 && defined($function_table{$name})) || 
1267         ( $function_only == 2 && !defined($function_table{$name})))
1268     {
1269         &$func(@_);
1270         $section_counter++;
1271     }
1272 }
1273
1274 ##
1275 # generic output function - calls the right one based
1276 # on current output mode.
1277 sub output_intro {
1278     no strict 'refs';
1279     my $func = "output_intro_".$output_mode;
1280     &$func(@_);
1281     $section_counter++;
1282 }
1283
1284 ##
1285 # takes a declaration (struct, union, enum, typedef) and 
1286 # invokes the right handler. NOT called for functions.
1287 sub dump_declaration($$) {
1288     no strict 'refs';
1289     my ($prototype, $file) = @_;
1290     my $func = "dump_".$decl_type;
1291     &$func(@_);
1292 }
1293
1294 sub dump_union($$) {
1295     dump_struct(@_);
1296 }
1297
1298 sub dump_struct($$) {
1299     my $x = shift;
1300     my $file = shift;
1301
1302     if ($x =~/(struct|union)\s+(\w+)\s*{(.*)}/) {
1303         $declaration_name = $2;
1304         my $members = $3;
1305
1306         # ignore embedded structs or unions
1307         $members =~ s/{.*?}//g;
1308
1309         # ignore members marked private:
1310         $members =~ s/\/\*.*?private:.*?public:.*?\*\///gos;
1311         $members =~ s/\/\*.*?private:.*//gos;
1312         # strip comments:
1313         $members =~ s/\/\*.*?\*\///gos;
1314
1315         create_parameterlist($members, ';', $file);
1316
1317         output_declaration($declaration_name,
1318                            'struct',
1319                            {'struct' => $declaration_name,
1320                             'module' => $modulename,
1321                             'parameterlist' => \@parameterlist,
1322                             'parameterdescs' => \%parameterdescs,
1323                             'parametertypes' => \%parametertypes,
1324                             'sectionlist' => \@sectionlist,
1325                             'sections' => \%sections,
1326                             'purpose' => $declaration_purpose,
1327                             'type' => $decl_type
1328                            });
1329     }
1330     else {
1331         print STDERR "Error(${file}:$.): Cannot parse struct or union!\n";
1332         ++$errors;
1333     }
1334 }
1335
1336 sub dump_enum($$) {
1337     my $x = shift;
1338     my $file = shift;
1339
1340     $x =~ s@/\*.*?\*/@@gos;     # strip comments.
1341     if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
1342         $declaration_name = $1;
1343         my $members = $2;
1344
1345         foreach my $arg (split ',', $members) {
1346             $arg =~ s/^\s*(\w+).*/$1/;
1347             push @parameterlist, $arg;
1348             if (!$parameterdescs{$arg}) {
1349                 $parameterdescs{$arg} = $undescribed;
1350                 print STDERR "Warning(${file}:$.): Enum value '$arg' ".
1351                     "not described in enum '$declaration_name'\n";
1352             }
1353
1354         }
1355         
1356         output_declaration($declaration_name,
1357                            'enum',
1358                            {'enum' => $declaration_name,
1359                             'module' => $modulename,
1360                             'parameterlist' => \@parameterlist,
1361                             'parameterdescs' => \%parameterdescs,
1362                             'sectionlist' => \@sectionlist,
1363                             'sections' => \%sections,
1364                             'purpose' => $declaration_purpose
1365                            });
1366     }
1367     else {
1368         print STDERR "Error(${file}:$.): Cannot parse enum!\n";
1369         ++$errors;
1370     }
1371 }
1372
1373 sub dump_typedef($$) {
1374     my $x = shift;
1375     my $file = shift;
1376
1377     $x =~ s@/\*.*?\*/@@gos;     # strip comments.
1378     while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) {
1379         $x =~ s/\(*.\)\s*;$/;/;
1380         $x =~ s/\[*.\]\s*;$/;/;
1381     }
1382
1383     if ($x =~ /typedef.*\s+(\w+)\s*;/) {
1384         $declaration_name = $1;
1385
1386         output_declaration($declaration_name,
1387                            'typedef',
1388                            {'typedef' => $declaration_name,
1389                             'module' => $modulename,
1390                             'sectionlist' => \@sectionlist,
1391                             'sections' => \%sections,
1392                             'purpose' => $declaration_purpose
1393                            });
1394     }
1395     else {
1396         print STDERR "Error(${file}:$.): Cannot parse typedef!\n";
1397         ++$errors;
1398     }
1399 }
1400
1401 sub create_parameterlist($$$) {
1402     my $args = shift;
1403     my $splitter = shift;
1404     my $file = shift;
1405     my $type;
1406     my $param;
1407
1408     # temporarily replace commas inside function pointer definition
1409     while ($args =~ /(\([^\),]+),/) {
1410         $args =~ s/(\([^\),]+),/$1#/g;
1411     }
1412     
1413     foreach my $arg (split($splitter, $args)) {
1414         # strip comments
1415         $arg =~ s/\/\*.*\*\///;
1416         # strip leading/trailing spaces
1417         $arg =~ s/^\s*//;
1418         $arg =~ s/\s*$//;
1419         $arg =~ s/\s+/ /;
1420
1421         if ($arg =~ /^#/) {
1422             # Treat preprocessor directive as a typeless variable just to fill
1423             # corresponding data structures "correctly". Catch it later in
1424             # output_* subs.
1425             push_parameter($arg, "", $file);
1426         } elsif ($arg =~ m/\(/) {
1427             # pointer-to-function
1428             $arg =~ tr/#/,/;
1429             $arg =~ m/[^\(]+\(\*([^\)]+)\)/;
1430             $param = $1;
1431             $type = $arg;
1432             $type =~ s/([^\(]+\(\*)$param/$1/;
1433             push_parameter($param, $type, $file);
1434         } elsif ($arg) {
1435             $arg =~ s/\s*:\s*/:/g;
1436             $arg =~ s/\s*\[/\[/g;
1437
1438             my @args = split('\s*,\s*', $arg);
1439             if ($args[0] =~ m/\*/) {
1440                 $args[0] =~ s/(\*+)\s*/ $1/;
1441             }
1442             my @first_arg = split('\s+', shift @args);
1443             unshift(@args, pop @first_arg);
1444             $type = join " ", @first_arg;
1445
1446             foreach $param (@args) {
1447                 if ($param =~ m/^(\*+)\s*(.*)/) {
1448                     push_parameter($2, "$type $1", $file);
1449                 }
1450                 elsif ($param =~ m/(.*?):(\d+)/) {
1451                     push_parameter($1, "$type:$2", $file)
1452                 }
1453                 else {
1454                     push_parameter($param, $type, $file);
1455                 }
1456             }
1457         }
1458     }
1459 }
1460
1461 sub push_parameter($$$) {
1462         my $param = shift;
1463         my $type = shift;
1464         my $file = shift;
1465
1466         my $param_name = $param;
1467         $param_name =~ s/\[.*//;
1468
1469         if ($type eq "" && $param =~ /\.\.\.$/)
1470         {
1471             $type="";
1472             $parameterdescs{$param} = "variable arguments";
1473         }
1474         elsif ($type eq "" && ($param eq "" or $param eq "void"))
1475         {
1476             $type="";
1477             $param="void";
1478             $parameterdescs{void} = "no arguments";
1479         }
1480         # warn if parameter has no description
1481         # (but ignore ones starting with # as these are no parameters
1482         # but inline preprocessor statements
1483         if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) {
1484
1485             $parameterdescs{$param_name} = $undescribed;
1486
1487             if (($type eq 'function') || ($type eq 'enum')) {
1488                 print STDERR "Warning(${file}:$.): Function parameter ".
1489                     "or member '$param' not " .
1490                     "described in '$declaration_name'\n";
1491             }
1492             print STDERR "Warning(${file}:$.):".
1493                          " No description found for parameter '$param'\n";
1494             ++$warnings;
1495         }
1496
1497         push @parameterlist, $param;
1498         $parametertypes{$param} = $type;
1499 }
1500
1501 ##
1502 # takes a function prototype and the name of the current file being
1503 # processed and spits out all the details stored in the global
1504 # arrays/hashes.
1505 sub dump_function($$) {
1506     my $prototype = shift;
1507     my $file = shift;
1508
1509     $prototype =~ s/^static +//;
1510     $prototype =~ s/^extern +//;
1511     $prototype =~ s/^fastcall +//;
1512     $prototype =~ s/^asmlinkage +//;
1513     $prototype =~ s/^inline +//;
1514     $prototype =~ s/^__inline__ +//;
1515     $prototype =~ s/^#define +//; #ak added
1516     $prototype =~ s/__attribute__ \(\([a-z,]*\)\)//;
1517
1518     # Yes, this truly is vile.  We are looking for:
1519     # 1. Return type (may be nothing if we're looking at a macro)
1520     # 2. Function name
1521     # 3. Function parameters.
1522     #
1523     # All the while we have to watch out for function pointer parameters
1524     # (which IIRC is what the two sections are for), C types (these
1525     # regexps don't even start to express all the possibilities), and
1526     # so on.
1527     #
1528     # If you mess with these regexps, it's a good idea to check that
1529     # the following functions' documentation still comes out right:
1530     # - parport_register_device (function pointer parameters)
1531     # - atomic_set (macro)
1532     # - pci_match_device (long return type)
1533
1534     if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
1535         $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
1536         $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
1537         $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
1538         $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
1539         $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
1540         $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
1541         $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
1542         $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
1543         $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
1544         $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
1545         $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
1546         $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
1547         $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/)  {
1548         $return_type = $1;
1549         $declaration_name = $2;
1550         my $args = $3;
1551
1552         create_parameterlist($args, ',', $file);
1553     } else {
1554         print STDERR "Error(${file}:$.): cannot understand prototype: '$prototype'\n";
1555         ++$errors;
1556         return;
1557     }
1558
1559     output_declaration($declaration_name, 
1560                        'function',
1561                        {'function' => $declaration_name,
1562                         'module' => $modulename,
1563                         'functiontype' => $return_type,
1564                         'parameterlist' => \@parameterlist,
1565                         'parameterdescs' => \%parameterdescs,
1566                         'parametertypes' => \%parametertypes,
1567                         'sectionlist' => \@sectionlist,
1568                         'sections' => \%sections,
1569                         'purpose' => $declaration_purpose
1570                        });
1571 }
1572
1573 sub process_file($);
1574
1575 # Read the file that maps relative names to absolute names for
1576 # separate source and object directories and for shadow trees.
1577 if (open(SOURCE_MAP, "<.tmp_filelist.txt")) {
1578         my ($relname, $absname);
1579         while(<SOURCE_MAP>) {
1580                 chop();
1581                 ($relname, $absname) = (split())[0..1];
1582                 $relname =~ s:^/+::;
1583                 $source_map{$relname} = $absname;
1584         }
1585         close(SOURCE_MAP);
1586 }
1587
1588 if ($filelist) {
1589         open(FLIST,"<$filelist") or die "Can't open file list $filelist";
1590         while(<FLIST>) {
1591                 chop;
1592                 process_file($_);
1593         }
1594 }
1595
1596 foreach (@ARGV) {
1597     chomp;
1598     process_file($_);
1599 }
1600 if ($verbose && $errors) {
1601   print STDERR "$errors errors\n";
1602 }
1603 if ($verbose && $warnings) {
1604   print STDERR "$warnings warnings\n";
1605 }
1606
1607 exit($errors);
1608
1609 sub reset_state {
1610     $function = "";
1611     %constants = ();
1612     %parameterdescs = ();
1613     %parametertypes = ();
1614     @parameterlist = ();
1615     %sections = ();
1616     @sectionlist = ();
1617     $prototype = "";
1618     
1619     $state = 0;
1620 }
1621
1622 sub process_state3_function($$) { 
1623     my $x = shift;
1624     my $file = shift;
1625
1626     if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#define/)) {
1627         # do nothing
1628     }
1629     elsif ($x =~ /([^\{]*)/) {
1630         $prototype .= $1;
1631     }
1632     if (($x =~ /\{/) || ($x =~ /\#define/) || ($x =~ /;/)) {
1633         $prototype =~ s@/\*.*?\*/@@gos; # strip comments.
1634         $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
1635         $prototype =~ s@^\s+@@gos; # strip leading spaces
1636         dump_function($prototype,$file);
1637         reset_state();
1638     }
1639 }
1640
1641 sub process_state3_type($$) { 
1642     my $x = shift;
1643     my $file = shift;
1644
1645     $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
1646     $x =~ s@^\s+@@gos; # strip leading spaces
1647     $x =~ s@\s+$@@gos; # strip trailing spaces
1648     if ($x =~ /^#/) {
1649         # To distinguish preprocessor directive from regular declaration later.
1650         $x .= ";";
1651     }
1652
1653     while (1) {
1654         if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
1655             $prototype .= $1 . $2;
1656             ($2 eq '{') && $brcount++;
1657             ($2 eq '}') && $brcount--;
1658             if (($2 eq ';') && ($brcount == 0)) {
1659                 dump_declaration($prototype,$file);
1660                 reset_state();
1661                 last;
1662             }
1663             $x = $3;
1664         } else {
1665             $prototype .= $x;
1666             last;
1667         }
1668     }
1669 }
1670
1671 # replace <, >, and &
1672 sub xml_escape($) {
1673         my $text = shift;
1674         $text =~ s/\&/\\\\\\amp;/g;
1675         $text =~ s/\</\\\\\\lt;/g;
1676         $text =~ s/\>/\\\\\\gt;/g;
1677         return $text;
1678 }
1679
1680 sub process_file($) {
1681     my $file;
1682     my $identifier;
1683     my $func;
1684     my $initial_section_counter = $section_counter;
1685
1686     if (defined($ENV{'SRCTREE'})) {
1687         $file = "$ENV{'SRCTREE'}" . "/" . "@_";
1688     }
1689     else {
1690         $file = "@_";
1691     }
1692     if (defined($source_map{$file})) {
1693         $file = $source_map{$file};
1694     }
1695
1696     if (!open(IN,"<$file")) {
1697         print STDERR "Error: Cannot open file $file\n";
1698         ++$errors;
1699         return;
1700     }
1701
1702     $section_counter = 0;
1703     while (<IN>) {
1704         if ($state == 0) {
1705             if (/$doc_start/o) {
1706                 $state = 1;             # next line is always the function name
1707             }
1708         } elsif ($state == 1) { # this line is the function name (always)
1709             if (/$doc_block/o) {
1710                 $state = 4;
1711                 $contents = "";
1712                 if ( $1 eq "" ) {
1713                         $section = $section_intro;
1714                 } else {
1715                         $section = $1;
1716                 }
1717             }
1718             elsif (/$doc_decl/o) {
1719                 $identifier = $1;
1720                 if (/\s*([\w\s]+?)\s*-/) {
1721                     $identifier = $1;
1722                 }
1723
1724                 $state = 2;
1725                 if (/-(.*)/) {
1726                     $declaration_purpose = xml_escape($1);
1727                 } else {
1728                     $declaration_purpose = "";
1729                 }
1730                 if ($identifier =~ m/^struct/) {
1731                     $decl_type = 'struct';
1732                 } elsif ($identifier =~ m/^union/) {
1733                     $decl_type = 'union';
1734                 } elsif ($identifier =~ m/^enum/) {
1735                     $decl_type = 'enum';
1736                 } elsif ($identifier =~ m/^typedef/) {
1737                     $decl_type = 'typedef';
1738                 } else {
1739                     $decl_type = 'function';
1740                 }
1741
1742                 if ($verbose) {
1743                     print STDERR "Info(${file}:$.): Scanning doc for $identifier\n";
1744                 }
1745             } else {
1746                 print STDERR "Warning(${file}:$.): Cannot understand $_ on line $.",
1747                 " - I thought it was a doc line\n";
1748                 ++$warnings;
1749                 $state = 0;
1750             }
1751         } elsif ($state == 2) { # look for head: lines, and include content
1752             if (/$doc_sect/o) {
1753                 $newsection = $1;
1754                 $newcontents = $2;
1755
1756                 if ($contents ne "") {
1757                     dump_section($section, xml_escape($contents));
1758                     $section = $section_default;
1759                 }
1760
1761                 $contents = $newcontents;
1762                 if ($contents ne "") {
1763                     $contents .= "\n";
1764                 }
1765                 $section = $newsection;
1766             } elsif (/$doc_end/) {
1767
1768                 if ($contents ne "") {
1769                     dump_section($section, xml_escape($contents));
1770                     $section = $section_default;
1771                     $contents = "";
1772                 }
1773
1774                 $prototype = "";
1775                 $state = 3;
1776                 $brcount = 0;
1777 #           print STDERR "end of doc comment, looking for prototype\n";
1778             } elsif (/$doc_content/) {
1779                 # miguel-style comment kludge, look for blank lines after
1780                 # @parameter line to signify start of description
1781                 if ($1 eq "" && 
1782                         ($section =~ m/^@/ || $section eq $section_context)) {
1783                     dump_section($section, xml_escape($contents));
1784                     $section = $section_default;
1785                     $contents = "";
1786                 } else {
1787                     $contents .= $1."\n";
1788                 }
1789             } else {
1790                 # i dont know - bad line?  ignore.
1791                 print STDERR "Warning(${file}:$.): bad line: $_"; 
1792                 ++$warnings;
1793             }
1794         } elsif ($state == 3) { # scanning for function { (end of prototype)
1795             if ($decl_type eq 'function') {
1796                 process_state3_function($_, $file);
1797             } else {
1798                 process_state3_type($_, $file);
1799             }
1800         } elsif ($state == 4) {
1801                 # Documentation block
1802                 if (/$doc_block/) {
1803                         dump_section($section, $contents);
1804                         output_intro({'sectionlist' => \@sectionlist,
1805                                       'sections' => \%sections });
1806                         $contents = "";
1807                         $function = "";
1808                         %constants = ();
1809                         %parameterdescs = ();
1810                         %parametertypes = ();
1811                         @parameterlist = ();
1812                         %sections = ();
1813                         @sectionlist = ();
1814                         $prototype = "";
1815                         if ( $1 eq "" ) {
1816                                 $section = $section_intro;
1817                         } else {
1818                                 $section = $1;
1819                         }
1820                 }
1821                 elsif (/$doc_end/)
1822                 {
1823                         dump_section($section, $contents);
1824                         output_intro({'sectionlist' => \@sectionlist,
1825                                       'sections' => \%sections });
1826                         $contents = "";
1827                         $function = "";
1828                         %constants = ();
1829                         %parameterdescs = ();
1830                         %parametertypes = ();
1831                         @parameterlist = ();
1832                         %sections = ();
1833                         @sectionlist = ();
1834                         $prototype = "";
1835                         $state = 0;
1836                 }
1837                 elsif (/$doc_content/)
1838                 {
1839                         if ( $1 eq "" )
1840                         {
1841                                 $contents .= $blankline;
1842                         }
1843                         else
1844                         {
1845                                 $contents .= $1 . "\n";
1846                         }       
1847                 }
1848           }
1849     }
1850     if ($initial_section_counter == $section_counter) {
1851         print STDERR "Warning(${file}): no structured comments found\n";
1852         if ($output_mode eq "xml") {
1853             # The template wants at least one RefEntry here; make one.
1854             print "<refentry>\n";
1855             print " <refnamediv>\n";
1856             print "  <refname>\n";
1857             print "   ${file}\n";
1858             print "  </refname>\n";
1859             print "  <refpurpose>\n";
1860             print "   Document generation inconsistency\n";
1861             print "  </refpurpose>\n";
1862             print " </refnamediv>\n";
1863             print " <refsect1>\n";
1864             print "  <title>\n";
1865             print "   Oops\n";
1866             print "  </title>\n";
1867             print "  <warning>\n";
1868             print "   <para>\n";
1869             print "    The template for this document tried to insert\n";
1870             print "    the structured comment from the file\n";
1871             print "    <filename>${file}</filename> at this point,\n";
1872             print "    but none was found.\n";
1873             print "    This dummy section is inserted to allow\n";
1874             print "    generation to continue.\n";
1875             print "   </para>\n";
1876             print "  </warning>\n";
1877             print " </refsect1>\n";
1878             print "</refentry>\n";
1879         }
1880     }
1881 }