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