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