xref: /openbsd/gnu/usr.bin/perl/autodoc.pl (revision 5af055cd)
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
25use strict;
26
27if (@ARGV) {
28    my $workdir = shift;
29    chdir $workdir
30        or die "Couldn't chdir to '$workdir': $!";
31}
32require 'regen/regen_lib.pl';
33require '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
42my %docs;
43my %funcflags;
44my %macro = (
45	     ax => 1,
46	     items => 1,
47	     ix => 1,
48	     svtype => 1,
49	    );
50my %missing;
51
52my $curheader = "Unknown section";
53
54sub autodoc ($$) { # parse a file and extract documentation info
55    my($fh,$file) = @_;
56    my($in, $doc, $line, $header_doc);
57FUNC:
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
80HDR_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 = "";
103DOC:
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
177sub 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
184future release of Perl.  Do not use it for new code; remove it from
185existing code.\n\n$docs";
186    }
187    else {
188        $docs = "\n\nNOTE: this function is experimental and may change or be
189removed 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
252sub 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_';
284The following functions have been flagged as part of the public API,
285but are currently undocumented.  Use them at your own risk, as the
286interfaces are subject to change.  Functions that are not listed in this
287document are not intended for public use, and should NOT be used under any
288circumstances.
289
290If you use one of the undocumented functions below, you may wish to consider
291creating and submitting documentation
292for it.  If your patch is accepted, this
293will indicate that the interface is stable (unless it is explicitly marked
294otherwise).
295
296=over
297
298_EOB_
299The following functions are currently undocumented.  If you use one of
300them, you may wish to consider creating and submitting documentation for
301it.
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
316foreach (@{(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.
330open my $fh, '<', 'MANIFEST'
331    or die "Can't open MANIFEST: $!";
332while (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}
340close $fh or die "Error whilst reading MANIFEST: $!";
341
342for (sort keys %funcflags) {
343    next unless $funcflags{$_}{flags} =~ /d/;
344    warn "no docs for $_\n"
345}
346
347foreach (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.
361my @missing_api = grep $funcflags{$_}{flags} =~ /A/ && $funcflags{$_}{flags} !~ /[MD]/ && !$docs{api}{$_}, keys %funcflags;
362output('perlapi', <<'_EOB_', $docs{api}, \@missing_api, <<'_EOE_');
363=head1 NAME
364
365perlapi - autogenerated documentation for the perl public API
366
367=head1 DESCRIPTION
368X<Perl API> X<API> X<api>
369
370This file contains the documentation of the perl public API generated by
371F<embed.pl>, specifically a listing of functions, macros, flags, and variables
372that may be used by extension writers.  L<At the end|/Undocumented functions>
373is a list of functions which have yet to be documented.  The interfaces of
374those are subject to change without notice.  Anything not listed here is
375not part of the public API, and should not be used by extension writers at
376all.  For these reasons, blindly using functions listed in proto.h is to be
377avoided when writing extensions.
378
379Note that all Perl API global variables must be referenced with the C<PL_>
380prefix.  Again, those not listed here are not to be used by extension writers,
381and can be changed or removed without notice; same with macros.
382Some macros are provided for compatibility with the older,
383unadorned names, but this support may be disabled in a future release.
384
385Perl was originally written to handle US-ASCII only (that is characters
386whose ordinal numbers are in the range 0 - 127).
387And documentation and comments may still use the term ASCII, when
388sometimes in fact the entire range from 0 - 255 is meant.
389
390Note that Perl can be compiled and run under EBCDIC (See L<perlebcdic>)
391or ASCII.  Most of the documentation (and even comments in the code)
392ignore the EBCDIC possibility.
393For almost all purposes the differences are transparent.
394As an example, under EBCDIC,
395instead of UTF-8, UTF-EBCDIC is used to encode Unicode strings, and so
396whenever this documentation refers to C<utf8>
397(and variants of that name, including in function names),
398it also (essentially transparently) means C<UTF-EBCDIC>.
399But the ordinals of characters differ between ASCII, EBCDIC, and
400the UTF- encodings, and a string encoded in UTF-EBCDIC may occupy more bytes
401than in UTF-8.
402
403The listing below is alphabetical, case insensitive.
404
405_EOB_
406
407=head1 AUTHORS
408
409Until May 1997, this document was maintained by Jeff Okamoto
410<okamoto@corp.hp.com>.  It is now maintained as part of Perl itself.
411
412With lots of help and suggestions from Dean Roehrich, Malcolm Beattie,
413Andreas Koenig, Paul Hudson, Ilya Zakharevich, Paul Marquess, Neil
414Bowers, Matthew Green, Tim Bunce, Spider Boardman, Ulrich Pfeifer,
415Stephen McCamant, and Gurusamy Sarathy.
416
417API Listing originally by Dean Roehrich <roehrich@cray.com>.
418
419Updated to be autogenerated from comments in the source by Benjamin Stuhl.
420
421=head1 SEE ALSO
422
423L<perlguts>, L<perlxs>, L<perlxstut>, L<perlintern>
424
425_EOE_
426
427# List of non-static internal functions
428my @missing_guts =
429 grep $funcflags{$_}{flags} !~ /[As]/ && !$docs{guts}{$_}, keys %funcflags;
430
431output('perlintern', <<'END', $docs{guts}, \@missing_guts, <<'END');
432=head1 NAME
433
434perlintern - autogenerated documentation of purely B<internal>
435		 Perl functions
436
437=head1 DESCRIPTION
438X<internal Perl functions> X<interpreter functions>
439
440This file is the autogenerated documentation of functions in the
441Perl interpreter that are documented using Perl's internal documentation
442format but are not marked as part of the Perl API.  In other words,
443B<they are not for use in extensions>!
444
445END
446
447=head1 AUTHORS
448
449The autodocumentation system was originally added to the Perl core by
450Benjamin Stuhl.  Documentation is by whoever was kind enough to
451document their functions.
452
453=head1 SEE ALSO
454
455L<perlguts>, L<perlapi>
456
457END
458