summaryrefslogtreecommitdiff
path: root/dist/Devel-PPPort/devel/mkapidoc.pl
diff options
context:
space:
mode:
Diffstat (limited to 'dist/Devel-PPPort/devel/mkapidoc.pl')
-rwxr-xr-xdist/Devel-PPPort/devel/mkapidoc.pl174
1 files changed, 144 insertions, 30 deletions
diff --git a/dist/Devel-PPPort/devel/mkapidoc.pl b/dist/Devel-PPPort/devel/mkapidoc.pl
index fa49459e2f..39a649d824 100755
--- a/dist/Devel-PPPort/devel/mkapidoc.pl
+++ b/dist/Devel-PPPort/devel/mkapidoc.pl
@@ -24,6 +24,7 @@
use warnings;
use strict;
use File::Find;
+use re '/aa';
my $PERLROOT = $ARGV[0];
unless ($PERLROOT) {
@@ -33,7 +34,9 @@ unless ($PERLROOT) {
die "'$PERLROOT' is invalid, or you haven't successfully run 'make' in it"
unless -e "$PERLROOT/warnings.h";
-
+my $maindir = '.';
+require "$maindir/parts/ppptools.pl";
+
my %seen;
# Find the files in MANIFEST that are core, but not embed.fnc, nor .t's
@@ -47,7 +50,33 @@ while (<$m>) { # In embed.fnc,
s/\t.*//;
push @files, "$PERLROOT/$_";
}
-close $m;
+close $m or die "Can't close $m: $!";
+
+# Here, we have the lists of doc files and root First, get the known macros
+# and functions from embed.fnc, converting from an array into a hash (for
+# convenience)
+my %embeds;
+my %apidoc;
+
+foreach my $entry (parse_embed("$maindir/parts/embed.fnc")) {
+ my $name = $entry->{'name'};
+ my $cond = $entry->{'cond'};
+
+ my $flags = join "", sort { lc $a cmp lc $b or $a cmp $b }
+ keys $entry->{flags}->%*;
+ my @arg_pairs;
+ foreach my $pair ($entry->{args}->@*) {
+ push @arg_pairs, join " ", $pair->@*;
+ }
+ my $args = join "|", @arg_pairs;
+
+ die "Multiple entries for $embeds{$name}{$cond}"
+ if defined $embeds{$name}{$cond};
+
+ # Save the embed.fnc entry
+ $embeds{$name}{$cond} = "$flags|$entry->{'ret'}|$name|$args";
+}
+
# Examine the SEE ALSO section of perlapi which should contain links to all
# the pods with apidoc entries in them. Add them to the MANIFEST list.
@@ -68,8 +97,10 @@ while (<$a>) {
while (<$a>) {
# The lines look like:
# F<config.h>, L<perlintern>, L<perlapio>, L<perlcall>, L<perlclib>,
- last if / ^ = /x;
+ last if /^=/;
+
my @tags = split /, \s* | \s+ /x; # Allow comma- or just space-separated
+
foreach my $tag (@tags) {
if ($tag =~ / ^ F< (.*) > $ /x) {
$file = $1;
@@ -86,49 +117,132 @@ while (<$a>) {
}
}
+my ($controlling_flags, $controlling_ret_type, $controlling_args);
+
# Look through all the files that potentially have apidoc entries
-my @entries;
-for (@files) {
+# These may be associated with embed.fnc, in which case we do nothing;
+# otherwise, we output them to apidoc.fnc, potentially modified.
+for my $file (@files) {
- s/ \t .* //x;
- open my $f, '<', "$_" or die "Can't open $_: $!";
+ $file =~ s/ \t .* //x; # Trim all but first column
+ open my $f, '<', "$file" or die "Can't open $file: $!";
my $line;
while (defined ($line = <$f>)) {
chomp $line;
- next unless $line =~ /^ =for \s+ apidoc \s+
- ( [^|]* \| # flags
- [^|]* \| # return type
- ( [^|]* ) # name
- (?: \| .* )? # optional args
- ) /x;
- my $meat = $1;
- my $name = $2;
-
- if (exists $seen{$name}) {
- if ($seen{$name} ne $meat) {
- print STDERR
- "Contradictory prototypes for $name,\n$seen{$name}\n$meat\n";
+ next unless $line =~ / ^ =for \s+ apidoc ( _item )? \s+
+ (?:
+ ( [^|]*? ) # flags, backoff trailing
+ # white space
+ \s* \| \s*
+
+ ( [^|]*? ) # return type
+
+ \s* \| \s*
+
+ )? # flags and ret type are all
+ # or nothing
+
+ ( [^|]+? ) # name
+
+ \s*
+
+ (?: \| \s* ( .* ) \s* )? # optional args
+
+ $
+ /x;
+ my $item = $1 // 0;
+ my $flags = $2 // "";
+ my $ret_type = $3 // "";
+ my $name = $4;
+ my $args = $5 // "";
+
+ next unless $name; # Not an apidoc line
+
+ # If embed.fnc already contains this name, this better be an empty
+ # entry, unless it has the M flag, meaning there is another macro
+ # defined for it.
+ if (defined $embeds{$name}) {
+ my @conds = keys $embeds{$name}->%*;
+
+ # If this is just the anchor for where the pod is in the source,
+ # the entry is already fully in embed.fnc.
+ if ("$flags$ret_type$args" eq "") {
+ if (! $item) {
+ foreach my $cond (@conds) {
+ # For a plain apidoc entry, save the inputs, so as to apply them
+ # to any following apidoc_item lines.
+ ($controlling_flags, $controlling_ret_type, $controlling_args)
+ = $embeds{$name}{$cond} =~ / ( [^|]* ) \| ( [^|]* ) \| (?: [^|]* ) \| (.*) /x;
+ $controlling_flags =~ s/[iMpb]//g;
+ $controlling_flags .= 'm' unless $controlling_flags =~ /m/;
+ last;
+ }
+ }
+ next;
+ }
+
+ # And the only reason we should have something with other
+ # information than what's in embed.fnc is if it is an M flag,
+ # meaning there is an extra macro for this function, and this is
+ # documenting that.
+ my $msg;
+ foreach my $cond (@conds) {
+ if ($embeds{$name}{$cond} !~ / ^ [^|]* M /x) {
+ $msg = "Specify only name when main entry is in embed.fnc";
+ last;
+ }
}
- next;
+
+ if (! defined $msg) {
+ if ($flags !~ /m/) {
+ $msg = "Must have 'm' flag for overriding 'M' embed.fnc entry";
+ }
+ elsif ($flags =~ /p/) {
+ $msg = "Must not have 'p' flag for overriding 'M' embed.fnc entry";
+ }
+ }
+
+ die "$msg: $file: $.: \n'$line'\n" if defined $msg;
}
- $meat =~ s/[ \t]+$//;
- $seen{$name} = $meat;
+ # Here, we have an entry for apidoc.fnc, one that isn't in embed.fnc.
+
+ # If this is an apidoc_item line, there was a plain apidoc line
+ # earlier, and we saved the values from that to use here (if here is
+ # empty).
+ if ($item) {
+ $flags = $controlling_flags unless $flags ne "";
+ $ret_type = $controlling_ret_type unless $ret_type ne "";
+ $args = $controlling_args unless $args ne "";
+ }
+ else {
+ # For a plain apidoc entry, save the inputs, so as to apply them
+ # to any following apidoc_item lines.
+ $controlling_flags = $flags;
+ $controlling_ret_type = $ret_type;
+ $controlling_args = $args;
+ }
# Many of the entries omit the "d" flag to indicate they are
- # documented, but we wouldn't have found this unless it was documented
- # in the source
- $meat =~ s/\|/d|/ unless $meat =~ /^[^|]*d/;
+ # documented, but we got here because of an apidoc line, which
+ # indicates it is documented in the source
+ $flags .= 'd' unless $flags =~ /d/;
+
+ # We currently don't handle typedefs, nor this special case
+ next if $flags =~ /y/;
+ next if $name eq 'JMPENV_PUSH';
- push @entries, "$meat\n";
+ my $entry = "$flags|$ret_type|$name";
+ $entry .= "|$args" if $args ne "";
+ $apidoc{$name}{entry} = $entry;
}
}
-my $outfile = "parts/apidoc.fnc";
+my $outfile = "$maindir/parts/apidoc.fnc";
open my $out, ">", $outfile
or die "Can't open '$outfile' for writing: $!";
-require "./parts/inc/inctools";
+require "$maindir/parts/inc/inctools";
print $out <<EOF;
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:
@@ -145,6 +259,6 @@ print $out <<EOF;
: source code, but are not contained in F<embed.fnc>.
:
EOF
-print $out sort sort_api_lines @entries;
+print $out join "\n", sort sort_api_lines map { $apidoc{$_}{entry} } keys %apidoc;
close $out or die "Close failed: $!";
print "$outfile regenerated\n";