This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
autodoc.pl: Add note for deprecated functions
[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 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 .= "NOTE: this function is experimental and may change or be
182 removed without notice.\n\n" 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.
386 my @missing_api = grep $funcflags{$_}{flags} =~ /A/ && $funcflags{$_}{flags} !~ /M/ && !$docs{api}{$_}, keys %funcflags;
387 output('perlapi', <<'_EOB_', $docs{api}, \@missing_api, <<'_EOE_');
388 =head1 NAME
389
390 perlapi - autogenerated documentation for the perl public API
391
392 =head1 DESCRIPTION
393 X<Perl API> X<API> X<api>
394
395 This file contains the documentation of the perl public API generated by
396 F<embed.pl>, specifically a listing of functions, macros, flags, and variables
397 that may be used by extension writers.  L<At the end|/Undocumented functions>
398 is a list of functions which have yet to be documented.  The interfaces of
399 those are subject to change without notice.  Any functions not listed here are
400 not part of the public API, and should not be used by extension writers at
401 all.  For these reasons, blindly using functions listed in proto.h is to be
402 avoided when writing extensions.
403
404 Note that all Perl API global variables must be referenced with the C<PL_>
405 prefix.  Some macros are provided for compatibility with the older,
406 unadorned names, but this support may be disabled in a future release.
407
408 Perl was originally written to handle US-ASCII only (that is characters
409 whose ordinal numbers are in the range 0 - 127).
410 And documentation and comments may still use the term ASCII, when
411 sometimes in fact the entire range from 0 - 255 is meant.
412
413 Note that Perl can be compiled and run under EBCDIC (See L<perlebcdic>)
414 or ASCII.  Most of the documentation (and even comments in the code)
415 ignore the EBCDIC possibility.  
416 For almost all purposes the differences are transparent.
417 As an example, under EBCDIC,
418 instead of UTF-8, UTF-EBCDIC is used to encode Unicode strings, and so
419 whenever this documentation refers to C<utf8>
420 (and variants of that name, including in function names),
421 it also (essentially transparently) means C<UTF-EBCDIC>.
422 But the ordinals of characters differ between ASCII, EBCDIC, and
423 the UTF- encodings, and a string encoded in UTF-EBCDIC may occupy more bytes
424 than in UTF-8.
425
426 The listing below is alphabetical, case insensitive.
427
428 _EOB_
429
430 =head1 AUTHORS
431
432 Until May 1997, this document was maintained by Jeff Okamoto
433 <okamoto@corp.hp.com>.  It is now maintained as part of Perl itself.
434
435 With lots of help and suggestions from Dean Roehrich, Malcolm Beattie,
436 Andreas Koenig, Paul Hudson, Ilya Zakharevich, Paul Marquess, Neil
437 Bowers, Matthew Green, Tim Bunce, Spider Boardman, Ulrich Pfeifer,
438 Stephen McCamant, and Gurusamy Sarathy.
439
440 API Listing originally by Dean Roehrich <roehrich@cray.com>.
441
442 Updated to be autogenerated from comments in the source by Benjamin Stuhl.
443
444 =head1 SEE ALSO
445
446 L<perlguts>, L<perlxs>, L<perlxstut>, L<perlintern>
447
448 _EOE_
449
450 # List of non-static internal functions
451 my @missing_guts =
452  grep $funcflags{$_}{flags} !~ /[As]/ && !$docs{guts}{$_}, keys %funcflags;
453
454 output('perlintern', <<'END', $docs{guts}, \@missing_guts, <<'END');
455 =head1 NAME
456
457 perlintern - autogenerated documentation of purely B<internal>
458                  Perl functions
459
460 =head1 DESCRIPTION
461 X<internal Perl functions> X<interpreter functions>
462
463 This file is the autogenerated documentation of functions in the
464 Perl interpreter that are documented using Perl's internal documentation
465 format but are not marked as part of the Perl API. In other words,
466 B<they are not for use in extensions>!
467
468 END
469
470 =head1 AUTHORS
471
472 The autodocumentation system was originally added to the Perl core by
473 Benjamin Stuhl. Documentation is by whoever was kind enough to
474 document their functions.
475
476 =head1 SEE ALSO
477
478 L<perlguts>, L<perlapi>
479
480 END