xref: /openbsd-src/gnu/usr.bin/perl/ext/Pod-Functions/Functions_pm.PL (revision eac174f2741a08d8deb8aae59a7f778ef9b5d770)
1898184e3Ssthen#!perl -w
2898184e3Ssthenuse strict;
3898184e3Ssthenuse Pod::Simple::SimpleTree;
4898184e3Ssthen
5898184e3Ssthenmy ($tap, $test, %Missing);
6898184e3Ssthen
76fb12b70Safresh1BEGIN {
8898184e3Ssthen    @ARGV = grep { not($_ eq '--tap' and $tap = 1) } @ARGV;
96fb12b70Safresh1    if ($tap) {
106fb12b70Safresh1        require Test::More;
116fb12b70Safresh1        Test::More->import;
126fb12b70Safresh1    }
136fb12b70Safresh1}
14898184e3Ssthen
15898184e3Ssthenmy (%Kinds, %Flavor, @Types);
16898184e3Ssthenmy %Omit;
17898184e3Ssthen
18898184e3Ssthenmy $p = Pod::Simple::SimpleTree->new;
19898184e3Ssthen$p->accept_targets('Pod::Functions');
20898184e3Ssthenmy $tree = $p->parse_file(shift)->root;
21898184e3Ssthen
22898184e3Ssthenforeach my $TL_node (@$tree[2 .. $#$tree]) {
23898184e3Ssthen    next unless $TL_node->[0] eq 'over-text';
24898184e3Ssthen    my $i = 2;
25898184e3Ssthen    while ($i <= $#$TL_node) {
26898184e3Ssthen        if ($TL_node->[$i][0] ne 'item-text') {
27898184e3Ssthen            ++$i;
28898184e3Ssthen            next;
29898184e3Ssthen        }
30898184e3Ssthen
31898184e3Ssthen        my $item_text = $TL_node->[$i][2];
32898184e3Ssthen        die "Confused by $item_text at line $TL_node->[$i][1]{start_line}"
33898184e3Ssthen            if ref $item_text;
34898184e3Ssthen        $item_text =~ s/\s+\z//s;
35898184e3Ssthen
36898184e3Ssthen        if ($TL_node->[$i+1][0] ne 'for'
37898184e3Ssthen           || $TL_node->[$i+1][1]{target} ne 'Pod::Functions') {
38898184e3Ssthen            ++$i;
39898184e3Ssthen            ++$Missing{$item_text} unless $Omit{$item_text};
40898184e3Ssthen            next;
41898184e3Ssthen        }
42898184e3Ssthen        my $data = $TL_node->[$i+1][2];
43898184e3Ssthen        die "Confused by $data at line $TL_node->[$i+1][1]{start_line}"
44898184e3Ssthen            unless ref $data eq 'ARRAY';
45898184e3Ssthen        my $text = $data->[2];
46898184e3Ssthen        die "Confused by $text at line $TL_node->[$i+1][1]{start_line}"
47898184e3Ssthen            if ref $text;
48898184e3Ssthen
49898184e3Ssthen        $i += 2;
50898184e3Ssthen
51898184e3Ssthen        if ($text =~ s/^=//) {
52898184e3Ssthen            # We are in "Perl Functions by Category"
53898184e3Ssthen            die "Expected a paragraph after =item at $TL_node->[$i-2][1]{start_line}"
54898184e3Ssthen                unless $TL_node->[$i][0] eq 'Para';
55898184e3Ssthen            my $para = $TL_node->[$i];
56898184e3Ssthen            # $text is the "type" of the built-in
57898184e3Ssthen            # Anything starting ! is not for inclusion in Pod::Functions
58898184e3Ssthen
59898184e3Ssthen            foreach my $func (@$para[2 .. $#$para]) {
60898184e3Ssthen                next unless ref $func eq 'ARRAY';
61b8851fccSafresh1                my $c_node =
62b8851fccSafresh1                    $func->[0] eq 'C' && !ref $func->[2] ? $func :
63b8851fccSafresh1                    $func->[0] eq 'L' && ref $func->[2]
64b8851fccSafresh1                        && $func->[2][0] eq 'C' && !ref $func->[2][2] ? $func->[2] :
65b8851fccSafresh1                    die "Expected only C<> blocks in paragraph after item at $TL_node->[$i-2][1]{start_line}";
66b8851fccSafresh1                # Everything is plain text (ie $c_node->[2] is everything)
67898184e3Ssthen                # except for C<-I<X>>. So untangle up to one level of nested <>
68898184e3Ssthen                my $funcname = join '', map {
69898184e3Ssthen                    ref $_ ? $_->[2] : $_
70b8851fccSafresh1                } @$c_node[2..$#$c_node];
71898184e3Ssthen                $funcname =~ s!(q.?)//!$1/STRING/!;
72898184e3Ssthen                push @{$Kinds{$text}}, $funcname;
73898184e3Ssthen            }
74898184e3Ssthen            if ($text =~ /^!/) {
75898184e3Ssthen                ++$Omit{$_} foreach @{$Kinds{$text}};
76898184e3Ssthen            } else {
77898184e3Ssthen                push @Types, [$text, $item_text];
78898184e3Ssthen            }
79898184e3Ssthen        } else {
80898184e3Ssthen            $item_text =~ s/ .*//;
81898184e3Ssthen            # For now, just remove any metadata about when it was added:
82898184e3Ssthen            $text =~ s/^\+\S+ //;
83898184e3Ssthen            $Flavor{$item_text} = $text;
84898184e3Ssthen            ++$Omit{$item_text} if $text =~ /^!/;
85898184e3Ssthen        }
86898184e3Ssthen    }
87898184e3Ssthen}
88898184e3Ssthen
89898184e3Ssthen# Take the lists of functions for each type group, and invert them to get the
90898184e3Ssthen# type group (or groups) for each function:
91898184e3Ssthenmy %Type;
92898184e3Ssthenwhile (my ($type, $funcs) = each %Kinds) {
93898184e3Ssthen    push @{$Type{$_}}, $type foreach @$funcs;
94898184e3Ssthen}
95898184e3Ssthen
96898184e3Ssthen# We sort __SUB__ after sub, but before substr, but __PACKAGE__ after package,
97b8851fccSafresh1# and __END__ after END.  (We create a temporary array of two elements, where
98b8851fccSafresh1# the second has the underscores squeezed out, and sort on that element
99b8851fccSafresh1# first.)
100898184e3Ssthensub sort_funcs {
101898184e3Ssthen    map { $_->[0] }
102b8851fccSafresh1        sort { uc $a->[1] cmp uc $b->[1]
103b8851fccSafresh1               || $b->[1] cmp $a->[1]
104b8851fccSafresh1               || $a->[0] =~ /^_/   # here $a and $b are identical when
105b8851fccSafresh1                                    # underscores squeezed out; so if $a
106b8851fccSafresh1                                    # begins with an underscore, it should
107b8851fccSafresh1                                    # sort after $b
108b8851fccSafresh1               || $a->[0] cmp $b->[0]
109b8851fccSafresh1             } map  { my $f = tr/_//dr; [ $_, $f ] }
110898184e3Ssthen                @_;
111898184e3Ssthen}
112898184e3Ssthen
113898184e3Ssthenif ($tap) {
114898184e3Ssthen    foreach my $func (sort_funcs(keys %Flavor)) {
1156fb12b70Safresh1       ok ( $Type{$func}, "$func is mentioned in at least one category group");
116898184e3Ssthen    }
117898184e3Ssthen    foreach (sort keys %Missing) {
118898184e3Ssthen        # Ignore anything that looks like an alternative for a function we've
119898184e3Ssthen        # already seen;
120898184e3Ssthen        s!(?: [A-Z].*| \(\)|\( LIST \)| /PATTERN/.*)!!;
121898184e3Ssthen        next if $Flavor{$_};
122898184e3Ssthen        if (/^[_a-z]/) {
1236fb12b70Safresh1            fail( "function '$_' has no summary for Pod::Functions" );
124898184e3Ssthen        } else {
1256fb12b70Safresh1            fail( "for Pod::Functions" );
126898184e3Ssthen        }
127898184e3Ssthen    }
128898184e3Ssthen    foreach my $kind (sort keys %Kinds) {
129898184e3Ssthen        my $funcs = $Kinds{$kind};
130898184e3Ssthen        ++$test;
131898184e3Ssthen        my $want = join ' ', sort_funcs(@$funcs);
1326fb12b70Safresh1        is ("@$funcs", $want, "category $kind is correctly sorted" );
133898184e3Ssthen    }
1346fb12b70Safresh1    done_testing();
135898184e3Ssthen    exit;
136898184e3Ssthen}
137898184e3Ssthen
138898184e3Ssthen# blead will run this with miniperl, hence we can't use autodie
139898184e3Ssthenmy $real = 'Functions.pm';
140898184e3Ssthenmy $temp = "Functions.$$";
141898184e3Ssthen
142898184e3SsthenEND {
143898184e3Ssthen    return if !defined $temp || !-e $temp;
144898184e3Ssthen    unlink $temp or warn "Can't unlink '$temp': $!";
145898184e3Ssthen}
146898184e3Ssthen
147898184e3Ssthenforeach ($real, $temp) {
148898184e3Ssthen    next if !-e $_;
149898184e3Ssthen    unlink $_ or die "Can't unlink '$_': $!";
150898184e3Ssthen}
151898184e3Ssthen
152898184e3Ssthenopen my $fh, '>', $temp or die "Can't open '$temp' for writing: $!";
153898184e3Ssthenprint $fh <<'EOT';
154898184e3Ssthenpackage Pod::Functions;
155898184e3Ssthenuse strict;
156898184e3Ssthen
157898184e3Ssthen=head1 NAME
158898184e3Ssthen
159898184e3SsthenPod::Functions - Group Perl's functions a la perlfunc.pod
160898184e3Ssthen
161898184e3Ssthen=head1 SYNOPSIS
162898184e3Ssthen
163898184e3Ssthen    use Pod::Functions;
164898184e3Ssthen
165898184e3Ssthen    my @misc_ops = @{ $Kinds{ 'Misc' } };
166898184e3Ssthen    my $misc_dsc = $Type_Description{ 'Misc' };
167898184e3Ssthen
168898184e3Ssthenor
169898184e3Ssthen
170898184e3Ssthen    perl /path/to/lib/Pod/Functions.pm
171898184e3Ssthen
172898184e3SsthenThis will print a grouped list of Perl's functions, like the
173898184e3SsthenL<perlfunc/"Perl Functions by Category"> section.
174898184e3Ssthen
175898184e3Ssthen=head1 DESCRIPTION
176898184e3Ssthen
177898184e3SsthenIt exports the following variables:
178898184e3Ssthen
179898184e3Ssthen=over 4
180898184e3Ssthen
181898184e3Ssthen=item %Kinds
182898184e3Ssthen
183898184e3SsthenThis holds a hash-of-lists. Each list contains the functions in the category
184898184e3Ssthenthe key denotes.
185898184e3Ssthen
186898184e3Ssthen=item %Type
187898184e3Ssthen
188898184e3SsthenIn this hash each key represents a function and the value is the category.
189898184e3SsthenThe category can be a comma separated list.
190898184e3Ssthen
191898184e3Ssthen=item %Flavor
192898184e3Ssthen
193898184e3SsthenIn this hash each key represents a function and the value is a short
194898184e3Ssthendescription of that function.
195898184e3Ssthen
196898184e3Ssthen=item %Type_Description
197898184e3Ssthen
198898184e3SsthenIn this hash each key represents a category of functions and the value is
199898184e3Ssthena short description of that category.
200898184e3Ssthen
201898184e3Ssthen=item @Type_Order
202898184e3Ssthen
203898184e3SsthenThis list of categories is used to produce the same order as the
204898184e3SsthenL<perlfunc/"Perl Functions by Category"> section.
205898184e3Ssthen
206898184e3Ssthen=back
207898184e3Ssthen
208898184e3Ssthen=cut
209898184e3Ssthen
210*eac174f2Safresh1our $VERSION = '1.14';
211898184e3Ssthen
212*eac174f2Safresh1use Exporter 'import';
213898184e3Ssthen
214898184e3Ssthenour @EXPORT = qw(%Kinds %Type %Flavor %Type_Description @Type_Order);
215898184e3Ssthen
216898184e3Ssthenour(%Kinds, %Type, %Flavor, %Type_Description, @Type_Order);
217898184e3Ssthen
218898184e3Ssthenforeach (
219898184e3SsthenEOT
220898184e3Ssthen
221898184e3Ssthenforeach (@Types) {
222898184e3Ssthen    my ($type, $desc) = @$_;
223898184e3Ssthen    $type = "'$type'" if $type =~ /[^A-Za-z]/;
224898184e3Ssthen    $desc =~ s!([\\'])!\\$1!g;
225898184e3Ssthen    printf $fh "    [%-9s  => '%s'],\n", $type, $desc;
226898184e3Ssthen}
227898184e3Ssthen
228898184e3Ssthenprint $fh <<'EOT';
229898184e3Ssthen	) {
230898184e3Ssthen    push @Type_Order, $_->[0];
231898184e3Ssthen    $Type_Description{$_->[0]} = $_->[1];
232898184e3Ssthen};
233898184e3Ssthen
234898184e3Ssthenwhile (<DATA>) {
235898184e3Ssthen    chomp;
236898184e3Ssthen    s/^#.*//;
237898184e3Ssthen    next unless $_;
238898184e3Ssthen    my($name, @data) = split "\t", $_;
239898184e3Ssthen    $Flavor{$name} = pop @data;
240898184e3Ssthen    $Type{$name} = join ',', @data;
241898184e3Ssthen    for my $t (@data) {
242898184e3Ssthen        push @{$Kinds{$t}}, $name;
243898184e3Ssthen    }
244898184e3Ssthen}
245898184e3Ssthen
246898184e3Ssthenclose DATA;
247898184e3Ssthen
248898184e3Ssthenmy( $typedesc, $list );
249898184e3Ssthenunless (caller) {
250898184e3Ssthen    foreach my $type ( @Type_Order ) {
251898184e3Ssthen	$list = join(", ", sort @{$Kinds{$type}});
252898184e3Ssthen	$typedesc = $Type_Description{$type} . ":";
253898184e3Ssthen	write;
254898184e3Ssthen    }
255898184e3Ssthen}
256898184e3Ssthen
257898184e3Ssthenformat =
258898184e3Ssthen
259898184e3Ssthen^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
260898184e3Ssthen    $typedesc
261898184e3Ssthen~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
262898184e3Ssthen    $typedesc
263898184e3Ssthen ~~  ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
264898184e3Ssthen	$list
265898184e3Ssthen.
266898184e3Ssthen
267898184e3Ssthen1;
268898184e3Ssthen
269898184e3Ssthen__DATA__
270898184e3SsthenEOT
271898184e3Ssthen
272898184e3Ssthenforeach my $func (sort_funcs(keys %Flavor)) {
273898184e3Ssthen    my $desc = $Flavor{$func};
274898184e3Ssthen    die "No types listed for $func" unless $Type{$func};
275898184e3Ssthen    next if $Omit{$func};
2766fb12b70Safresh1    print $fh join("\t", $func, (sort @{$Type{$func}}), $desc), "\n";
277898184e3Ssthen}
278898184e3Ssthen
279898184e3Ssthenclose $fh or die "Can't close '$temp': $!";
280898184e3Ssthenrename $temp, $real or die "Can't rename '$temp' to '$real': $!";
281