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