This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
printf %s, cast appropriately.
[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 invoked as part of 'make all'
17 #
18 # '=head1' are the only headings looked for.  If the next line after the
19 # heading begins with a word character, it is considered to be the first line
20 # of documentation that applies to the heading itself.  That is, it is output
21 # immediately after the heading, before the first function, and not indented.
22 # The next input line that is a pod directive terminates this heading-level
23 # documentation.
24
25 use strict;
26
27 if (@ARGV) {
28     my $workdir = shift;
29     chdir $workdir
30         or die "Couldn't chdir to '$workdir': $!";
31 }
32 require 'regen/regen_lib.pl';
33 require 'regen/embed_lib.pl';
34
35 #
36 # See database of global and static function prototypes in embed.fnc
37 # This is used to generate prototype headers under various configurations,
38 # export symbols lists for different platforms, and macros to provide an
39 # implicit interpreter context argument.
40 #
41
42 my %docs;
43 my %funcflags;
44 my %macro = (
45              ax => 1,
46              items => 1,
47              ix => 1,
48              svtype => 1,
49             );
50 my %missing;
51
52 my $curheader = "Unknown section";
53
54 sub autodoc ($$) { # parse a file and extract documentation info
55     my($fh,$file) = @_;
56     my($in, $doc, $line, $header_doc);
57 FUNC:
58     while (defined($in = <$fh>)) {
59         if ($in =~ /^#\s*define\s+([A-Za-z_][A-Za-z_0-9]+)\(/ &&
60             ($file ne 'embed.h' || $file ne 'proto.h')) {
61             $macro{$1} = $file;
62             next FUNC;
63         }
64         if ($in=~ /^=head1 (.*)/) {
65             $curheader = $1;
66
67             # If the next line begins with a word char, then is the start of
68             # heading-level documentation.
69             if (defined($doc = <$fh>)) {
70                 if ($doc !~ /^\w/) {
71                     $in = $doc;
72                     redo FUNC;
73                 }
74                 $header_doc = $doc;
75                 $line++;
76
77                 # Continue getting the heading-level documentation until read
78                 # in any pod directive (or as a fail-safe, find a closing
79                 # comment to this pod in a C language file
80 HDR_DOC:
81                 while (defined($doc = <$fh>)) {
82                     if ($doc =~ /^=\w/) {
83                         $in = $doc;
84                         redo FUNC;
85                     }
86                     $line++;
87
88                     if ($doc =~ m:^\s*\*/$:) {
89                         warn "=cut missing? $file:$line:$doc";;
90                         last HDR_DOC;
91                     }
92                     $header_doc .= $doc;
93                 }
94             }
95             next FUNC;
96         }
97         $line++;
98         if ($in =~ /^=for\s+apidoc\s+(.*?)\s*\n/) {
99             my $proto = $1;
100             $proto = "||$proto" unless $proto =~ /\|/;
101             my($flags, $ret, $name, @args) = split /\|/, $proto;
102             my $docs = "";
103 DOC:
104             while (defined($doc = <$fh>)) {
105                 $line++;
106                 last DOC if $doc =~ /^=\w+/;
107                 if ($doc =~ m:^\*/$:) {
108                     warn "=cut missing? $file:$line:$doc";;
109                     last DOC;
110                 }
111                 $docs .= $doc;
112             }
113             $docs = "\n$docs" if $docs and $docs !~ /^\n/;
114
115             # Check the consistency of the flags
116             my ($embed_where, $inline_where);
117             my ($embed_may_change, $inline_may_change);
118
119             my $docref = delete $funcflags{$name};
120             if ($docref and %$docref) {
121                 $embed_where = $docref->{flags} =~ /A/ ? 'api' : 'guts';
122                 $embed_may_change = $docref->{flags} =~ /M/;
123                 $flags .= 'D' if $docref->{flags} =~ /D/;
124             } else {
125                 $missing{$name} = $file;
126             }
127             if ($flags =~ /m/) {
128                 $inline_where = $flags =~ /A/ ? 'api' : 'guts';
129                 $inline_may_change = $flags =~ /x/;
130
131                 if (defined $embed_where && $inline_where ne $embed_where) {
132                     warn "Function '$name' inconsistency: embed.fnc says $embed_where, Pod says $inline_where";
133                 }
134
135                 if (defined $embed_may_change
136                     && $inline_may_change ne $embed_may_change) {
137                     my $message = "Function '$name' inconsistency: ";
138                     if ($embed_may_change) {
139                         $message .= "embed.fnc says 'may change', Pod does not";
140                     } else {
141                         $message .= "Pod says 'may change', embed.fnc does not";
142                     }
143                     warn $message;
144                 }
145             } elsif (!defined $embed_where) {
146                 warn "Unable to place $name!\n";
147                 next;
148             } else {
149                 $inline_where = $embed_where;
150                 $flags .= 'x' if $embed_may_change;
151                 @args = @{$docref->{args}};
152                 $ret = $docref->{retval};
153             }
154
155             $docs{$inline_where}{$curheader}{$name}
156                 = [$flags, $docs, $ret, $file, @args];
157
158             # Create a special entry with an empty-string name for the
159             # heading-level documentation.
160             if (defined $header_doc) {
161                 $docs{$inline_where}{$curheader}{""} = $header_doc;
162                 undef $header_doc;
163             }
164
165             if (defined $doc) {
166                 if ($doc =~ /^=(?:for|head)/) {
167                     $in = $doc;
168                     redo FUNC;
169                 }
170             } else {
171                 warn "$file:$line:$in";
172             }
173         }
174     }
175 }
176
177 sub docout ($$$) { # output the docs for one function
178     my($fh, $name, $docref) = @_;
179     my($flags, $docs, $ret, $file, @args) = @$docref;
180     $name =~ s/\s*$//;
181
182     if ($flags =~ /D/) {
183         $docs = "\n\nDEPRECATED!  It is planned to remove this function from a
184 future release of Perl.  Do not use it for new code; remove it from
185 existing code.\n\n$docs";
186     }
187     else {
188         $docs = "\n\nNOTE: this function is experimental and may change or be
189 removed without notice.\n\n$docs" if $flags =~ /x/;
190     }
191     $docs .= "NOTE: the perl_ form of this function is deprecated.\n\n"
192         if $flags =~ /p/;
193     $docs .= "NOTE: this function must be explicitly called as Perl_$name with an aTHX_ parameter.\n\n"
194         if $flags =~ /o/;
195
196     print $fh "=item $name\nX<$name>\n$docs";
197
198     if ($flags =~ /U/) { # no usage
199         # nothing
200     } elsif ($flags =~ /s/) { # semicolon ("dTHR;")
201         print $fh "\t\t$name;\n\n";
202     } elsif ($flags =~ /n/) { # no args
203         print $fh "\t$ret\t$name\n\n";
204     } else { # full usage
205         my $p            = $flags =~ /o/; # no #define foo Perl_foo
206         my $n            = "Perl_"x$p . $name;
207         my $large_ret    = length $ret > 7;
208         my $indent_size  = 7+8 # nroff: 7 under =head + 8 under =item
209                           +8+($large_ret ? 1 + length $ret : 8)
210                           +length($n) + 1;
211         my $indent;
212         print $fh "\t$ret" . ($large_ret ? ' ' : "\t") . "$n(";
213         my $long_args;
214         for (@args) {
215             if ($indent_size + 2 + length > 79) {
216                 $long_args=1;
217                 $indent_size -= length($n) - 3;
218                 last;
219             }
220         }
221         my $args = '';
222         if ($p) {
223             $args = @args ? "pTHX_ " : "pTHX";
224             if ($long_args) { print $fh $args; $args = '' }
225         }
226         $long_args and print $fh "\n";
227         my $first = !$long_args;
228         while () {
229             if (!@args or
230                  length $args
231                  && $indent_size + 3 + length($args[0]) + length $args > 79
232             ) {
233                 print $fh
234                   $first ? '' : (
235                     $indent //=
236                        "\t".($large_ret ? " " x (1+length $ret) : "\t")
237                       ." "x($long_args ? 4 : 1 + length $n)
238                   ),
239                   $args, (","x($args ne 'pTHX_ ') . "\n")x!!@args;
240                 $args = $first = '';
241             }
242             @args or last;
243             $args .= ", "x!!(length $args && $args ne 'pTHX_ ')
244                    . shift @args;
245         }
246         if ($long_args) { print $fh "\n", substr $indent, 0, -4 }
247         print $fh ")\n\n";
248     }
249     print $fh "=for hackers\nFound in file $file\n\n";
250 }
251
252 sub output {
253     my ($podname, $header, $dochash, $missing, $footer) = @_;
254     my $fh = open_new("pod/$podname.pod", undef,
255                       {by => "$0 extracting documentation",
256                        from => 'the C source files'}, 1);
257
258     print $fh $header;
259
260     my $key;
261     # case insensitive sort, with fallback for determinacy
262     for $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$dochash) {
263         my $section = $dochash->{$key}; 
264         print $fh "\n=head1 $key\n\n";
265
266         # Output any heading-level documentation and delete so won't get in
267         # the way later
268         if (exists $section->{""}) {
269             print $fh $section->{""} . "\n";
270             delete $section->{""};
271         }
272         print $fh "=over 8\n\n";
273
274         # Again, fallback for determinacy
275         for my $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$section) {
276             docout($fh, $key, $section->{$key});
277         }
278         print $fh "\n=back\n";
279     }
280
281     if (@$missing) {
282         print $fh "\n=head1 Undocumented functions\n\n";
283     print $fh $podname eq 'perlapi' ? <<'_EOB_' : <<'_EOB_';
284 The following functions have been flagged as part of the public API,
285 but are currently undocumented.  Use them at your own risk, as the
286 interfaces are subject to change.  Functions that are not listed in this
287 document are not intended for public use, and should NOT be used under any
288 circumstances.
289
290 If you use one of the undocumented functions below, you may wish to consider
291 creating and submitting documentation
292 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 # glob() picks up docs from extra .c or .h files that may be in unclean
329 # development trees.
330 open my $fh, '<', 'MANIFEST'
331     or die "Can't open MANIFEST: $!";
332 while (my $line = <$fh>) {
333     next unless my ($file) = $line =~ /^(\S+\.[ch])\t/;
334
335     open F, "< $file" or die "Cannot open $file for docs: $!\n";
336     $curheader = "Functions in file $file\n";
337     autodoc(\*F,$file);
338     close F or die "Error closing $file: $!\n";
339 }
340 close $fh or die "Error whilst reading MANIFEST: $!";
341
342 for (sort keys %funcflags) {
343     next unless $funcflags{$_}{flags} =~ /d/;
344     warn "no docs for $_\n"
345 }
346
347 foreach (sort keys %missing) {
348     next if $macro{$_};
349     # Heuristics for known not-a-function macros:
350     next if /^[A-Z]/;
351     next if /^dj?[A-Z]/;
352
353     warn "Function '$_', documented in $missing{$_}, not listed in embed.fnc";
354 }
355
356 # walk table providing an array of components in each line to
357 # subroutine, printing the result
358
359 # List of funcs in the public API that aren't also marked as experimental nor
360 # deprecated.
361 my @missing_api = grep $funcflags{$_}{flags} =~ /A/ && $funcflags{$_}{flags} !~ /[MD]/ && !$docs{api}{$_}, keys %funcflags;
362 output('perlapi', <<'_EOB_', $docs{api}, \@missing_api, <<'_EOE_');
363 =head1 NAME
364
365 perlapi - autogenerated documentation for the perl public API
366
367 =head1 DESCRIPTION
368 X<Perl API> X<API> X<api>
369
370 This file contains the documentation of the perl public API generated by
371 F<embed.pl>, specifically a listing of functions, macros, flags, and variables
372 that may be used by extension writers.  L<At the end|/Undocumented functions>
373 is a list of functions which have yet to be documented.  The interfaces of
374 those are subject to change without notice.  Anything not listed here is
375 not part of the public API, and should not be used by extension writers at
376 all.  For these reasons, blindly using functions listed in proto.h is to be
377 avoided when writing extensions.
378
379 Note that all Perl API global variables must be referenced with the C<PL_>
380 prefix.  Again, those not listed here are not to be used by extension writers,
381 and can be changed or removed without notice; same with macros.
382 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