This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
embed.fnc: Add flag for bypass macro existence
[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 first non-blank line after
19 # the heading begins with a word character, it is considered to be the first 
20 # line of documentation that applies to the heading itself.  That is, it is 
21 # output immediately after the heading, before the first function, and not 
22 # indented. The next input line that is a pod directive terminates this 
23 # heading-level 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
58     # Count lines easier
59     my $get_next_line = sub { $line++; return <$fh> };
60
61 FUNC:
62     while (defined($in = $get_next_line->())) {
63         if ($in =~ /^#\s*define\s+([A-Za-z_][A-Za-z_0-9]+)\(/ &&
64             ($file ne 'embed.h' || $file ne 'proto.h')) {
65             $macro{$1} = $file;
66             next FUNC;
67         }
68         if ($in=~ /^=head1 (.*)/) {
69             $curheader = $1;
70
71             # If the next non-space line begins with a word char, then it is
72             # the start of heading-ldevel documentation.
73             if (defined($doc = $get_next_line->())) {
74                 # Skip over empty lines
75                 while ($doc =~ /^\s+$/) {
76                     if (! defined($doc = $get_next_line->())) {
77                         next FUNC;
78                     }
79                 }
80
81                 if ($doc !~ /^\w/) {
82                     $in = $doc;
83                     redo FUNC;
84                 }
85                 $header_doc = $doc;
86
87                 # Continue getting the heading-level documentation until read
88                 # in any pod directive (or as a fail-safe, find a closing
89                 # comment to this pod in a C language file
90 HDR_DOC:
91                 while (defined($doc = $get_next_line->())) {
92                     if ($doc =~ /^=\w/) {
93                         $in = $doc;
94                         redo FUNC;
95                     }
96
97                     if ($doc =~ m:^\s*\*/$:) {
98                         warn "=cut missing? $file:$line:$doc";;
99                         last HDR_DOC;
100                     }
101                     $header_doc .= $doc;
102                 }
103             }
104             next FUNC;
105         }
106         if ($in =~ /^=for\s+apidoc\s+(.*?)\s*\n/) {
107             my $proto = $1;
108             $proto = "||$proto" unless $proto =~ /\|/;
109             my($flags, $ret, $name, @args) = split /\s*\|\s*/, $proto;
110             my $docs = "";
111 DOC:
112             while (defined($doc = $get_next_line->())) {
113
114                 # Other pod commands are considered part of the current
115                 # function's docs, so can have lists, etc.
116                 last DOC if $doc =~ /^=(cut|for\s+apidoc|head)/;
117                 if ($doc =~ m:^\*/$:) {
118                     warn "=cut missing? $file:$line:$doc";;
119                     last DOC;
120                 }
121                 $docs .= $doc;
122             }
123             $docs = "\n$docs" if $docs and $docs !~ /^\n/;
124
125             # Check the consistency of the flags
126             my ($embed_where, $inline_where);
127             my ($embed_may_change, $inline_may_change);
128
129             my $embed_docref = delete $funcflags{$name};
130             if ($embed_docref and %$embed_docref) {
131                 $embed_where = $embed_docref->{flags} =~ /A/ ? 'api' : 'guts';
132                 $embed_may_change = $embed_docref->{flags} =~ /x/;
133                 $flags .= 'D' if $embed_docref->{flags} =~ /D/;
134                 $flags .= 'O' if $embed_docref->{flags} =~ /O/;
135                 $flags .= 'p' if $embed_docref->{flags} =~ /p/;
136                 $flags .= 'M' if $embed_docref->{flags} =~ /M/;
137             } else {
138                 $missing{$name} = $file;
139             }
140             if ($flags =~ /m/) {
141                 $inline_where = $flags =~ /A/ ? 'api' : 'guts';
142                 $inline_may_change = $flags =~ /x/;
143
144                 if (defined $embed_where && $inline_where ne $embed_where) {
145                     warn "Function '$name' inconsistency: embed.fnc says $embed_where, Pod says $inline_where";
146                 }
147
148                 if (defined $embed_may_change
149                     && $inline_may_change ne $embed_may_change) {
150                     my $message = "Function '$name' inconsistency: ";
151                     if ($embed_may_change) {
152                         $message .= "embed.fnc says 'may change', Pod does not";
153                     } else {
154                         $message .= "Pod says 'may change', embed.fnc does not";
155                     }
156                     warn $message;
157                 }
158             } elsif (!defined $embed_where) {
159                 warn "Unable to place $name!\n";
160                 next;
161             } else {
162                 $inline_where = $embed_where;
163                 $flags .= 'x' if $embed_may_change;
164                 @args = @{$embed_docref->{args}};
165                 $ret = $embed_docref->{retval};
166             }
167
168             if (exists $docs{$inline_where}{$curheader}{$name}) {
169                 warn "$0: duplicate API entry for '$name' in $inline_where/$curheader\n";
170                 next;
171             }
172             $docs{$inline_where}{$curheader}{$name}
173                 = [$flags, $docs, $ret, $file, @args];
174
175             # Create a special entry with an empty-string name for the
176             # heading-level documentation.
177             if (defined $header_doc) {
178                 $docs{$inline_where}{$curheader}{""} = $header_doc;
179                 undef $header_doc;
180             }
181
182             if (defined $doc) {
183                 if ($doc =~ /^=(?:for|head)/) {
184                     $in = $doc;
185                     redo FUNC;
186                 }
187             } else {
188                 warn "$file:$line:$in";
189             }
190         }
191     }
192 }
193
194 sub docout ($$$) { # output the docs for one function
195     my($fh, $name, $docref) = @_;
196     my($flags, $docs, $ret, $file, @args) = @$docref;
197     $name =~ s/\s*$//;
198
199     if ($flags =~ /D/) {
200         $docs = "\n\nDEPRECATED!  It is planned to remove this function from a
201 future release of Perl.  Do not use it for new code; remove it from
202 existing code.\n\n$docs";
203     }
204     else {
205         $docs = "\n\nNOTE: this function is experimental and may change or be
206 removed without notice.\n\n$docs" if $flags =~ /x/;
207     }
208
209     # Is Perl_, but no #define foo # Perl_foo
210     my $p = $flags =~ /p/ && $flags =~ /o/ && $flags !~ /M/;
211
212     $docs .= "NOTE: the perl_ form of this function is deprecated.\n\n"
213         if $flags =~ /O/;
214     if ($p) {
215         $docs .= "NOTE: this function must be explicitly called as Perl_$name";
216         $docs .= " with an aTHX_ parameter";
217         $docs .= ".\n\n"
218     }
219
220     print $fh "=item $name\nX<$name>\n$docs";
221
222     if ($flags =~ /U/) { # no usage
223         # nothing
224     } else {
225         if ($flags =~ /s/) { # semicolon ("dTHR;")
226             print $fh "\t\t$name;";
227         } elsif ($flags =~ /n/) { # no args
228             print $fh "\t$ret\t$name";
229         } else { # full usage
230             my $n            = "Perl_"x$p . $name;
231             my $large_ret    = length $ret > 7;
232             my $indent_size  = 7+8 # nroff: 7 under =head + 8 under =item
233                             +8+($large_ret ? 1 + length $ret : 8)
234                             +length($n) + 1;
235             my $indent;
236             print $fh "\t$ret" . ($large_ret ? ' ' : "\t") . "$n(";
237             my $long_args;
238             for (@args) {
239                 if ($indent_size + 2 + length > 79) {
240                     $long_args=1;
241                     $indent_size -= length($n) - 3;
242                     last;
243                 }
244             }
245             my $args = '';
246             if ($p) {
247                 $args = @args ? "pTHX_ " : "pTHX";
248                 if ($long_args) { print $fh $args; $args = '' }
249             }
250             $long_args and print $fh "\n";
251             my $first = !$long_args;
252             while () {
253                 if (!@args or
254                     length $args
255                     && $indent_size + 3 + length($args[0]) + length $args > 79
256                 ) {
257                     print $fh
258                     $first ? '' : (
259                         $indent //=
260                         "\t".($large_ret ? " " x (1+length $ret) : "\t")
261                         ." "x($long_args ? 4 : 1 + length $n)
262                     ),
263                     $args, (","x($args ne 'pTHX_ ') . "\n")x!!@args;
264                     $args = $first = '';
265                 }
266                 @args or last;
267                 $args .= ", "x!!(length $args && $args ne 'pTHX_ ')
268                     . shift @args;
269             }
270             if ($long_args) { print $fh "\n", substr $indent, 0, -4 }
271             print $fh ")";
272         }
273         print $fh "\n\n";
274     }
275     print $fh "=for hackers\nFound in file $file\n\n";
276 }
277
278 sub sort_helper {
279     # Do a case-insensitive dictionary sort, with only alphabetics
280     # significant, falling back to using everything for determinancy
281     return (uc($a =~ s/[[:^alpha:]]//r) cmp uc($b =~ s/[[:^alpha:]]//r))
282            || uc($a) cmp uc($b)
283            || $a cmp $b;
284 }
285
286 sub output {
287     my ($podname, $header, $dochash, $missing, $footer) = @_;
288     #
289     # strip leading '|' from each line which had been used to hide
290     # pod from pod checkers.
291     s/^\|//gm for $header, $footer;
292
293     my $fh = open_new("pod/$podname.pod", undef,
294                       {by => "$0 extracting documentation",
295                        from => 'the C source files'}, 1);
296
297     print $fh $header;
298
299     my $key;
300     for $key (sort sort_helper keys %$dochash) {
301         my $section = $dochash->{$key}; 
302         print $fh "\n=head1 $key\n\n";
303
304         # Output any heading-level documentation and delete so won't get in
305         # the way later
306         if (exists $section->{""}) {
307             print $fh $section->{""} . "\n";
308             delete $section->{""};
309         }
310         print $fh "=over 8\n\n";
311
312         for my $key (sort sort_helper keys %$section) {
313             docout($fh, $key, $section->{$key});
314         }
315         print $fh "\n=back\n";
316     }
317
318     if (@$missing) {
319         print $fh "\n=head1 Undocumented functions\n\n";
320     print $fh $podname eq 'perlapi' ? <<'_EOB_' : <<'_EOB_';
321 The following functions have been flagged as part of the public API,
322 but are currently undocumented.  Use them at your own risk, as the
323 interfaces are subject to change.  Functions that are not listed in this
324 document are not intended for public use, and should NOT be used under any
325 circumstances.
326
327 If you feel you need to use one of these functions, first send email to
328 L<perl5-porters@perl.org|mailto:perl5-porters@perl.org>.  It may be
329 that there is a good reason for the function not being documented, and it
330 should be removed from this list; or it may just be that no one has gotten
331 around to documenting it.  In the latter case, you will be asked to submit a
332 patch to document the function.  Once your patch is accepted, it will indicate
333 that the interface is stable (unless it is explicitly marked otherwise) and
334 usable by you.
335 _EOB_
336 The following functions are currently undocumented.  If you use one of
337 them, you may wish to consider creating and submitting documentation for
338 it.
339 _EOB_
340     print $fh "\n=over\n\n";
341
342     for my $missing (sort @$missing) {
343         print $fh "=item $missing\nX<$missing>\n\n";
344     }
345     print $fh "=back\n\n";
346 }
347     print $fh $footer, "=cut\n";
348
349     read_only_bottom_close_and_rename($fh);
350 }
351
352 foreach (@{(setup_embed())[0]}) {
353     next if @$_ < 2;
354     my ($flags, $retval, $func, @args) = @$_;
355     s/\b(?:NN|NULLOK)\b\s+//g for @args;
356
357     $funcflags{$func} = {
358                          flags => $flags,
359                          retval => $retval,
360                          args => \@args,
361                         };
362 }
363
364 # glob() picks up docs from extra .c or .h files that may be in unclean
365 # development trees.
366 open my $fh, '<', 'MANIFEST'
367     or die "Can't open MANIFEST: $!";
368 while (my $line = <$fh>) {
369     next unless my ($file) = $line =~ /^(\S+\.[ch])\t/;
370
371     open F, '<', $file or die "Cannot open $file for docs: $!\n";
372     $curheader = "Functions in file $file\n";
373     autodoc(\*F,$file);
374     close F or die "Error closing $file: $!\n";
375 }
376 close $fh or die "Error whilst reading MANIFEST: $!";
377
378 for (sort keys %funcflags) {
379     next unless $funcflags{$_}{flags} =~ /d/;
380     warn "no docs for $_\n"
381 }
382
383 foreach (sort keys %missing) {
384     next if $macro{$_};
385     # Heuristics for known not-a-function macros:
386     next if /^[A-Z]/;
387     next if /^dj?[A-Z]/;
388
389     warn "Function '$_', documented in $missing{$_}, not listed in embed.fnc";
390 }
391
392 # walk table providing an array of components in each line to
393 # subroutine, printing the result
394
395 # List of funcs in the public API that aren't also marked as experimental nor
396 # deprecated.
397 my @missing_api = grep $funcflags{$_}{flags} =~ /A/ && $funcflags{$_}{flags} !~ /[xD]/ && !$docs{api}{$_}, keys %funcflags;
398 output('perlapi', <<'_EOB_', $docs{api}, \@missing_api, <<'_EOE_');
399 |=encoding UTF-8
400 |
401 |=head1 NAME
402 |
403 |perlapi - autogenerated documentation for the perl public API
404 |
405 |=head1 DESCRIPTION
406 |X<Perl API> X<API> X<api>
407 |
408 |This file contains the documentation of the perl public API generated by
409 |F<embed.pl>, specifically a listing of functions, macros, flags, and variables
410 |that may be used by extension writers.  L<At the end|/Undocumented functions>
411 |is a list of functions which have yet to be documented.  The interfaces of
412 |those are subject to change without notice.  Anything not listed here is
413 |not part of the public API, and should not be used by extension writers at
414 |all.  For these reasons, blindly using functions listed in proto.h is to be
415 |avoided when writing extensions.
416 |
417 |In Perl, unlike C, a string of characters may generally contain embedded
418 |C<NUL> characters.  Sometimes in the documentation a Perl string is referred
419 |to as a "buffer" to distinguish it from a C string, but sometimes they are
420 |both just referred to as strings.
421 |
422 |Note that all Perl API global variables must be referenced with the C<PL_>
423 |prefix.  Again, those not listed here are not to be used by extension writers,
424 |and can be changed or removed without notice; same with macros.
425 |Some macros are provided for compatibility with the older,
426 |unadorned names, but this support may be disabled in a future release.
427 |
428 |Perl was originally written to handle US-ASCII only (that is characters
429 |whose ordinal numbers are in the range 0 - 127).
430 |And documentation and comments may still use the term ASCII, when
431 |sometimes in fact the entire range from 0 - 255 is meant.
432 |
433 |The non-ASCII characters below 256 can have various meanings, depending on
434 |various things.  (See, most notably, L<perllocale>.)  But usually the whole
435 |range can be referred to as ISO-8859-1.  Often, the term "Latin-1" (or
436 |"Latin1") is used as an equivalent for ISO-8859-1.  But some people treat
437 |"Latin1" as referring just to the characters in the range 128 through 255, or
438 |somethimes from 160 through 255.
439 |This documentation uses "Latin1" and "Latin-1" to refer to all 256 characters.
440 |
441 |Note that Perl can be compiled and run under either ASCII or EBCDIC (See
442 |L<perlebcdic>).  Most of the documentation (and even comments in the code)
443 |ignore the EBCDIC possibility.
444 |For almost all purposes the differences are transparent.
445 |As an example, under EBCDIC,
446 |instead of UTF-8, UTF-EBCDIC is used to encode Unicode strings, and so
447 |whenever this documentation refers to C<utf8>
448 |(and variants of that name, including in function names),
449 |it also (essentially transparently) means C<UTF-EBCDIC>.
450 |But the ordinals of characters differ between ASCII, EBCDIC, and
451 |the UTF- encodings, and a string encoded in UTF-EBCDIC may occupy a different
452 |number of bytes than in UTF-8.
453 |
454 |The listing below is alphabetical, case insensitive.
455 |
456 _EOB_
457 |
458 |=head1 AUTHORS
459 |
460 |Until May 1997, this document was maintained by Jeff Okamoto
461 |<okamoto@corp.hp.com>.  It is now maintained as part of Perl itself.
462 |
463 |With lots of help and suggestions from Dean Roehrich, Malcolm Beattie,
464 |Andreas Koenig, Paul Hudson, Ilya Zakharevich, Paul Marquess, Neil
465 |Bowers, Matthew Green, Tim Bunce, Spider Boardman, Ulrich Pfeifer,
466 |Stephen McCamant, and Gurusamy Sarathy.
467 |
468 |API Listing originally by Dean Roehrich <roehrich@cray.com>.
469 |
470 |Updated to be autogenerated from comments in the source by Benjamin Stuhl.
471 |
472 |=head1 SEE ALSO
473 |
474 |L<perlguts>, L<perlxs>, L<perlxstut>, L<perlintern>
475 |
476 _EOE_
477
478 # List of non-static internal functions
479 my @missing_guts =
480  grep $funcflags{$_}{flags} !~ /[AS]/ && !$docs{guts}{$_}, keys %funcflags;
481
482 output('perlintern', <<'END', $docs{guts}, \@missing_guts, <<'END');
483 |=head1 NAME
484 |
485 |perlintern - autogenerated documentation of purely B<internal>
486 |                Perl functions
487 |
488 |=head1 DESCRIPTION
489 |X<internal Perl functions> X<interpreter functions>
490 |
491 |This file is the autogenerated documentation of functions in the
492 |Perl interpreter that are documented using Perl's internal documentation
493 |format but are not marked as part of the Perl API.  In other words,
494 |B<they are not for use in extensions>!
495 |
496 END
497 |
498 |=head1 AUTHORS
499 |
500 |The autodocumentation system was originally added to the Perl core by
501 |Benjamin Stuhl.  Documentation is by whoever was kind enough to
502 |document their functions.
503 |
504 |=head1 SEE ALSO
505 |
506 |L<perlguts>, L<perlapi>
507 |
508 END