use non-dev version for Safe
[perl.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             } else {
117                 $missing{$name} = $file;
118             }
119             if ($flags =~ /m/) {
120                 $inline_where = $flags =~ /A/ ? 'api' : 'guts';
121                 $inline_may_change = $flags =~ /x/;
122
123                 if (defined $embed_where && $inline_where ne $embed_where) {
124                     warn "Function '$name' inconsistency: embed.fnc says $embed_where, Pod says $inline_where";
125                 }
126
127                 if (defined $embed_may_change
128                     && $inline_may_change ne $embed_may_change) {
129                     my $message = "Function '$name' inconsistency: ";
130                     if ($embed_may_change) {
131                         $message .= "embed.fnc says 'may change', Pod does not";
132                     } else {
133                         $message .= "Pod says 'may change', embed.fnc does not";
134                     }
135                     warn $message;
136                 }
137             } elsif (!defined $embed_where) {
138                 warn "Unable to place $name!\n";
139                 next;
140             } else {
141                 $inline_where = $embed_where;
142                 $flags .= 'x' if $embed_may_change;
143                 @args = @{$docref->{args}};
144                 $ret = $docref->{retval};
145             }
146
147             $docs{$inline_where}{$curheader}{$name}
148                 = [$flags, $docs, $ret, $file, @args];
149
150             # Create a special entry with an empty-string name for the
151             # heading-level documentation.
152             if (defined $header_doc) {
153                 $docs{$inline_where}{$curheader}{""} = $header_doc;
154                 undef $header_doc;
155             }
156
157             if (defined $doc) {
158                 if ($doc =~ /^=(?:for|head)/) {
159                     $in = $doc;
160                     redo FUNC;
161                 }
162             } else {
163                 warn "$file:$line:$in";
164             }
165         }
166     }
167 }
168
169 sub docout ($$$) { # output the docs for one function
170     my($fh, $name, $docref) = @_;
171     my($flags, $docs, $ret, $file, @args) = @$docref;
172     $name =~ s/\s*$//;
173
174     $docs .= "NOTE: this function is experimental and may change or be
175 removed without notice.\n\n" if $flags =~ /x/;
176     $docs .= "NOTE: the perl_ form of this function is deprecated.\n\n"
177         if $flags =~ /p/;
178     $docs .= "NOTE: this function must be explicitly called as Perl_$name with an aTHX_ parameter.\n\n"
179         if $flags =~ /o/;
180
181     print $fh "=item $name\nX<$name>\n$docs";
182
183     if ($flags =~ /U/) { # no usage
184         # nothing
185     } elsif ($flags =~ /s/) { # semicolon ("dTHR;")
186         print $fh "\t\t$name;\n\n";
187     } elsif ($flags =~ /n/) { # no args
188         print $fh "\t$ret\t$name\n\n";
189     } else { # full usage
190         my $p            = $flags =~ /o/; # no #define foo Perl_foo
191         my $n            = "Perl_"x$p . $name;
192         my $large_ret    = length $ret > 7;
193         my $indent_size  = 7+8 # nroff: 7 under =head + 8 under =item
194                           +8+($large_ret ? 1 + length $ret : 8)
195                           +length($n) + 1;
196         my $indent;
197         print $fh "\t$ret" . ($large_ret ? ' ' : "\t") . "$n(";
198         my $long_args;
199         for (@args) {
200             if ($indent_size + 2 + length > 79) {
201                 $long_args=1;
202                 $indent_size -= length($n) - 3;
203                 last;
204             }
205         }
206         my $args = '';
207         if ($p) {
208             $args = @args ? "pTHX_ " : "pTHX";
209             if ($long_args) { print $fh $args; $args = '' }
210         }
211         $long_args and print $fh "\n";
212         my $first = !$long_args;
213         while () {
214             if (!@args or
215                  length $args
216                  && $indent_size + 3 + length($args[0]) + length $args > 79
217             ) {
218                 print $fh
219                   $first ? '' : (
220                     $indent //=
221                        "\t".($large_ret ? " " x (1+length $ret) : "\t")
222                       ." "x($long_args ? 4 : 1 + length $n)
223                   ),
224                   $args, (","x($args ne 'pTHX_ ') . "\n")x!!@args;
225                 $args = $first = '';
226             }
227             @args or last;
228             $args .= ", "x!!(length $args && $args ne 'pTHX_ ')
229                    . shift @args;
230         }
231         if ($long_args) { print $fh "\n", substr $indent, 0, -4 }
232         print $fh ")\n\n";
233     }
234     print $fh "=for hackers\nFound in file $file\n\n";
235 }
236
237 sub output {
238     my ($podname, $header, $dochash, $missing, $footer) = @_;
239     my $filename = "pod/$podname.pod";
240     open my $fh, '>', $filename or die "Can't open $filename: $!";
241
242     print $fh <<"_EOH_", $header;
243 -*- buffer-read-only: t -*-
244
245 !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
246 This file is built by $0 extracting documentation from the C source
247 files.
248
249 _EOH_
250
251     my $key;
252     # case insensitive sort, with fallback for determinacy
253     for $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$dochash) {
254         my $section = $dochash->{$key}; 
255         print $fh "\n=head1 $key\n\n";
256
257         # Output any heading-level documentation and delete so won't get in
258         # the way later
259         if (exists $section->{""}) {
260             print $fh $section->{""} . "\n";
261             delete $section->{""};
262         }
263         print $fh "=over 8\n\n";
264
265         # Again, fallback for determinacy
266         for my $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$section) {
267             docout($fh, $key, $section->{$key});
268         }
269         print $fh "\n=back\n";
270     }
271
272     if (@$missing) {
273         print $fh "\n=head1 Undocumented functions\n\n";
274     print $fh $podname eq 'perlapi' ? <<'_EOB_' : <<'_EOB_';
275 The following functions have been flagged as part of the public API,
276 but are currently undocumented. Use them at your own risk, as the
277 interfaces are subject to change.  Functions that are not listed in this
278 document are not intended for public use, and should NOT be used under any
279 circumstances.
280
281 If you use one of the undocumented functions below, you may wish to consider
282 creating and submitting documentation for it. If your patch is accepted, this
283 will indicate that the interface is stable (unless it is explicitly marked
284 otherwise).
285
286 =over
287
288 _EOB_
289 The following functions are currently undocumented.  If you use one of
290 them, you may wish to consider creating and submitting documentation for
291 it.
292
293 =over
294
295 _EOB_
296     for my $missing (sort @$missing) {
297         print $fh "=item $missing\nX<$missing>\n\n";
298     }
299     print $fh "=back\n\n";
300 }
301
302 print $fh $footer, <<'_EOF_';
303 =cut
304
305  ex: set ro:
306 _EOF_
307
308     close $fh or die "Can't close $filename: $!";
309 }
310
311 if (@ARGV) {
312     my $workdir = shift;
313     chdir $workdir
314         or die "Couldn't chdir to '$workdir': $!";
315 }
316
317 open IN, "embed.fnc" or die $!;
318
319 while (<IN>) {
320     chomp;
321     next if /^:/;
322     while (s|\\\s*$||) {
323         $_ .= <IN>;
324         chomp;
325     }
326     s/\s+$//;
327     next if /^\s*(#|$)/;
328
329     my ($flags, $retval, $func, @args) = split /\s*\|\s*/, $_;
330
331     next unless $func;
332
333     s/\b(NN|NULLOK)\b\s+//g for @args;
334     $func =~ s/\t//g; # clean up fields from embed.pl
335     $retval =~ s/\t//;
336
337     $funcflags{$func} = {
338                          flags => $flags,
339                          retval => $retval,
340                          args => \@args,
341                         };
342 }
343
344 my $file;
345 # glob() picks up docs from extra .c or .h files that may be in unclean
346 # development trees.
347 my $MANIFEST = do {
348   local ($/, *FH);
349   open FH, "MANIFEST" or die "Can't open MANIFEST: $!";
350   <FH>;
351 };
352
353 for $file (($MANIFEST =~ /^(\S+\.c)\t/gm), ($MANIFEST =~ /^(\S+\.h)\t/gm)) {
354     open F, "< $file" or die "Cannot open $file for docs: $!\n";
355     $curheader = "Functions in file $file\n";
356     autodoc(\*F,$file);
357     close F or die "Error closing $file: $!\n";
358 }
359
360 for (sort keys %funcflags) {
361     next unless $funcflags{$_}{flags} =~ /d/;
362     warn "no docs for $_\n"
363 }
364
365 foreach (sort keys %missing) {
366     next if $macro{$_};
367     # Heuristics for known not-a-function macros:
368     next if /^[A-Z]/;
369     next if /^dj?[A-Z]/;
370
371     warn "Function '$_', documented in $missing{$_}, not listed in embed.fnc";
372 }
373
374 # walk table providing an array of components in each line to
375 # subroutine, printing the result
376
377 # List of funcs in the public API that aren't also marked as experimental.
378 my @missing_api = grep $funcflags{$_}{flags} =~ /A/ && $funcflags{$_}{flags} !~ /M/ && !$docs{api}{$_}, keys %funcflags;
379 output('perlapi', <<'_EOB_', $docs{api}, \@missing_api, <<'_EOE_');
380 =head1 NAME
381
382 perlapi - autogenerated documentation for the perl public API
383
384 =head1 DESCRIPTION
385 X<Perl API> X<API> X<api>
386
387 This file contains the documentation of the perl public API generated by
388 F<embed.pl>, specifically a listing of functions, macros, flags, and variables
389 that may be used by extension writers.  L<At the end|/Undocumented functions>
390 is a list of functions which have yet to be documented.  The interfaces of
391 those are subject to change without notice.  Any functions not listed here are
392 not part of the public API, and should not be used by extension writers at
393 all.  For these reasons, blindly using functions listed in proto.h is to be
394 avoided when writing extensions.
395
396 Note that all Perl API global variables must be referenced with the C<PL_>
397 prefix.  Some macros are provided for compatibility with the older,
398 unadorned names, but this support may be disabled in a future release.
399
400 Perl was originally written to handle US-ASCII only (that is characters
401 whose ordinal numbers are in the range 0 - 127).
402 And documentation and comments may still use the term ASCII, when
403 sometimes in fact the entire range from 0 - 255 is meant.
404
405 Note that Perl can be compiled and run under EBCDIC (See L<perlebcdic>)
406 or ASCII.  Most of the documentation (and even comments in the code)
407 ignore the EBCDIC possibility.  
408 For almost all purposes the differences are transparent.
409 As an example, under EBCDIC,
410 instead of UTF-8, UTF-EBCDIC is used to encode Unicode strings, and so
411 whenever this documentation refers to C<utf8>
412 (and variants of that name, including in function names),
413 it also (essentially transparently) means C<UTF-EBCDIC>.
414 But the ordinals of characters differ between ASCII, EBCDIC, and
415 the UTF- encodings, and a string encoded in UTF-EBCDIC may occupy more bytes
416 than in UTF-8.
417
418 Also, on some EBCDIC machines, functions that are documented as operating on
419 US-ASCII (or Basic Latin in Unicode terminology) may in fact operate on all
420 256 characters in the EBCDIC range, not just the subset corresponding to
421 US-ASCII.
422
423 The listing below is alphabetical, case insensitive.
424
425 _EOB_
426
427 =head1 AUTHORS
428
429 Until May 1997, this document was maintained by Jeff Okamoto
430 <okamoto@corp.hp.com>.  It is now maintained as part of Perl itself.
431
432 With lots of help and suggestions from Dean Roehrich, Malcolm Beattie,
433 Andreas Koenig, Paul Hudson, Ilya Zakharevich, Paul Marquess, Neil
434 Bowers, Matthew Green, Tim Bunce, Spider Boardman, Ulrich Pfeifer,
435 Stephen McCamant, and Gurusamy Sarathy.
436
437 API Listing originally by Dean Roehrich <roehrich@cray.com>.
438
439 Updated to be autogenerated from comments in the source by Benjamin Stuhl.
440
441 =head1 SEE ALSO
442
443 L<perlguts>, L<perlxs>, L<perlxstut>, L<perlintern>
444
445 _EOE_
446
447 # List of non-static internal functions
448 my @missing_guts =
449  grep $funcflags{$_}{flags} !~ /[As]/ && !$docs{guts}{$_}, keys %funcflags;
450
451 output('perlintern', <<'END', $docs{guts}, \@missing_guts, <<'END');
452 =head1 NAME
453
454 perlintern - autogenerated documentation of purely B<internal>
455                  Perl functions
456
457 =head1 DESCRIPTION
458 X<internal Perl functions> X<interpreter functions>
459
460 This file is the autogenerated documentation of functions in the
461 Perl interpreter that are documented using Perl's internal documentation
462 format but are not marked as part of the Perl API. In other words,
463 B<they are not for use in extensions>!
464
465 END
466
467 =head1 AUTHORS
468
469 The autodocumentation system was originally added to the Perl core by
470 Benjamin Stuhl. Documentation is by whoever was kind enough to
471 document their functions.
472
473 =head1 SEE ALSO
474
475 L<perlguts>, L<perlapi>
476
477 END