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