This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
lib/locale.t: Refactor some tests common to 2 branches
[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 sort_helper {
253     # Do a case-insensitive dictionary sort, with only alphabetics
254     # significant, falling back to using everything for determinancy
255     return (uc($a =~ s/[[^:alpha]]//r) cmp uc($b =~ s/[[^:alpha]]//r))
256            || uc($a) cmp uc($b)
257            || $a cmp $b;
258 }
259
260 sub output {
261     my ($podname, $header, $dochash, $missing, $footer) = @_;
262     my $fh = open_new("pod/$podname.pod", undef,
263                       {by => "$0 extracting documentation",
264                        from => 'the C source files'}, 1);
265
266     print $fh $header;
267
268     my $key;
269     for $key (sort sort_helper keys %$dochash) {
270         my $section = $dochash->{$key}; 
271         print $fh "\n=head1 $key\n\n";
272
273         # Output any heading-level documentation and delete so won't get in
274         # the way later
275         if (exists $section->{""}) {
276             print $fh $section->{""} . "\n";
277             delete $section->{""};
278         }
279         print $fh "=over 8\n\n";
280
281         for my $key (sort sort_helper keys %$section) {
282             docout($fh, $key, $section->{$key});
283         }
284         print $fh "\n=back\n";
285     }
286
287     if (@$missing) {
288         print $fh "\n=head1 Undocumented functions\n\n";
289     print $fh $podname eq 'perlapi' ? <<'_EOB_' : <<'_EOB_';
290 The following functions have been flagged as part of the public API,
291 but are currently undocumented.  Use them at your own risk, as the
292 interfaces are subject to change.  Functions that are not listed in this
293 document are not intended for public use, and should NOT be used under any
294 circumstances.
295
296 If you use one of the undocumented functions below, you may wish to consider
297 creating and submitting documentation
298 for it.  If your patch is accepted, this
299 will indicate that the interface is stable (unless it is explicitly marked
300 otherwise).
301
302 =over
303
304 _EOB_
305 The following functions are currently undocumented.  If you use one of
306 them, you may wish to consider creating and submitting documentation for
307 it.
308
309 =over
310
311 _EOB_
312     for my $missing (sort @$missing) {
313         print $fh "=item $missing\nX<$missing>\n\n";
314     }
315     print $fh "=back\n\n";
316 }
317     print $fh $footer, "=cut\n";
318
319     read_only_bottom_close_and_rename($fh);
320 }
321
322 foreach (@{(setup_embed())[0]}) {
323     next if @$_ < 2;
324     my ($flags, $retval, $func, @args) = @$_;
325     s/\b(?:NN|NULLOK)\b\s+//g for @args;
326
327     $funcflags{$func} = {
328                          flags => $flags,
329                          retval => $retval,
330                          args => \@args,
331                         };
332 }
333
334 # glob() picks up docs from extra .c or .h files that may be in unclean
335 # development trees.
336 open my $fh, '<', 'MANIFEST'
337     or die "Can't open MANIFEST: $!";
338 while (my $line = <$fh>) {
339     next unless my ($file) = $line =~ /^(\S+\.[ch])\t/;
340
341     open F, "< $file" or die "Cannot open $file for docs: $!\n";
342     $curheader = "Functions in file $file\n";
343     autodoc(\*F,$file);
344     close F or die "Error closing $file: $!\n";
345 }
346 close $fh or die "Error whilst reading MANIFEST: $!";
347
348 for (sort keys %funcflags) {
349     next unless $funcflags{$_}{flags} =~ /d/;
350     warn "no docs for $_\n"
351 }
352
353 foreach (sort keys %missing) {
354     next if $macro{$_};
355     # Heuristics for known not-a-function macros:
356     next if /^[A-Z]/;
357     next if /^dj?[A-Z]/;
358
359     warn "Function '$_', documented in $missing{$_}, not listed in embed.fnc";
360 }
361
362 # walk table providing an array of components in each line to
363 # subroutine, printing the result
364
365 # List of funcs in the public API that aren't also marked as experimental nor
366 # deprecated.
367 my @missing_api = grep $funcflags{$_}{flags} =~ /A/ && $funcflags{$_}{flags} !~ /[MD]/ && !$docs{api}{$_}, keys %funcflags;
368 output('perlapi', <<'_EOB_', $docs{api}, \@missing_api, <<'_EOE_');
369 =head1 NAME
370
371 perlapi - autogenerated documentation for the perl public API
372
373 =head1 DESCRIPTION
374 X<Perl API> X<API> X<api>
375
376 This file contains the documentation of the perl public API generated by
377 F<embed.pl>, specifically a listing of functions, macros, flags, and variables
378 that may be used by extension writers.  L<At the end|/Undocumented functions>
379 is a list of functions which have yet to be documented.  The interfaces of
380 those are subject to change without notice.  Anything not listed here is
381 not part of the public API, and should not be used by extension writers at
382 all.  For these reasons, blindly using functions listed in proto.h is to be
383 avoided when writing extensions.
384
385 Note that all Perl API global variables must be referenced with the C<PL_>
386 prefix.  Again, those not listed here are not to be used by extension writers,
387 and can be changed or removed without notice; same with macros.
388 Some macros are provided for compatibility with the older,
389 unadorned names, but this support may be disabled in a future release.
390
391 Perl was originally written to handle US-ASCII only (that is characters
392 whose ordinal numbers are in the range 0 - 127).
393 And documentation and comments may still use the term ASCII, when
394 sometimes in fact the entire range from 0 - 255 is meant.
395
396 Note that Perl can be compiled and run under EBCDIC (See L<perlebcdic>)
397 or ASCII.  Most of the documentation (and even comments in the code)
398 ignore the EBCDIC possibility.  
399 For almost all purposes the differences are transparent.
400 As an example, under EBCDIC,
401 instead of UTF-8, UTF-EBCDIC is used to encode Unicode strings, and so
402 whenever this documentation refers to C<utf8>
403 (and variants of that name, including in function names),
404 it also (essentially transparently) means C<UTF-EBCDIC>.
405 But the ordinals of characters differ between ASCII, EBCDIC, and
406 the UTF- encodings, and a string encoded in UTF-EBCDIC may occupy more bytes
407 than in UTF-8.
408
409 The listing below is alphabetical, case insensitive.
410
411 _EOB_
412
413 =head1 AUTHORS
414
415 Until May 1997, this document was maintained by Jeff Okamoto
416 <okamoto@corp.hp.com>.  It is now maintained as part of Perl itself.
417
418 With lots of help and suggestions from Dean Roehrich, Malcolm Beattie,
419 Andreas Koenig, Paul Hudson, Ilya Zakharevich, Paul Marquess, Neil
420 Bowers, Matthew Green, Tim Bunce, Spider Boardman, Ulrich Pfeifer,
421 Stephen McCamant, and Gurusamy Sarathy.
422
423 API Listing originally by Dean Roehrich <roehrich@cray.com>.
424
425 Updated to be autogenerated from comments in the source by Benjamin Stuhl.
426
427 =head1 SEE ALSO
428
429 L<perlguts>, L<perlxs>, L<perlxstut>, L<perlintern>
430
431 _EOE_
432
433 # List of non-static internal functions
434 my @missing_guts =
435  grep $funcflags{$_}{flags} !~ /[As]/ && !$docs{guts}{$_}, keys %funcflags;
436
437 output('perlintern', <<'END', $docs{guts}, \@missing_guts, <<'END');
438 =head1 NAME
439
440 perlintern - autogenerated documentation of purely B<internal>
441                  Perl functions
442
443 =head1 DESCRIPTION
444 X<internal Perl functions> X<interpreter functions>
445
446 This file is the autogenerated documentation of functions in the
447 Perl interpreter that are documented using Perl's internal documentation
448 format but are not marked as part of the Perl API.  In other words,
449 B<they are not for use in extensions>!
450
451 END
452
453 =head1 AUTHORS
454
455 The autodocumentation system was originally added to the Perl core by
456 Benjamin Stuhl.  Documentation is by whoever was kind enough to
457 document their functions.
458
459 =head1 SEE ALSO
460
461 L<perlguts>, L<perlapi>
462
463 END