xref: /netbsd-src/crypto/external/bsd/openssl/dist/util/perl/OpenSSL/Util/Pod.pm (revision b0d1725196a7921d003d2c66a14f186abda4176b)
1*b0d17251Schristos# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
2c7da899bSchristos#
3*b0d17251Schristos# Licensed under the Apache License 2.0 (the "License").  You may not use
4c7da899bSchristos# this file except in compliance with the License.  You can obtain a copy
5c7da899bSchristos# in the file LICENSE in the source distribution or at
6c7da899bSchristos# https://www.openssl.org/source/license.html
7c7da899bSchristos
8c7da899bSchristospackage OpenSSL::Util::Pod;
9c7da899bSchristos
10c7da899bSchristosuse strict;
11c7da899bSchristosuse warnings;
12c7da899bSchristos
13c7da899bSchristosuse Exporter;
14c7da899bSchristosuse vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
15c7da899bSchristos$VERSION = "0.1";
16c7da899bSchristos@ISA = qw(Exporter);
17c7da899bSchristos@EXPORT = qw(extract_pod_info);
18c7da899bSchristos@EXPORT_OK = qw();
19c7da899bSchristos
20c7da899bSchristos=head1 NAME
21c7da899bSchristos
22c7da899bSchristosOpenSSL::Util::Pod - utilities to manipulate .pod files
23c7da899bSchristos
24c7da899bSchristos=head1 SYNOPSIS
25c7da899bSchristos
26c7da899bSchristos  use OpenSSL::Util::Pod;
27c7da899bSchristos
28c7da899bSchristos  my %podinfo = extract_pod_info("foo.pod");
29c7da899bSchristos
30c7da899bSchristos  # or if the file is already opened...  Note that this consumes the
31c7da899bSchristos  # remainder of the file.
32c7da899bSchristos
33c7da899bSchristos  my %podinfo = extract_pod_info(\*STDIN);
34c7da899bSchristos
35c7da899bSchristos=head1 DESCRIPTION
36c7da899bSchristos
37c7da899bSchristos=over
38c7da899bSchristos
39c7da899bSchristos=item B<extract_pod_info "FILENAME", HASHREF>
40c7da899bSchristos
41c7da899bSchristos=item B<extract_pod_info "FILENAME">
42c7da899bSchristos
43c7da899bSchristos=item B<extract_pod_info GLOB, HASHREF>
44c7da899bSchristos
45c7da899bSchristos=item B<extract_pod_info GLOB>
46c7da899bSchristos
47c7da899bSchristosExtracts information from a .pod file, given a STRING (file name) or a
48c7da899bSchristosGLOB (a file handle).  The result is given back as a hash table.
49c7da899bSchristos
50c7da899bSchristosThe additional hash is for extra parameters:
51c7da899bSchristos
52c7da899bSchristos=over
53c7da899bSchristos
54c7da899bSchristos=item B<section =E<gt> N>
55c7da899bSchristos
5613d40330SchristosThe value MUST be a number, and will be the man section number
5713d40330Schristosto be used with the given .pod file.
58c7da899bSchristos
59c7da899bSchristos=item B<debug =E<gt> 0|1>
60c7da899bSchristos
61c7da899bSchristosIf set to 1, extra debug text will be printed on STDERR
62c7da899bSchristos
63c7da899bSchristos=back
64c7da899bSchristos
65c7da899bSchristos=back
66c7da899bSchristos
67c7da899bSchristos=head1 RETURN VALUES
68c7da899bSchristos
69c7da899bSchristos=over
70c7da899bSchristos
71c7da899bSchristos=item B<extract_pod_info> returns a hash table with the following
72c7da899bSchristositems:
73c7da899bSchristos
74c7da899bSchristos=over
75c7da899bSchristos
76c7da899bSchristos=item B<section =E<gt> N>
77c7da899bSchristos
78c7da899bSchristosThe man section number this .pod file belongs to.  Often the same as
79c7da899bSchristoswas given as input.
80c7da899bSchristos
81c7da899bSchristos=item B<names =E<gt> [ "name", ... ]>
82c7da899bSchristos
83c7da899bSchristosAll the names extracted from the NAME section.
84c7da899bSchristos
85*b0d17251Schristos=item B<contents =E<gt> "...">
86*b0d17251Schristos
87*b0d17251SchristosThe whole contents of the .pod file.
88*b0d17251Schristos
89c7da899bSchristos=back
90c7da899bSchristos
91c7da899bSchristos=back
92c7da899bSchristos
93c7da899bSchristos=cut
94c7da899bSchristos
95c7da899bSchristossub extract_pod_info {
96c7da899bSchristos    my $input = shift;
97c7da899bSchristos    my $defaults_ref = shift || {};
98c7da899bSchristos    my %defaults = ( debug => 0, section => 0, %$defaults_ref );
99c7da899bSchristos    my $fh = undef;
100c7da899bSchristos    my $filename = undef;
101*b0d17251Schristos    my $contents;
102c7da899bSchristos
103c7da899bSchristos    # If not a file handle, then it's assume to be a file path (a string)
104*b0d17251Schristos    if (ref $input eq "") {
105c7da899bSchristos        $filename = $input;
106c7da899bSchristos        open $fh, $input or die "Trying to read $filename: $!\n";
107c7da899bSchristos        print STDERR "DEBUG: Reading $input\n" if $defaults{debug};
108c7da899bSchristos        $input = $fh;
109c7da899bSchristos    }
110*b0d17251Schristos    if (ref $input eq "GLOB") {
111*b0d17251Schristos        local $/ = undef;
112*b0d17251Schristos        $contents = <$input>;
113*b0d17251Schristos    } else {
114*b0d17251Schristos        die "Unknown input type";
115*b0d17251Schristos    }
116c7da899bSchristos
117*b0d17251Schristos    my @invisible_names = ();
118c7da899bSchristos    my %podinfo = ( section => $defaults{section});
119*b0d17251Schristos    $podinfo{lastsecttext} = ""; # init needed in case input file is empty
120*b0d17251Schristos
121*b0d17251Schristos    # Regexp to split a text into paragraphs found at
122*b0d17251Schristos    # https://www.perlmonks.org/?node_id=584367
123*b0d17251Schristos    # Most of all, \G (continue at last match end) and /g (anchor
124*b0d17251Schristos    # this match for \G) are significant
125*b0d17251Schristos    foreach (map { /\G((?:(?!\n\n).)*\n+|.+\z)/sg } $contents) {
126*b0d17251Schristos        # Remove as many line endings as possible from the end of the paragraph
127*b0d17251Schristos        while (s|\R$||) {}
128*b0d17251Schristos
129*b0d17251Schristos        print STDERR "DEBUG: Paragraph:\n$_\n"
130*b0d17251Schristos            if $defaults{debug};
131*b0d17251Schristos
132c7da899bSchristos        # Stop reading when we have reached past the NAME section.
133c7da899bSchristos        last if (m|^=head1|
134c7da899bSchristos                 && defined $podinfo{lastsect}
135c7da899bSchristos                 && $podinfo{lastsect} eq "NAME");
136c7da899bSchristos
137c7da899bSchristos        # Collect the section name
138c7da899bSchristos        if (m|^=head1\s*(.*)|) {
139c7da899bSchristos            $podinfo{lastsect} = $1;
140c7da899bSchristos            $podinfo{lastsect} =~ s/\s+$//;
141c7da899bSchristos            print STDERR "DEBUG: Found new pod section $1\n"
142c7da899bSchristos                if $defaults{debug};
143c7da899bSchristos            print STDERR "DEBUG: Clearing pod section text\n"
144c7da899bSchristos                if $defaults{debug};
145c7da899bSchristos            $podinfo{lastsecttext} = "";
146c7da899bSchristos        }
147c7da899bSchristos
148*b0d17251Schristos        # Add invisible names
149*b0d17251Schristos        if (m|^=for\s+openssl\s+names:\s*(.*)|s) {
150*b0d17251Schristos            my $x = $1;
151*b0d17251Schristos            my @tmp = map { map { s/\s+//g; $_ } split(/,/, $_) } $x;
152*b0d17251Schristos            print STDERR
153*b0d17251Schristos                "DEBUG: Found invisible names: ", join(', ', @tmp), "\n"
154*b0d17251Schristos                if $defaults{debug};
155*b0d17251Schristos            push @invisible_names, @tmp;
156*b0d17251Schristos        }
157*b0d17251Schristos
158c7da899bSchristos        next if (m|^=| || m|^\s*$|);
159c7da899bSchristos
160c7da899bSchristos        # Collect the section text
161c7da899bSchristos        print STDERR "DEBUG: accumulating pod section text \"$_\"\n"
162c7da899bSchristos            if $defaults{debug};
163c7da899bSchristos        $podinfo{lastsecttext} .= " " if $podinfo{lastsecttext};
164c7da899bSchristos        $podinfo{lastsecttext} .= $_;
165c7da899bSchristos    }
166c7da899bSchristos
167c7da899bSchristos
168c7da899bSchristos    if (defined $fh) {
169c7da899bSchristos        close $fh;
170c7da899bSchristos        print STDERR "DEBUG: Done reading $filename\n" if $defaults{debug};
171c7da899bSchristos    }
172c7da899bSchristos
173*b0d17251Schristos    $podinfo{lastsecttext} =~ s|\s+-\s+.*$||s;
174c7da899bSchristos
175c7da899bSchristos    my @names =
176*b0d17251Schristos        map { s/^\s+//g;        # Trim prefix blanks
177*b0d17251Schristos              s/\s+$//g;        # Trim suffix blanks
178*b0d17251Schristos              s|/|-|g;          # Treat slash as dash
179*b0d17251Schristos              $_ }
180c7da899bSchristos        split(m|,|, $podinfo{lastsecttext});
181c7da899bSchristos
182*b0d17251Schristos    print STDERR
183*b0d17251Schristos        "DEBUG: Collected names are: ",
184*b0d17251Schristos        join(', ', @names, @invisible_names), "\n"
185*b0d17251Schristos        if $defaults{debug};
186*b0d17251Schristos
187*b0d17251Schristos    return ( section => $podinfo{section},
188*b0d17251Schristos             names => [ @names, @invisible_names ],
189*b0d17251Schristos             contents => $contents,
190*b0d17251Schristos             filename => $filename );
191c7da899bSchristos}
192c7da899bSchristos
193c7da899bSchristos1;
194