From 154b3020f113add8c4e2ee1d009a464dd522ccd2 Mon Sep 17 00:00:00 2001 From: Karl Williamson Date: Sun, 14 Jul 2024 10:45:48 -0600 Subject: [PATCH] autodoc: Add documentation; fix white space --- autodoc.pl | 103 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 28 deletions(-) diff --git a/autodoc.pl b/autodoc.pl index 25bb963612f4..523996d7e3ee 100644 --- a/autodoc.pl +++ b/autodoc.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl -w use Text::Tabs; -# + # Unconditionally regenerate: # # pod/perlintern.pod @@ -121,22 +121,39 @@ require './regen/regen_lib.pl'; require './regen/embed_lib.pl'; -my %described_elsewhere; +# This is the main data structure. Each key is the name of a potential API +# element available to be documentable. Each value is a hash containing +# information about that element, such as its prototype. It is initialized +# from embed.fnc, and added to as we go along. +my %elements; +# This hash is used to organize the data in %elements for output. The top +# level keys are either 'api' or 'intern' for the two pod files generated by +# this program. # -# See database of global and static function prototypes in embed.fnc -# This is used to generate prototype headers under various configurations, -# export symbols lists for different platforms, and macros to provide an -# implicit interpreter context argument. +# Under those are hashes for each section in its corresponding pod. There is +# a section for API elements involved with SV handling; another for AV +# handling, etc. # - +# Under each section are hashes for each group in the section. Each group +# consists of one or more API elements that share the same pod. Each group +# hash contains fields for the common parts of the group, and then an array of +# all the API elements that comprise it. The array determines the ordering of +# the output for the API elements. +# +# The elements are pointers to the leaf nodes in %elements. These contain all +# the information needed to know what to output for each. my %docs; -my %elements; + +# This hash is populated with the names of other pod files that we determine +# contain relevant information about the API elements. It is used just for +# the SEE ALSO section +my %described_elsewhere; my $link_text = "Described in"; my $description_indent = 4; -my $usage_indent = 3; # + initial blank yields 4 total +my $usage_indent = 3; # + initial verbatim block blank yields 4 total my $AV_scn = 'AV Handling'; my $callback_scn = 'Callback Functions'; @@ -446,6 +463,11 @@ sub where_from_string($;$) { my ($file, $line_num) = @_; + + # Returns a string of hopefully idiomatic text about the location given by + # the input parameters. The line number is not always available, and this + # centralizes into one function the logic to deal with that + return "in $file" unless $line_num; return "at $file, line $line_num"; } @@ -485,10 +507,10 @@ sub check_and_add_proto_defn { # usage signature for $element, and marks the place in the source where # the documentation is found. Handling that happens naturally here. - # This is currently used only by config.h. See comments at the definition - # of this line type. If there is an existing prototype definition, defer - # to that (by setting the parameters to empty); otherwise use the one - # passed in. + # This definition type is currently used only by config.h. See comments + # at the definition of this line type. If there is an existing prototype + # definition, defer to that (by setting the parameters to empty); + # otherwise use the one passed in. if ($definition_type == CONDITIONAL_APIDOC) { if (exists $elements{$element}) { my @dummy; @@ -732,6 +754,11 @@ ($$$$) sub handle_apidoc_line ($$$$) { my ($file, $line_num, $type, $arg) = @_; + + # This just does a couple of checks that would otherwise have to be + # duplicated in the calling code, and calls check_and_add_proto_defn() to + # do the real work. + my $proto_as_written = $arg; my $proto = $proto_as_written; $proto = "||$proto" if $proto !~ /\|/; @@ -770,7 +797,8 @@ ($$$$) return $updated; } -sub destination_pod ($) { +sub destination_pod ($) { # Into which pod should the element go whose flags + # are $1 my $flags = shift; return "unknown" if $flags eq ""; return "api" if $flags =~ /A/; @@ -778,11 +806,10 @@ ($) } sub autodoc ($$) { # parse a file and extract documentation info - my($fh,$file) = @_; + my($fh, $file) = @_; my $section = $initial_file_section{$file} if defined $initial_file_section{$file}; - my $file_is_C = $file =~ / \. [ch] $ /x; # Count lines easier and handle apidoc continuation lines @@ -876,6 +903,8 @@ ($$) # Here the line starts a new section ... $section = $arg; + + # Convert $foo to its value if ($section =~ / ^ \$ /x) { $section .= '_scn' unless $section =~ / _scn $ /x; $section = eval "$section"; @@ -884,6 +913,8 @@ ($$) } die "Unknown section name '$section' in $file near line $line_num\n" unless defined $valid_sections{$section}; + + # Drop down to accumulate the heading text for this section. } elsif ($outer_line_type == PLAIN_APIDOC) { my $leader_ref = @@ -935,8 +966,8 @@ ($$) # # Accumulation stops at a terminating line, which is one of: # 1) =cut - # 2) =head (in a C file only =head1) - # 3) an end comment line in a C file: m:^\s*\*/: + # 2) =headN (N must be 1 in a C file) + # 3) an end comment line in a C file: m: ^ \s* [*] / :x # 4) =for apidoc... (except apidoc_item lines) my $head_ender_num = ($file_is_C) ? 1 : ""; while (1) { @@ -949,8 +980,9 @@ ($$) if ($file_is_C && $inner_arg =~ m: ^ \s* \* / $ :x) { - # End of comment line in C files is a fall-back terminator, - # but warn only if there actually is some accumulated text + # End of comment line in C files is a fall-back + # terminator, but warn only if there actually is some + # accumulated text warn "=cut missing? " . where_from_string($file, $line_num) . "\n$inner_arg" if $text =~ /\S/; @@ -960,7 +992,7 @@ ($$) $text .= $inner_arg; } - # Here, are done accumulating the text for this item. Trim it + # Here, are done accumulating the text for this element. Trim it $text =~ s/ ^ \s* //x; $text =~ s/ \s* $ //x; $text .= "\n" if $text ne ""; @@ -979,7 +1011,7 @@ ($$) my $item0 = ${$items[0]}; my $element_name = $item0->{name}; - # Here, we have accumulated into $text, the pod for $element_name + # Here, into $text, we have accumulated the pod for $element_name die "No =for apidoc_section nor =head1 " . where_from_string($file, $line_num) @@ -1316,7 +1348,7 @@ sub parse_config_h { chomp $was; if ($was ne "" && $was !~ m/$link_text/) { die "Multiple descriptions for $name\n" - . "The '$section' section contained\n'$was'"; + . "The '$section' section contained\n'$was'"; } $docs{'api'}{$section}{$name}->{pod} = $configs{$name}{pod}; $configs{$name}{section} = $section; @@ -2062,7 +2094,7 @@ sub dictionary_order { return $a cmp $b; } -sub output($) { +sub output($) { # Output a complete pod file my $destpod = shift; my $podname = $destpod->{podname}; my $dochash = $destpod->{docs}; @@ -2153,6 +2185,7 @@ ($) read_only_bottom_close_and_rename($fh); } +# Beginning of actual processing. First process embed.fnc foreach (@{(setup_embed())[0]}) { my $embed= $_->{embed} or next; @@ -2160,7 +2193,10 @@ ($) my ($flags, $ret_type, $func, $args) = @{$embed}{qw(flags return_type name args)}; check_and_add_proto_defn($func, $file, - undef, # Unknown line number in embed.fnc + # embed.fnc data doesn't currently furnish the + # line number + undef, + $flags, $ret_type, $args, # This is like an 'apidoc_defn' line, in that it @@ -2171,7 +2207,7 @@ ($) } # glob() picks up docs from extra .c or .h files that may be in unclean -# development trees. +# development trees, so use MANIFEST instead my @headers; my @non_headers; open my $fh, '<', 'MANIFEST' @@ -2192,14 +2228,19 @@ ($) } close $fh or die "Error whilst reading MANIFEST: $!"; +# Now have the files to examine saved. Do the headers first to minimize the +# number of forward references that we would have to deal with later for my $file (@headers, @non_headers) { open my $fh, '<', $file or die "Cannot open $file for docs: $!\n"; autodoc($fh, $file); close $fh or die "Error closing $file: $!\n"; } +# Code in this file depends on doing config.h last. parse_config_h(); +# Here, we have parsed everything + # Any apidoc group whose leader element's documentation wasn't known by the # time it was parsed has been placed in 'unknown' member of %docs. We should # now be able to figure out which real pod file to place it in, and its usage. @@ -2224,8 +2265,9 @@ ($) # $destpod now gives the correct pod for this group. Prepare to move it # to there - die "$destpod unexpectedly has an entry in $section_name for $group_name" - if defined $docs{$destpod}{$section_name}{$group_name}; + die "$destpod unexpectedly has an entry in $section_name for " + . $group_name if defined $docs{$destpod}{$section_name}{$group_name}; + $docs{$destpod}{$section_name}{$group_name} = delete $unknown->{$section_name}{$group_name}; } @@ -2283,9 +2325,14 @@ ($) } } +# Here %docs is populated; and we're ready to output + my %api = ( podname => 'perlapi', docs => $docs{'api'} ); my %intern = ( podname => 'perlintern', docs => $docs{'intern'} ); +# But first, look for inconsistencies and populate the lists of elements whose +# documentation is missing + for my $which (\%api, \%intern) { my (@deprecated, @experimental, @missings); for my $name (sort dictionary_order keys %elements) {