X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=autodoc.pl;h=285bc3a5b3180bd417c7c916afa73033069ec9b1;hb=d4451e15b8fd19b38c87c9ec4aea2dc5af3f94d1;hp=0e8258f6dd1b98cd4180bc79ef08601dd5920124;hpb=848ad75c717886b27932509687e0ca4b7eef020a;p=p5sagit%2Fp5-mst-13.2.git diff --git a/autodoc.pl b/autodoc.pl index 0e8258f..285bc3a 100644 --- a/autodoc.pl +++ b/autodoc.pl @@ -1,12 +1,20 @@ #!/usr/bin/perl -w - -require 5.003; # keep this compatible, an old perl is all we may have before - # we build the new one - -BEGIN { - push @INC, 'lib'; - require 'regen_lib.pl'; -} +# +# Unconditionally regenerate: +# +# pod/perlintern.pod +# pod/perlapi.pod +# +# from information stored in +# +# embed.fnc +# plus all the .c and .h files listed in MANIFEST +# +# Has an optional arg, which is the directory to chdir to before reading +# MANIFEST and *.[ch]. +# +# This script is normally invoked as part of 'make all', but is also +# called from from regen.pl. use strict; @@ -17,37 +25,15 @@ use strict; # implicit interpreter context argument. # -open IN, "embed.fnc" or die $!; - -# walk table providing an array of components in each line to -# subroutine, printing the result -sub walk_table (&@) { - my $function = shift; - seek IN, 0, 0; # so we may restart - while () { - chomp; - next if /^:/; - while (s|\\\s*$||) { - $_ .= ; - chomp; - } - s/\s+$//; - my @args; - if (/^\s*(#|$)/) { - @args = $_; - } - else { - @args = split /\s*\|\s*/, $_; - } - s/\b(NN|NULLOK)\b\s+//g for @args; - $function->(@args); - } -} - -my %apidocs; -my %gutsdocs; -my %docfuncs; -my %seenfuncs; +my %docs; +my %funcflags; +my %macro = ( + ax => 1, + items => 1, + ix => 1, + svtype => 1, + ); +my %missing; my $curheader = "Unknown section"; @@ -56,6 +42,11 @@ sub autodoc ($$) { # parse a file and extract documentation info my($in, $doc, $line); FUNC: while (defined($in = <$fh>)) { + if ($in =~ /^#\s*define\s+([A-Za-z_][A-Za-z_0-9]+)\(/ && + ($file ne 'embed.h' || $file ne 'proto.h')) { + $macro{$1} = $file; + next FUNC; + } if ($in=~ /^=head1 (.*)/) { $curheader = $1; next FUNC; @@ -77,17 +68,49 @@ DOC: $docs .= $doc; } $docs = "\n$docs" if $docs and $docs !~ /^\n/; + + # Check the consistency of the flags + my ($embed_where, $inline_where); + my ($embed_may_change, $inline_may_change); + + my $docref = delete $funcflags{$name}; + if ($docref and %$docref) { + $embed_where = $docref->{flags} =~ /A/ ? 'api' : 'guts'; + $embed_may_change = $docref->{flags} =~ /M/; + } else { + $missing{$name} = $file; + } if ($flags =~ /m/) { - if ($flags =~ /A/) { - $apidocs{$curheader}{$name} = [$flags, $docs, $ret, $file, @args]; + $inline_where = $flags =~ /A/ ? 'api' : 'guts'; + $inline_may_change = $flags =~ /x/; + + if (defined $embed_where && $inline_where ne $embed_where) { + warn "Function '$name' inconsistency: embed.fnc says $embed_where, Pod says $inline_where"; } - else { - $gutsdocs{$curheader}{$name} = [$flags, $docs, $ret, $file, @args]; + + if (defined $embed_may_change + && $inline_may_change ne $embed_may_change) { + my $message = "Function '$name' inconsistency: "; + if ($embed_may_change) { + $message .= "embed.fnc says 'may change', Pod does not"; + } else { + $message .= "Pod says 'may change', embed.fnc does not"; + } + warn $message; } + } elsif (!defined $embed_where) { + warn "Unable to place $name!\n"; + next; + } else { + $inline_where = $embed_where; + $flags .= 'x' if $embed_may_change; + @args = @{$docref->{args}}; + $ret = $docref->{retval}; } - else { - $docfuncs{$name} = [$flags, $docs, $ret, $file, $curheader, @args]; - } + + $docs{$inline_where}{$curheader}{$name} + = [$flags, $docs, $ret, $file, @args]; + if (defined $doc) { if ($doc =~ /^=(?:for|head)/) { $in = $doc; @@ -126,9 +149,12 @@ removed without notice.\n\n" if $flags =~ /x/; print $fh "=for hackers\nFound in file $file\n\n"; } -sub readonly_header (*) { - my $fh = shift; - print $fh <<"_EOH_"; +sub output { + my ($podname, $header, $dochash, $missing, $footer) = @_; + my $filename = "pod/$podname.pod"; + open my $fh, '>', $filename or die "Can't open $filename: $!"; + + print $fh <<"_EOH_", $header; -*- buffer-read-only: t -*- !!!!!!! DO NOT EDIT THIS FILE !!!!!!! @@ -136,15 +162,68 @@ This file is built by $0 extracting documentation from the C source files. _EOH_ -} -sub readonly_footer (*) { - my $fh = shift; - print $fh <<'_EOF_'; + my $key; + # case insensitive sort, with fallback for determinacy + for $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$dochash) { + my $section = $dochash->{$key}; + print $fh "\n=head1 $key\n\n=over 8\n\n"; + # Again, fallback for determinacy + for my $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$section) { + docout($fh, $key, $section->{$key}); + } + print $fh "\n=back\n"; + } + + if (@$missing) { + print $fh "\n=head1 Undocumented functions\n\n"; + print $fh "These functions are currently undocumented:\n\n=over\n\n"; + for my $missing (sort @$missing) { + print $fh "=item $missing\nX<$missing>\n\n"; + } + print $fh "=back\n\n"; + } + + print $fh $footer, <<'_EOF_'; =cut ex: set ro: _EOF_ + + close $fh or die "Can't close $filename: $!"; +} + +if (@ARGV) { + my $workdir = shift; + chdir $workdir + or die "Couldn't chdir to '$workdir': $!"; +} + +open IN, "embed.fnc" or die $!; + +while () { + chomp; + next if /^:/; + while (s|\\\s*$||) { + $_ .= ; + chomp; + } + s/\s+$//; + next if /^\s*(#|$)/; + + my ($flags, $retval, $func, @args) = split /\s*\|\s*/, $_; + + next unless $func; + + s/\b(NN|NULLOK)\b\s+//g for @args; + $func =~ s/\t//g; # clean up fields from embed.pl + $retval =~ s/\t//; + + $funcflags{$func} = { + flags => $flags, + retval => $retval, + args => \@args, + }; } my $file; @@ -163,43 +242,25 @@ for $file (($MANIFEST =~ /^(\S+\.c)\t/gm), ($MANIFEST =~ /^(\S+\.h)\t/gm)) { close F or die "Error closing $file: $!\n"; } -safer_unlink "pod/perlapi.pod"; -my $doc = safer_open("pod/perlapi.pod"); - -walk_table { # load documented functions into appropriate hash - if (@_ > 1) { - my($flags, $retval, $func, @args) = @_; - return "" unless $flags =~ /d/; - $func =~ s/\t//g; $flags =~ s/p//; # clean up fields from embed.pl - $retval =~ s/\t//; - my $docref = delete $docfuncs{$func}; - $seenfuncs{$func} = 1; - if ($docref and @$docref) { - if ($flags =~ /A/) { - $docref->[0].="x" if $flags =~ /M/; - $apidocs{$docref->[4]}{$func} = - [$docref->[0] . 'A', $docref->[1], $retval, $docref->[3], - @args]; - } else { - $gutsdocs{$docref->[4]}{$func} = - [$docref->[0], $docref->[1], $retval, $docref->[3], @args]; - } - } - else { - warn "no docs for $func\n" unless $seenfuncs{$func}; - } - } -}; +for (sort keys %funcflags) { + next unless $funcflags{$_}{flags} =~ /d/; + warn "no docs for $_\n" +} + +foreach (sort keys %missing) { + next if $macro{$_}; + # Heuristics for known not-a-function macros: + next if /^[A-Z]/; + next if /^dj?[A-Z]/; -for (sort keys %docfuncs) { - # Have you used a full for apidoc or just a func name? - # Have you used Ap instead of Am in the for apidoc? - warn "Unable to place $_!\n"; + warn "Function '$_', documented in $missing{$_}, not listed in embed.fnc"; } -readonly_header($doc); +# walk table providing an array of components in each line to +# subroutine, printing the result -print $doc <<'_EOB_'; +my @missing_api = grep $funcflags{$_}{flags} =~ /A/ && !$docs{api}{$_}, keys %funcflags; +output('perlapi', <<'_EOB_', $docs{api}, \@missing_api, <<'_EOE_'); =head1 NAME perlapi - autogenerated documentation for the perl public API @@ -245,20 +306,6 @@ The listing below is alphabetical, case insensitive. _EOB_ -my $key; -# case insensitive sort, with fallback for determinacy -for $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %apidocs) { - my $section = $apidocs{$key}; - print $doc "\n=head1 $key\n\n=over 8\n\n"; - # Again, fallback for determinacy - for my $key (sort { uc($a) cmp uc($b) || $a cmp $b } keys %$section) { - docout($doc, $key, $section->{$key}); - } - print $doc "\n=back\n"; -} - -print $doc <<'_EOE_'; - =head1 AUTHORS Until May 1997, this document was maintained by Jeff Okamoto @@ -275,18 +322,13 @@ Updated to be autogenerated from comments in the source by Benjamin Stuhl. =head1 SEE ALSO -perlguts(1), perlxs(1), perlxstut(1), perlintern(1) +L, L, L, L _EOE_ -readonly_footer($doc); +my @missing_guts = grep $funcflags{$_}{flags} !~ /A/ && !$docs{guts}{$_}, keys %funcflags; -safer_close($doc); - -safer_unlink "pod/perlintern.pod"; -my $guts = safer_open("pod/perlintern.pod"); -readonly_header($guts); -print $guts <<'END'; +output('perlintern', <<'END', $docs{guts}, \@missing_guts, <<'END'); =head1 NAME perlintern - autogenerated documentation of purely B @@ -302,17 +344,6 @@ B! END -for $key (sort { uc($a) cmp uc($b); } keys %gutsdocs) { - my $section = $gutsdocs{$key}; - print $guts "\n=head1 $key\n\n=over 8\n\n"; - for my $key (sort { uc($a) cmp uc($b); } keys %$section) { - docout($guts, $key, $section->{$key}); - } - print $guts "\n=back\n"; -} - -print $guts <<'END'; - =head1 AUTHORS The autodocumentation system was originally added to the Perl core by @@ -321,9 +352,6 @@ document their functions. =head1 SEE ALSO -perlguts(1), perlapi(1) +L, L END -readonly_footer($guts); - -safer_close($guts);