This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
XS::APItest: Flatten src for utf16_to_utf8_reversed
[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.  Any functions not listed here are
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.  Some macros are provided for compatibility with the older,
381 unadorned names, but this support may be disabled in a future release.
382
383 Perl was originally written to handle US-ASCII only (that is characters
384 whose ordinal numbers are in the range 0 - 127).
385 And documentation and comments may still use the term ASCII, when
386 sometimes in fact the entire range from 0 - 255 is meant.
387
388 Note that Perl can be compiled and run under EBCDIC (See L<perlebcdic>)
389 or ASCII.  Most of the documentation (and even comments in the code)
390 ignore the EBCDIC possibility.  
391 For almost all purposes the differences are transparent.
392 As an example, under EBCDIC,
393 instead of UTF-8, UTF-EBCDIC is used to encode Unicode strings, and so
394 whenever this documentation refers to C<utf8>
395 (and variants of that name, including in function names),
396 it also (essentially transparently) means C<UTF-EBCDIC>.
397 But the ordinals of characters differ between ASCII, EBCDIC, and
398 the UTF- encodings, and a string encoded in UTF-EBCDIC may occupy more bytes
399 than in UTF-8.
400
401 The listing below is alphabetical, case insensitive.
402
403 _EOB_
404
405 =head1 AUTHORS
406
407 Until May 1997, this document was maintained by Jeff Okamoto
408 <okamoto@corp.hp.com>.  It is now maintained as part of Perl itself.
409
410 With lots of help and suggestions from Dean Roehrich, Malcolm Beattie,
411 Andreas Koenig, Paul Hudson, Ilya Zakharevich, Paul Marquess, Neil
412 Bowers, Matthew Green, Tim Bunce, Spider Boardman, Ulrich Pfeifer,
413 Stephen McCamant, and Gurusamy Sarathy.
414
415 API Listing originally by Dean Roehrich <roehrich@cray.com>.
416
417 Updated to be autogenerated from comments in the source by Benjamin Stuhl.
418
419 =head1 SEE ALSO
420
421 L<perlguts>, L<perlxs>, L<perlxstut>, L<perlintern>
422
423 _EOE_
424
425 # List of non-static internal functions
426 my @missing_guts =
427  grep $funcflags{$_}{flags} !~ /[As]/ && !$docs{guts}{$_}, keys %funcflags;
428
429 output('perlintern', <<'END', $docs{guts}, \@missing_guts, <<'END');
430 =head1 NAME
431
432 perlintern - autogenerated documentation of purely B<internal>
433                  Perl functions
434
435 =head1 DESCRIPTION
436 X<internal Perl functions> X<interpreter functions>
437
438 This file is the autogenerated documentation of functions in the
439 Perl interpreter that are documented using Perl's internal documentation
440 format but are not marked as part of the Perl API.  In other words,
441 B<they are not for use in extensions>!
442
443 END
444
445 =head1 AUTHORS
446
447 The autodocumentation system was originally added to the Perl core by
448 Benjamin Stuhl.  Documentation is by whoever was kind enough to
449 document their functions.
450
451 =head1 SEE ALSO
452
453 L<perlguts>, L<perlapi>
454
455 END