Pod.pm 5.0 KB

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