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