This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
typo fixes for root level scripts
[perl5.git] / autodoc.pl
1 #!/usr/bin/perl -w
2
3 # Unconditionally regenerate:
4 #
5 #    pod/perlintern.pod
6 #    pod/perlapi.pod
7 #
8 # from information stored in
9 #
10 #    embed.fnc
11 #    plus all the .c and .h files listed in MANIFEST
12 #
13 # Has an optional arg, which is the directory to chdir to before reading
14 # MANIFEST and *.[ch].
15 #
16 # This script is normally invoked as part of 'make all', but is also
17 # called from regen.pl.
18 #
19 # '=head1' are the only headings looked for.  If the next line after the
20 # heading begins with a word character, it is considered to be the first line
21 # of documentation that applies to the heading itself.  That is, it is output
22 # immediately after the heading, before the first function, and not indented.
23 # The next input line that is a pod directive terminates this heading-level
24 # documentation.
25
26 use strict;
27
28 #
29 # See database of global and static function prototypes in embed.fnc
30 # This is used to generate prototype headers under various configurations,
31 # export symbols lists for different platforms, and macros to provide an
32 # implicit interpreter context argument.
33 #
34
35 my %docs;
36 my %funcflags;
37 my %macro = (
38              ax => 1,
39              items => 1,
40              ix => 1,
41              svtype => 1,
42             );
43 my %missing;
44
45 my $curheader = "Unknown section";
46
47 sub autodoc ($$) { # parse a file and extract documentation info
48     my($fh,$file) = @_;
49     my($in, $doc, $line, $header_doc);
50 FUNC:
51     while (defined($in = <$fh>)) {
52         if ($in =~ /^#\s*define\s+([A-Za-z_][A-Za-z_0-9]+)\(/ &&
53             ($file ne 'embed.h' || $file ne 'proto.h')) {
54             $macro{$1} = $file;
55             next FUNC;
56         }
57         if ($in=~ /^=head1 (.*)/) {
58             $curheader = $1;
59
60             # If the next line begins with a word char, then is the start of
61             # heading-level documentation.
62             if (defined($doc = <$fh>)) {
63                 if ($doc !~ /^\w/) {
64                     $in = $doc;
65                     redo FUNC;
66                 }
67                 $header_doc = $doc;
68                 $line++;
69
70                 # Continue getting the heading-level documentation until read
71                 # in any pod directive (or as a fail-safe, find a closing
72                 # comment to this pod in a C language file
73 HDR_DOC:
74                 while (defined($doc = <$fh>)) {
75                     if ($doc =~ /^=\w/) {
76                         $in = $doc;
77                         redo FUNC;
78                     }
79                     $line++;
80
81                     if ($doc =~ m:^\s*\*/$:) {
82                         warn "=cut missing? $file:$line:$doc";;
83                         last HDR_DOC;
84                     }
85                     $header_doc .= $doc;
86                 }
87             }
88             next FUNC;
89         }
90         $line++;
91         if ($in =~ /^=for\s+apidoc\s+(.*?)\s*\n/) {
92             my $proto = $1;
93             $proto = "||$proto" unless $proto =~ /\|/;
94             my($flags, $ret, $name, @args) = split /\|/, $proto;
95             my $docs = "";
96 DOC:
97             while (defined($doc = <$fh>)) {
98                 $line++;
99                 last DOC if $doc =~ /^=\w+/;
100                 if ($doc =~ m:^\*/$:) {
101                     warn "=cut missing? $file:$line:$doc";;
102                     last DOC;
103                 }
104                 $docs .= $doc;
105             }
106             $docs = "\n$docs" if $docs and $docs !~ /^\n/;
107
108             # Check the consistency of the flags
109             my ($embed_where, $inline_where);
110             my ($embed_may_change, $inline_may_change);
111
112             my $docref = delete $funcflags{$name};
113             if ($docref and %$docref) {
114                 $embed_where = $docref->{flags} =~ /A/ ? 'api' : 'guts';
115                 $embed_may_change = $docref->{flags} =~ /M/;
116                 $flags .= 'D' if $docref->{flags} =~ /D/;
117             } else {
118                 $missing{$name} = $file;
119             }
120             if ($flags =~ /m/) {
121                 $inline_where = $flags =~ /A/ ? 'api' : 'guts';
122                 $inline_may_change = $flags =~ /x/;
123
124                 if (defined $embed_where && $inline_where ne $embed_where) {
125                     warn "Function '$name' inconsistency: embed.fnc says $embed_where, Pod says $inline_where";
126                 }
127
128                 if (defined $embed_may_change
129                     && $inline_may_change ne $embed_may_change) {
130                     my $message = "Function '$name' inconsistency: ";
131                     if ($embed_may_change) {
132                         $message .= "embed.fnc says 'may change', Pod does not";
133                     } else {
134                         $message .= "Pod says 'may change', embed.fnc does not";
135                     }
136                     warn $message;
137                 }
138             } elsif (!defined $embed_where) {
139                 warn "Unable to place $name!\n";
140                 next;
141             } else {
142                 $inline_where = $embed_where;
143                 $flags .= 'x' if $embed_may_change;
144                 @args = @{$docref->{args}};
145                 $ret = $docref->{retval};
146             }
147
148             $docs{$inline_where}{$curheader}{$name}
149                 = [$flags, $docs, $ret, $file, @args];
150
151             # Create a special entry with an empty-string name for the
152             # heading-level documentation.
153             if (defined $header_doc) {
154                 $docs{$inline_where}{$curheader}{""} = $header_doc;
155                 undef $header_doc;
156             }
157
158             if (defined $doc) {
159                 if ($doc =~ /^=(?:for|head)/) {
160                     $in = $doc;
161                     redo FUNC;
162                 }
163             } else {
164                 warn "$file:$line:$in";
165             }
166         }
167     }
168 }
169
170 sub docout ($$$) { # output the docs for one function
171     my($fh, $name, $docref) = @_;
172     my($flags, $docs, $ret, $file, @args) = @$docref;
173     $name =~ s/\s*$//;
174
175     if ($flags =~ /D/) {
176         $docs = "\n\nDEPRECATED!  It is planned to remove this function from a
177 future release of Perl.  Do not use it for new code; remove it from
178 existing code.\n\n$docs";
179     }
180     else {
181         $docs = "\n\nNOTE: this function is experimental and may change or be
182 removed without notice.\n\n$docs" if $flags =~ /x/;
183     }
184     $docs .= "NOTE: the perl_ form of this function is deprecated.\n\n"
185         if $flags =~ /p/;
186     $docs .= "NOTE: this function must be explicitly called as Perl_$name with an aTHX_ parameter.\n\n"
187         if $flags =~ /o/;
188
189     print $fh "=item $name\nX<$name>\n$docs";
190
191     if ($flags =~ /U/) { # no usage
192         # nothing
193     } elsif ($flags =~ /s/) { # semicolon ("dTHR;")
194         print $fh "\t\t$name;\n\n";
195     } elsif ($flags =~ /n/) { # no args
196         print $fh "\t$ret\t$name\n\n";
197     } else { # full usage
198         my $p            = $flags =~ /o/; # no #define foo Perl_foo
199         my $n            = "Perl_"x$p . $name;
200         my $large_ret    = length $ret > 7;
201         my $indent_size  = 7+8 # nroff: 7 under =head + 8 under =item
202                           +8+($large_ret ? 1 + length $ret : 8)
203                           +length($n) + 1;
204         my $indent;
205         print $fh "\t$ret" . ($large_ret ? ' ' : "\t") . "$n(";
206         my $long_args;
207         for (@args) {
208             if ($indent_size + 2 + length > 79) {
209                 $long_args=1;
210                 $indent_size -= length($n) - 3;
211                 last;
212             }
213         }
214         my $args = '';
215         if ($p) {
216             $args = @args ? "pTHX_ " : "pTHX";
217             if ($long_args) { print $fh $args; $args = '' }
218         }
219         $long_args and print $fh "\n";
220         my $first = !$long_args;
221         while () {
222             if (!@args or
223                  length $args
224                  && $indent_size + 3 + length($args[0]) + length $args > 79
225             ) {
226                 print $fh
227                   $first ? '' : (
228                     $indent //=
229                        "\t".($large_ret ? " " x (1+length $ret) : "\t")
230                       ." "x($long_args ? 4 : 1 + length $n)
231                   ),
232                   $args, (","x($args ne 'pTHX_ ') . "\n")x!!@args;
233                 $args = $first = '';
234             }
235             @args or last;
236             $args .= ", "x!!(length $args && $args ne 'pTHX_ ')
237                    . shift @args;
238         }
239         if ($long_args) { print $fh "\n", substr $indent, 0, -4 }
240         print $fh ")\n\n";
241     }
242     print $fh "=for hackers\nFound in file $file\n\n";
243 }
244
245 sub output {
246     my ($podname, $header, $dochash, $missing, $footer) = @_;
247     my $filename = "pod/$podname.pod";
248     open my $fh, '>', $filename or die "Can't open $filename: $!";
249
250     print $fh <<"_EOH_", $header;
251 -*- buffer-read-only: t -*-
252
253 !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
254 This file is built by $0 extracting documentation from the C source
255 files.
256
257 _EOH_
258
259     my $key;
260     # case insensitive sort, with fallback for determinacy
261     for $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$dochash) {
262         my $section = $dochash->{$key}; 
263         print $fh "\n=head1 $key\n\n";
264
265         # Output any heading-level documentation and delete so won't get in
266         # the way later
267         if (exists $section->{""}) {
268             print $fh $section->{""} . "\n";
269             delete $section->{""};
270         }
271         print $fh "=over 8\n\n";
272
273         # Again, fallback for determinacy
274         for my $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$section) {
275             docout($fh, $key, $section->{$key});
276         }
277         print $fh "\n=back\n";
278     }
279
280     if (@$missing) {
281         print $fh "\n=head1 Undocumented functions\n\n";
282     print $fh $podname eq 'perlapi' ? <<'_EOB_' : <<'_EOB_';
283 The following functions have been flagged as part of the public API,
284 but are currently undocumented. Use them at your own risk, as the
285 interfaces are subject to change.  Functions that are not listed in this
286 document are not intended for public use, and should NOT be used under any
287 circumstances.
288
289 If you use one of the undocumented functions below, you may wish to consider
290 creating and submitting documentation for it. If your patch is accepted, this
291 will indicate that the interface is stable (unless it is explicitly marked
292 otherwise).
293
294 =over
295
296 _EOB_
297 The following functions are currently undocumented.  If you use one of
298 them, you may wish to consider creating and submitting documentation for
299 it.
300
301 =over
302
303 _EOB_
304     for my $missing (sort @$missing) {
305         print $fh "=item $missing\nX<$missing>\n\n";
306     }
307     print $fh "=back\n\n";
308 }
309
310 print $fh $footer, <<'_EOF_';
311 =cut
312
313  ex: set ro:
314 _EOF_
315
316     close $fh or die "Can't close $filename: $!";
317 }
318
319 if (@ARGV) {
320     my $workdir = shift;
321     chdir $workdir
322         or die "Couldn't chdir to '$workdir': $!";
323 }
324
325 open IN, "embed.fnc" or die $!;
326
327 while (<IN>) {
328     chomp;
329     next if /^:/;
330     while (s|\\\s*$||) {
331         $_ .= <IN>;
332         chomp;
333     }
334     s/\s+$//;
335     next if /^\s*(#|$)/;
336
337     my ($flags, $retval, $func, @args) = split /\s*\|\s*/, $_;
338
339     next unless $func;
340
341     s/\b(NN|NULLOK)\b\s+//g for @args;
342     $func =~ s/\t//g; # clean up fields from embed.pl
343     $retval =~ s/\t//;
344
345     $funcflags{$func} = {
346                          flags => $flags,
347                          retval => $retval,
348                          args => \@args,
349                         };
350 }
351
352 my $file;
353 # glob() picks up docs from extra .c or .h files that may be in unclean
354 # development trees.
355 my $MANIFEST = do {
356   local ($/, *FH);
357   open FH, "MANIFEST" or die "Can't open MANIFEST: $!";
358   <FH>;
359 };
360
361 for $file (($MANIFEST =~ /^(\S+\.c)\t/gm), ($MANIFEST =~ /^(\S+\.h)\t/gm)) {
362     open F, "< $file" or die "Cannot open $file for docs: $!\n";
363     $curheader = "Functions in file $file\n";
364     autodoc(\*F,$file);
365     close F or die "Error closing $file: $!\n";
366 }
367
368 for (sort keys %funcflags) {
369     next unless $funcflags{$_}{flags} =~ /d/;
370     warn "no docs for $_\n"
371 }
372
373 foreach (sort keys %missing) {
374     next if $macro{$_};
375     # Heuristics for known not-a-function macros:
376     next if /^[A-Z]/;
377     next if /^dj?[A-Z]/;
378
379     warn "Function '$_', documented in $missing{$_}, not listed in embed.fnc";
380 }
381
382 # walk table providing an array of components in each line to
383 # subroutine, printing the result
384
385 # List of funcs in the public API that aren't also marked as experimental nor
386 # deprecated.
387 my @missing_api = grep $funcflags{$_}{flags} =~ /A/ && $funcflags{$_}{flags} !~ /[MD]/ && !$docs{api}{$_}, keys %funcflags;
388 output('perlapi', <<'_EOB_', $docs{api}, \@missing_api, <<'_EOE_');
389 =head1 NAME
390
391 perlapi - autogenerated documentation for the perl public API
392
393 =head1 DESCRIPTION
394 X<Perl API> X<API> X<api>
395
396 This file contains the documentation of the perl public API generated by
397 F<embed.pl>, specifically a listing of functions, macros, flags, and variables
398 that may be used by extension writers.  L<At the end|/Undocumented functions>
399 is a list of functions which have yet to be documented.  The interfaces of
400 those are subject to change without notice.  Any functions not listed here are
401 not part of the public API, and should not be used by extension writers at
402 all.  For these reasons, blindly using functions listed in proto.h is to be
403 avoided when writing extensions.
404
405 Note that all Perl API global variables must be referenced with the C<PL_>
406 prefix.  Some macros are provided for compatibility with the older,
407 unadorned names, but this support may be disabled in a future release.
408
409 Perl was originally written to handle US-ASCII only (that is characters
410 whose ordinal numbers are in the range 0 - 127).
411 And documentation and comments may still use the term ASCII, when
412 sometimes in fact the entire range from 0 - 255 is meant.
413
414 Note that Perl can be compiled and run under EBCDIC (See L<perlebcdic>)
415 or ASCII.  Most of the documentation (and even comments in the code)
416 ignore the EBCDIC possibility.  
417 For almost all purposes the differences are transparent.
418 As an example, under EBCDIC,
419 instead of UTF-8, UTF-EBCDIC is used to encode Unicode strings, and so
420 whenever this documentation refers to C<utf8>
421 (and variants of that name, including in function names),
422 it also (essentially transparently) means C<UTF-EBCDIC>.
423 But the ordinals of characters differ between ASCII, EBCDIC, and
424 the UTF- encodings, and a string encoded in UTF-EBCDIC may occupy more bytes
425 than in UTF-8.
426
427 The listing below is alphabetical, case insensitive.
428
429 _EOB_
430
431 =head1 AUTHORS
432
433 Until May 1997, this document was maintained by Jeff Okamoto
434 <okamoto@corp.hp.com>.  It is now maintained as part of Perl itself.
435
436 With lots of help and suggestions from Dean Roehrich, Malcolm Beattie,
437 Andreas Koenig, Paul Hudson, Ilya Zakharevich, Paul Marquess, Neil
438 Bowers, Matthew Green, Tim Bunce, Spider Boardman, Ulrich Pfeifer,
439 Stephen McCamant, and Gurusamy Sarathy.
440
441 API Listing originally by Dean Roehrich <roehrich@cray.com>.
442
443 Updated to be autogenerated from comments in the source by Benjamin Stuhl.
444
445 =head1 SEE ALSO
446
447 L<perlguts>, L<perlxs>, L<perlxstut>, L<perlintern>
448
449 _EOE_
450
451 # List of non-static internal functions
452 my @missing_guts =
453  grep $funcflags{$_}{flags} !~ /[As]/ && !$docs{guts}{$_}, keys %funcflags;
454
455 output('perlintern', <<'END', $docs{guts}, \@missing_guts, <<'END');
456 =head1 NAME
457
458 perlintern - autogenerated documentation of purely B<internal>
459                  Perl functions
460
461 =head1 DESCRIPTION
462 X<internal Perl functions> X<interpreter functions>
463
464 This file is the autogenerated documentation of functions in the
465 Perl interpreter that are documented using Perl's internal documentation
466 format but are not marked as part of the Perl API. In other words,
467 B<they are not for use in extensions>!
468
469 END
470
471 =head1 AUTHORS
472
473 The autodocumentation system was originally added to the Perl core by
474 Benjamin Stuhl. Documentation is by whoever was kind enough to
475 document their functions.
476
477 =head1 SEE ALSO
478
479 L<perlguts>, L<perlapi>
480
481 END