This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add Bo Lindburgh alternate email to checkAUTHORS.pl
[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 normally invoked as part of 'make all', but is also
17 # called from from regen.pl.
18
19 use strict;
20
21 #
22 # See database of global and static function prototypes in embed.fnc
23 # This is used to generate prototype headers under various configurations,
24 # export symbols lists for different platforms, and macros to provide an
25 # implicit interpreter context argument.
26 #
27
28 my %docs;
29 my %funcflags;
30 my %macro = (
31              ax => 1,
32              items => 1,
33              ix => 1,
34              svtype => 1,
35             );
36 my %missing;
37
38 my $curheader = "Unknown section";
39
40 sub autodoc ($$) { # parse a file and extract documentation info
41     my($fh,$file) = @_;
42     my($in, $doc, $line);
43 FUNC:
44     while (defined($in = <$fh>)) {
45         if ($in =~ /^#\s*define\s+([A-Za-z_][A-Za-z_0-9]+)\(/ &&
46             ($file ne 'embed.h' || $file ne 'proto.h')) {
47             $macro{$1} = $file;
48             next FUNC;
49         }
50         if ($in=~ /^=head1 (.*)/) {
51             $curheader = $1;
52             next FUNC;
53         }
54         $line++;
55         if ($in =~ /^=for\s+apidoc\s+(.*?)\s*\n/) {
56             my $proto = $1;
57             $proto = "||$proto" unless $proto =~ /\|/;
58             my($flags, $ret, $name, @args) = split /\|/, $proto;
59             my $docs = "";
60 DOC:
61             while (defined($doc = <$fh>)) {
62                 $line++;
63                 last DOC if $doc =~ /^=\w+/;
64                 if ($doc =~ m:^\*/$:) {
65                     warn "=cut missing? $file:$line:$doc";;
66                     last DOC;
67                 }
68                 $docs .= $doc;
69             }
70             $docs = "\n$docs" if $docs and $docs !~ /^\n/;
71
72             # Check the consistency of the flags
73             my ($embed_where, $inline_where);
74             my ($embed_may_change, $inline_may_change);
75
76             my $docref = delete $funcflags{$name};
77             if ($docref and %$docref) {
78                 $embed_where = $docref->{flags} =~ /A/ ? 'api' : 'guts';
79                 $embed_may_change = $docref->{flags} =~ /M/;
80             } else {
81                 $missing{$name} = $file;
82             }
83             if ($flags =~ /m/) {
84                 $inline_where = $flags =~ /A/ ? 'api' : 'guts';
85                 $inline_may_change = $flags =~ /x/;
86
87                 if (defined $embed_where && $inline_where ne $embed_where) {
88                     warn "Function '$name' inconsistency: embed.fnc says $embed_where, Pod says $inline_where";
89                 }
90
91                 if (defined $embed_may_change
92                     && $inline_may_change ne $embed_may_change) {
93                     my $message = "Function '$name' inconsistency: ";
94                     if ($embed_may_change) {
95                         $message .= "embed.fnc says 'may change', Pod does not";
96                     } else {
97                         $message .= "Pod says 'may change', embed.fnc does not";
98                     }
99                     warn $message;
100                 }
101             } elsif (!defined $embed_where) {
102                 warn "Unable to place $name!\n";
103                 next;
104             } else {
105                 $inline_where = $embed_where;
106                 $flags .= 'x' if $embed_may_change;
107                 @args = @{$docref->{args}};
108                 $ret = $docref->{retval};
109             }
110
111             $docs{$inline_where}{$curheader}{$name}
112                 = [$flags, $docs, $ret, $file, @args];
113
114             if (defined $doc) {
115                 if ($doc =~ /^=(?:for|head)/) {
116                     $in = $doc;
117                     redo FUNC;
118                 }
119             } else {
120                 warn "$file:$line:$in";
121             }
122         }
123     }
124 }
125
126 sub docout ($$$) { # output the docs for one function
127     my($fh, $name, $docref) = @_;
128     my($flags, $docs, $ret, $file, @args) = @$docref;
129     $name =~ s/\s*$//;
130
131     $docs .= "NOTE: this function is experimental and may change or be
132 removed without notice.\n\n" if $flags =~ /x/;
133     $docs .= "NOTE: the perl_ form of this function is deprecated.\n\n"
134         if $flags =~ /p/;
135
136     print $fh "=item $name\nX<$name>\n$docs";
137
138     if ($flags =~ /U/) { # no usage
139         # nothing
140     } elsif ($flags =~ /s/) { # semicolon ("dTHR;")
141         print $fh "\t\t$name;\n\n";
142     } elsif ($flags =~ /n/) { # no args
143         print $fh "\t$ret\t$name\n\n";
144     } else { # full usage
145         print $fh "\t$ret\t$name";
146         print $fh "(" . join(", ", @args) . ")";
147         print $fh "\n\n";
148     }
149     print $fh "=for hackers\nFound in file $file\n\n";
150 }
151
152 sub output {
153     my ($podname, $header, $dochash, $missing, $footer) = @_;
154     my $filename = "pod/$podname.pod";
155     open my $fh, '>', $filename or die "Can't open $filename: $!";
156
157     print $fh <<"_EOH_", $header;
158 -*- buffer-read-only: t -*-
159
160 !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
161 This file is built by $0 extracting documentation from the C source
162 files.
163
164 _EOH_
165
166     my $key;
167     # case insensitive sort, with fallback for determinacy
168     for $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$dochash) {
169         my $section = $dochash->{$key}; 
170         print $fh "\n=head1 $key\n\n=over 8\n\n";
171         # Again, fallback for determinacy
172         for my $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$section) {
173             docout($fh, $key, $section->{$key});
174         }
175         print $fh "\n=back\n";
176     }
177
178     if (@$missing) {
179         print $fh "\n=head1 Undocumented functions\n\n";
180         print $fh "These functions are currently undocumented:\n\n=over\n\n";
181         for my $missing (sort @$missing) {
182             print $fh "=item $missing\nX<$missing>\n\n";
183         }
184         print $fh "=back\n\n";
185     }
186
187     print $fh $footer, <<'_EOF_';
188 =cut
189
190  ex: set ro:
191 _EOF_
192
193     close $fh or die "Can't close $filename: $!";
194 }
195
196 if (@ARGV) {
197     my $workdir = shift;
198     chdir $workdir
199         or die "Couldn't chdir to '$workdir': $!";
200 }
201
202 open IN, "embed.fnc" or die $!;
203
204 while (<IN>) {
205     chomp;
206     next if /^:/;
207     while (s|\\\s*$||) {
208         $_ .= <IN>;
209         chomp;
210     }
211     s/\s+$//;
212     next if /^\s*(#|$)/;
213
214     my ($flags, $retval, $func, @args) = split /\s*\|\s*/, $_;
215
216     next unless $func;
217
218     s/\b(NN|NULLOK)\b\s+//g for @args;
219     $func =~ s/\t//g; # clean up fields from embed.pl
220     $retval =~ s/\t//;
221
222     $funcflags{$func} = {
223                          flags => $flags,
224                          retval => $retval,
225                          args => \@args,
226                         };
227 }
228
229 my $file;
230 # glob() picks up docs from extra .c or .h files that may be in unclean
231 # development trees.
232 my $MANIFEST = do {
233   local ($/, *FH);
234   open FH, "MANIFEST" or die "Can't open MANIFEST: $!";
235   <FH>;
236 };
237
238 for $file (($MANIFEST =~ /^(\S+\.c)\t/gm), ($MANIFEST =~ /^(\S+\.h)\t/gm)) {
239     open F, "< $file" or die "Cannot open $file for docs: $!\n";
240     $curheader = "Functions in file $file\n";
241     autodoc(\*F,$file);
242     close F or die "Error closing $file: $!\n";
243 }
244
245 for (sort keys %funcflags) {
246     next unless $funcflags{$_}{flags} =~ /d/;
247     warn "no docs for $_\n"
248 }
249
250 foreach (sort keys %missing) {
251     next if $macro{$_};
252     # Heuristics for known not-a-function macros:
253     next if /^[A-Z]/;
254     next if /^dj?[A-Z]/;
255
256     warn "Function '$_', documented in $missing{$_}, not listed in embed.fnc";
257 }
258
259 # walk table providing an array of components in each line to
260 # subroutine, printing the result
261
262 my @missing_api = grep $funcflags{$_}{flags} =~ /A/ && !$docs{api}{$_}, keys %funcflags;
263 output('perlapi', <<'_EOB_', $docs{api}, \@missing_api, <<'_EOE_');
264 =head1 NAME
265
266 perlapi - autogenerated documentation for the perl public API
267
268 =head1 DESCRIPTION
269 X<Perl API> X<API> X<api>
270
271 This file contains the documentation of the perl public API generated by
272 embed.pl, specifically a listing of functions, macros, flags, and variables
273 that may be used by extension writers.  The interfaces of any functions that
274 are not listed here are subject to change without notice.  For this reason,
275 blindly using functions listed in proto.h is to be avoided when writing
276 extensions.
277
278 Note that all Perl API global variables must be referenced with the C<PL_>
279 prefix.  Some macros are provided for compatibility with the older,
280 unadorned names, but this support may be disabled in a future release.
281
282 Perl was originally written to handle US-ASCII only (that is characters
283 whose ordinal numbers are in the range 0 - 127).
284 And documentation and comments may still use the term ASCII, when
285 sometimes in fact the entire range from 0 - 255 is meant.
286
287 Note that Perl can be compiled and run under EBCDIC (See L<perlebcdic>)
288 or ASCII.  Most of the documentation (and even comments in the code)
289 ignore the EBCDIC possibility.  
290 For almost all purposes the differences are transparent.
291 As an example, under EBCDIC,
292 instead of UTF-8, UTF-EBCDIC is used to encode Unicode strings, and so
293 whenever this documentation refers to C<utf8>
294 (and variants of that name, including in function names),
295 it also (essentially transparently) means C<UTF-EBCDIC>.
296 But the ordinals of characters differ between ASCII, EBCDIC, and
297 the UTF- encodings, and a string encoded in UTF-EBCDIC may occupy more bytes
298 than in UTF-8.
299
300 Also, on some EBCDIC machines, functions that are documented as operating on
301 US-ASCII (or Basic Latin in Unicode terminology) may in fact operate on all
302 256 characters in the EBCDIC range, not just the subset corresponding to
303 US-ASCII.
304
305 The listing below is alphabetical, case insensitive.
306
307 _EOB_
308
309 =head1 AUTHORS
310
311 Until May 1997, this document was maintained by Jeff Okamoto
312 <okamoto@corp.hp.com>.  It is now maintained as part of Perl itself.
313
314 With lots of help and suggestions from Dean Roehrich, Malcolm Beattie,
315 Andreas Koenig, Paul Hudson, Ilya Zakharevich, Paul Marquess, Neil
316 Bowers, Matthew Green, Tim Bunce, Spider Boardman, Ulrich Pfeifer,
317 Stephen McCamant, and Gurusamy Sarathy.
318
319 API Listing originally by Dean Roehrich <roehrich@cray.com>.
320
321 Updated to be autogenerated from comments in the source by Benjamin Stuhl.
322
323 =head1 SEE ALSO
324
325 L<perlguts>, L<perlxs>, L<perlxstut>, L<perlintern>
326
327 _EOE_
328
329 my @missing_guts = grep $funcflags{$_}{flags} !~ /A/ && !$docs{guts}{$_}, keys %funcflags;
330
331 output('perlintern', <<'END', $docs{guts}, \@missing_guts, <<'END');
332 =head1 NAME
333
334 perlintern - autogenerated documentation of purely B<internal>
335                  Perl functions
336
337 =head1 DESCRIPTION
338 X<internal Perl functions> X<interpreter functions>
339
340 This file is the autogenerated documentation of functions in the
341 Perl interpreter that are documented using Perl's internal documentation
342 format but are not marked as part of the Perl API. In other words,
343 B<they are not for use in extensions>!
344
345 END
346
347 =head1 AUTHORS
348
349 The autodocumentation system was originally added to the Perl core by
350 Benjamin Stuhl. Documentation is by whoever was kind enough to
351 document their functions.
352
353 =head1 SEE ALSO
354
355 L<perlguts>, L<perlapi>
356
357 END