From e55e79a9ff734996c4ca66b74673fd47da2ce4b7 Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 16 2020 15:41:52 +0000 Subject: perl-podlators-4.11 base --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..146b3be --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +/Build +/Build.bat +/MANIFEST.bak +/Makefile +/Makefile.old +/META.json +/META.yml +/MYMETA.json +/MYMETA.yml +/_build/ +/blib/ +/cover_db/ +/nytprof.out +/nytprof/ +/pm_to_blib +/podlators-*/ +/podlators-*.tar.gz +/podlators-*.tar.gz.asc +/scripts/pod2man +/scripts/pod2text diff --git a/Changes b/Changes new file mode 100644 index 0000000..56c21e8 --- /dev/null +++ b/Changes @@ -0,0 +1,1098 @@ + User-Visible podlators Changes + +podlators 4.11 (2018-05-07) + + [Pod::Text] The default value of the sentence option is false, not + true, and has been since at least 2.0.0. Fix the documentation to + match. Thanks, eponymous alias. (#124461) + + [Pod::Text::Termcap] Correctly honor the width option, which was being + ignored due to a bug in interpreting user-supplied options. Thanks, + eponymous alias. (#124447) + + [Pod::Text::Color, Pod::Text::Termcap] Fix a subtle wrapping bug with + long =item text that would cause lines to be wrapped when they didn't + need to be. Thanks, eponymous alias. + + [Pod::Text::Color, Pod::Text::Termcap] Clear any text attributes at + the end of each line and reinstate them at the start of the next line, + since some pagers (less -R in particular) clear all text attributes at + the end of each line and were therefore not correctly showing + attributes in wrapped text. Thanks, eponymous alias. + + [Pod::Text::Termcap] Correctly get the terminal width from Term::Cap + information when COLUMNS isn't set, instead of getting a string value + that later cannot be used numerically. + + Specifying "none" for the errors option of Pod::Man and Pod::Text no + longer results in an errata section in the generated documentation, + matching the documented behavior. Thanks, Olly Betts. + + Fix order of SEE ALSO section in manual pages to match the + recommendation of perlpodstyle. + + Use https for all eyrie.org URLs. + + Add SPDX-License-Identifier headers to all substantial source files. + +podlators 4.10 (2017-12-25) + + [Pod::Man] Change man page references and function names to bold + instead of italic, following the current Linux man page standard. The + previous formatting was taken from Solaris, and it seems safe to say + that the Linux man page formatting conventions are now much more + widely followed than Solaris's. Patch from Guillem Jover. + + [Pod::Man] Revert the .IX handling code to the earlier version from + Bjarni Ingi Gislason but add the trailing backslashes that should + hopefully avoid blank page issues on HP-UX. This fixes a warning + regression when man is run with warnings enabled. (Debian Bug#847972) + + [Pod::Man] Wrap the output file descriptor in a glob before passing it + to PerlIO::get_layers so that the layer check works properly. + Previously, this code would throw a warning if given a scalar not + wrapped in a glob and not detect layers properly. Patch from Zefram. + (#122521) + + Produce a proper diagnostic when given empty input on standard input + with no other arguments to pod2man or pod2text. Reported by Guillem + Jover. + +podlators 4.09 (2016-11-05) + + [Pod::Text] Use Pod::Simple's logic to determine the native code + points for NO BREAK SPACE and SOFT HYPHEN instead of hard-coding the + ASCII values. Hopefully fixes the case of mysterious disappearing + open brackets on EBCDIC systems. (#118240) + +podlators 4.08 (2016-09-24) + + [Pod::Man] Partially revert change in 4.00 to require the name option + (--name to pod2man) when generating man pages from standard input. + Historically, pod2man silently tolerated this, and there turned out to + be a lot of software that depended on this, making the change too + disruptive. Instead, silently set the man page title to STDIN in this + case, but warn about it in the documentation. (#117990) + + [Pod::Man] Fix rendering bug for "TRUE (1)", which was recognized as + needing small caps and then erroneously as a man page reference, + resulting in escaped nroff. (Found by Dan Jacobson with the + XML::LibXML::Element man page.) (Debian Bug#836831) + + [Pod::Man] Fix rendering bug causing "\s0(1)" to be mistakenly marked + as a man page reference, later confusing backslash escaping. + + [Pod::Man] Add new lquote and rquote options (and corresponding + --lquote and --rquote flags to pod2man) to set the left and right + quotes for C<> text independently. (#103298) + + Remove test for nested L<> markup, since an upcoming version of + Pod::Simple will drop support for this. (#114075) + +podlators 4.07 (2016-03-20) + + [Pod::Man] Avoid undefined variable warnings when determining the + title for a Perl module at the top level of a distribution. Thanks, + Dave Mitchell. (#112625) + + [Pod::Man] Fix font resets with nroff when fixed-width fonts are used + in the label for an =item. Previously, italic was being ended with + \f(CW even in nroff mode, which, with groff, only changes the font to + fixed-width and doesn't reset to a non-italic font. Thanks, Paul + Townsend. (#98199) + + [Pod::Man] Suppress warnings about a missing Encode module if + PERL_CORE is set in the environment. Due to build ordering during + Perl core builds, Encode is expected to not yet be available during + the build step that sets PERL_CORE. Thanks, Dave Mitchell. + +podlators 4.06 (2016-01-31) + + Handle scripts ending in .com on VMS systems and don't generate the + man page for perlpodstyle when built as part of Perl core. These are + hopefully the last two changes required to fully merge with Perl core + without core having to maintain a separate build system. Thanks, + Craig A. Berry. + + During build, generate the pod2text and pod2man man pages from the + *.PL files rather than the generated scripts. This may be required + due to the different script extensions on VMS hosts. + + Rename perlpodstyle back to perlpodstyle.pod, since we no longer need + the workaround for Module::Build's POD handling. + +podlators 4.05 (2016-01-16) + + Switch back to generating pod2man and pod2text from *.PL files. While + ExtUtils::MakeMaker can fix the #! line, it can't handle all non-UNIX + operating systems, and the *.PL script generation code can. This will + hopefully remove the need for Perl core to maintain a separate copy of + the *.PL wrapper scripts as well. Thanks, Craig A. Berry. + + [Pod::Man] Fall back (with a warning) to non-utf8 behavior if the utf8 + option is specified but the Encode module is not available. This is + useful in some cross-compilation situations. Thanks, Niko Tyni. + + Don't try to remove the temporary directory used by tests in the tests + themselves, since this races with other tests run in parallel. + Instead, just remove it on make clean. + + Provide a mailto address in bug tracking metadata, use the shorter + form of the RT bug tracker URL, and fix the license value to match the + new metadata specification. + +podlators 4.04 (2016-01-02) + + Fix portability of the t/docs/synopsis.t test to Windows. It was + assuming UNIX path delimiters when filtering out files it didn't + intend to test. + + Don't include .travis.yml in the distribution so that it isn't picked + up by Perl core. Thanks, Karen Etheridge. (#110385) + + Add homepage information to the CPAN metadata and change the canonical + repository location to GitHub. + +podlators 4.03 (2015-12-06) + + Fix tests when POD_MAN_DATE or SOURCE_DATE_EPOCH are already set in + the environment. Thanks, Niko Tyni. (Debian Bug#807086) + + Continue general improvements and refactoring of the test suite to + make it more maintainable and clean out duplicate or unnecessary code. + +podlators 4.02 (2015-12-02) + + For versions of Perl prior to 5.11, install the modules into the Perl + core module directories, since in those versions site modules did not + take precedence over Perl core modules. Thanks, Peter Rabbitson. + (#110024) + +podlators 4.01 (2015-12-01) + + [Pod::Text::Termcap] Do not override the TERMPATH environment variable + if it's already set. This should fix the test suite with Term::Cap + 1.16 (which has a bug in termcap handling if TERMPATH doesn't point to + a valid file). Also document the manipulation of TERMPATH. + + Revert the switch to Module::Build as the build system. This creates + a circular dependency with Module::Build, since it wants a newer + version of Pod::Man than in Perl versions prior to 5.10.1. Instead, + add the new metadata to Makefile.PL and stick with a single build + system that will also work inside Perl core. + +podlators 4.00 (2015-11-28) + + Increase the version number of the package to be larger than any of + the previous version numbers of any of the modules, and change all + modules to use the same version as the overall podlators package. + Switch to a simple decimal version number to avoid complexity with + v-strings and portability to old versions of Perl. + + podlators now requires Perl 5.006 or later. All modules enable + warnings. Please report any unexpected or confusing warnings as bugs + in the bug tracker. + + [pod2man] In previous versions, the -r or --release option could be + specified without an argument and was interpreted as setting that + value to the empty string. That never made a great deal of sense, and + the original change to Perl was apparently because no one realized one + could pass the empty string as the argument value. The argument is + now mandatory, but may be the empty string, which will cause some + *roff implementations to use the system default. + + Allow any even number of characters to be specified as the quote marks + for Pod::Text and Pod::Man (and the corresponding --quotes options of + pod2text and pod2man), rather than being artificially limited to one- + or two-character quotes. The first half of the string will be used as + the left quote and the second half as the right quote. This allows + Unicode characters or groff escapes like \(lq and \(rq to be used. + (Partly addresses #103298) + + [Pod::Man] Attempt to detect if the input came from a pipe and + therefore has a completely unhelpful (and nonreproducible) source file + name, and diagnose this as an error. Document that the name option + (--name to pod2man) is required when processing POD source from + standard input. (Debian Bug#777405) + + [Pod::Man] Honor the environment variable SOURCE_DATE_EPOCH and use it + as the timestamp from which to derive the left-hand footer if the date + option is not set, overriding the timestamp of the input file. This + is primarily useful to ensure reproducible builds of the same output + file given the same source and Pod::Man version, even when file + timestamps may not be consistent. Thanks, Niko Tyni. (Debian + Bug#801621) + + [Pod::Man] Honor the environment variable POD_MAN_DATE and use its + contents, if set, as the value of the left-hand footer if the date + option is not set, overriding the timestamp of the input file. This + was an earlier version of SOURCE_DATE_EPOCH, but has been supported in + Debian for a while and doesn't serve exactly the same purpose, so both + continue to be supported. Thanks, Niko Tyni. + + [Pod::Man] The default left-hand footer date is now based on UTC + rather than the local time zone to make the output more reproducible. + Thanks, Chris Lamb. (Debian Bug#780259) + + [Pod::Man] Simplify the preamble code for handling the F register and + index entries, and add backslashes after the braces in the preamble + code for handling the F register to avoid introducing a spurious page + break before at the first page with AT&T *roff. Thanks, Carsten + Kunze and Daphne Pfister. (#92979) + + [Pod::Man] Support setting the left-hand footer to the empty string. + + Fix documentation of the utf8 option to Pod::Man and Pod::Text, and + the corresponding -u option to pod2man and pod2text, to reflect that + Pod::Simple now autodetects Latin-1 and UTF-8 but warns. + + More clearly document the options that set values in the .TH header in + the pod2man and Pod::Man documentation. Thanks, Guillem Jover. + (#103297) + + [Pod::Text] Fix encoding handling in documents that start without an + encoding declaration and then declare an encoding partway through. + Previously, this would result in attempts to print wide characters if + there were non-ASCII characters in the document. Thanks, Magnolia K. + (#101722) + + [Pod::Text] Change the documentation to not say Pod::Text only + generates ASCII text. (#89355) + + Switch the preferred module build system to Module::Build, but still + provide a Makefile.PL file for backward compatibility and for the use + of Perl core. (#108714) + + Installation of this package no longer tries to overwrite the Pod::Man + and Pod::Text modules that come with Perl core, and instead relies on + the normal precedence rules in Perl's module search path that prefer + locally-installed modules over core modules. + + Rename NEWS to Changes to match the normal Perl convention. + + Work around a bug in Term::Cap 1.16 that caused the test suite to fail + by forcing a setting of TERMPATH to a termcap file provided by the + test suite while running tests. (#98272) + +podlators 2.5.3 (2013-10-05) + + Fix documentation of the default for the errors constructor parameter. + + Skip the empty text and man page errors tests if Pod::Simple didn't + produce any errors, which happens with the version shipped with Perl + versions prior to 5.18. Catch warnings as well as exceptions in these + tests. + +podlators 2.5.2 (2013-09-22) + + The parse_lines and parse_string_document methods in Pod::Man and + Pod::Text now set a default output file handle of STDOUT if none was + set. + + Perform document initialization even if the document is contentless. + Documents with only errors are shown as contentless but then have a + POD ERRORS section, and previously this led to internal errors because + state variables weren't properly initialized. Thanks, Andreas Koenig. + (#88724) + + Apply various optimization improvements from Dagfinn Ilmari Mannsåker. + There should be no changes in the output. (#83253) + + Fix an erroneous output_fh reference in the Pod::Man documentation. + Thanks, Andreas Koenig. (#88723) + + Fix various comment typos. Thanks, David Steinbrunner. (#85683) + + In perlpodstyle, wrap verbatim license line in POD that was over 79 + characters after the man page indentation. Thanks, Brian Gottreu and + Steve Hay. (#87440) + +podlators 2.5.1 (2013-02-27) + + Adjust the tag width tests and the list handling tests to avoid + spurious warnings from Pod::Simple about mismatched =item types. + +podlators 2.5.0 (2013-01-02) + + Support a new errors option in Pod::Man and Pod::Text. Valid values + are die, stderr, pod, and none. Convert the stderr option to the + errors option with value stderr. Add the corresponding --errors + option to pod2man and pod2text. (#39007) + + Add a new nourls option to Pod::Man and Pod::Text to suppress the URL + from L<> formatting codes that contain anchor text, and add the + corresponding --nourls option to pod2man and pod2text. (#62210) + + [Pod::Man] Extend a small-caps section through the punctuation that + commonly appears in license disclaimers so that small caps isn't + turned on and off at the boundaries of every word, producing + unreadable *roff. + + [Pod::Man] Collapse consecutive whitespace and remove newlines in + index term text. Thanks, Kevin Ryde. (#82332) + +podlators 2.4.2 (2012-06-01) + + Remove the test of a POD document without an encoding. We previously + tested that this interpreted the document as ISO 8859-1, but + Pod::Simple behavior has changed so that the test started failing, + plus Pod::Simple now warns about a missing =encoding. (#77553) + +podlators 2.4.1 (2012-05-30) + + Fix detection of PerlIO UTF-8 handling by requesting details on PerlIO + layers to look for the UTF8 flag, which is not a layer in its own + right. Thanks, Leon Timmermans. (#76440) + + [Pod::Man] Fix handling of the F register when processing multiple + documents at once. .IX will now continue to be defined for documents + after the first, and the page number will not be reset at the start of + each document. Thanks to Nicholas Clark for the analysis. (perl + #103202) + + In the pod2man and pod2text driver scripts, report an error and remove + the empty output file if the input file had no content (if it did not + exist, for example). Exit with non-zero status if there were any + errors. Track contentless status inside Pod::Man and Pod::Text. + Thanks, Dmitry Smirnov. (#75099) + + Override parse_file in Pod::Man and Pod::Text to set output_fh to + STDOUT if it is not already set. (#77530) + + [Pod::Man] Format the URL text before comparing it to the anchor when + deciding whether to show separate anchor text. This avoids spurious + mismatches between the URL target and anchor text because the anchor + text was already formatted and has (for example) hyphens escaped. + (#76396) + + [Pod::Man] Define \*(C` and \*(C' to the empty string when processed + through troff to avoid groff warnings. Avoid warnings from checking + the F register (used to enable index output) when running under groff. + Patch from Bjarni Ingi Gislason. (#75434) + + [Pod::Man] Fix the ASCII fallback string for the AE ligature to use + the string that was actually defined. + + Stop removing pod2man and pod2text on make realclean, left over from + when they were generated from *.PL scripts. (#74848) + + Embed the PID in file names generated by the test suite to avoid + conflicts when running the test suite in parallel. (#62083) + +podlators 2.4.0 (2010-10-10) + + Switch UTF-8 output encoding to use Encode directly instead of adding + a PerlIO layer. Probe the PerlIO layers with protection for Perl + versions without PerlIO and set a flag indicating whether we also need + to encode, to avoid double-encoding when writing to a file handle that + is already doing UTF-8 encoding via PerlIO. + + [Pod::Man] Do not strip escaped trailing whitespace such as that + created by S<> at the end of a line, since the backslash is then taken + by *roff as escaping the newline. Thanks, Kevin Ryde. (#61781) + + Add perlpodstyle, a new style guide for POD documentation, split + mostly from the NOTES section of the pod2man man page. Remove the + NOTES section of pod2man's documentation. + + Convert pod2man and pod2text from scripts generated from *.PL files to + simple scripts, relying on ExtUtils::MakeMaker to handle replacing the + #! path during the package build. + +podlators 2.3.1 (2010-02-17) + + Increase $VERSION in Pod::Text::Color and Pod::Text::Termcap, missed + in the previous release. + +podlators 2.3.0 (2009-12-28) + + Support anchor text for L<> links of type URL by rendering the anchor + text and then the URL in angle brackets. Now requires Pod::Simple + 3.06 or later. + + [Pod::Text] When formatting item tags, use the width of the tag + without formatting codes. This fixes formatting issues with + Pod::Text::Color, Pod::Text::Termcap, and Pod::Text::Overstrike. + + [Pod::Man] Suppress all formatting in the NAME section to avoid + confusing lexgrog and fix mishandling of C<> markup in NAME. Clarify + in the pod2man documentation that no markup should be used in the NAME + section of a manual page. Thanks, Niko Tyni. + + [Pod::Man] Escape backslashes in the quoted text of .IX macros + generated from X<> formatting code. + + [Pod::Man] Avoid using POSIX::strftime because POSIX requires Fcntl, + which is an XS module, and hence can't build in miniperl. This allows + ExtUtils::MakeMaker to build as a normal module in Perl core. Thanks, + Michael G Schwern. + + [Pod::ParseLink] Allow anchor text for URLs. Fix the check of the + anchor text to not think no text was provided when the text was "0". + + Remove the temporary files created by the test suite in a loop to + ensure that all versions are deleted on VMS. Thanks, John + E. Malmberg. + + Convert the test suite to Test::More. + +podlators 2.2.2 (2009-01-17) + + [Pod::Text] Correctly handle indentation of verbatim paragraphs that + contain lines with only whitespace. Thanks, Renee Baecker. + +podlators 2.2.1 (2008-12-19) + + [Pod::Text] In the legacy pod2text method, properly initialize the + output file handle when called with only one argument. Thanks, + Michael G Schwern. + + Fix the t/text-encoding.t test on Windows by setting raw encoding on + the output file handle. Thanks, Steve Hay. + +podlators 2.2.0 (2008-10-05) + + [Pod::Text] Try to preserve the previous behavior of setting the + output encoding to match the input encoding if utf8 is not set, but + support forcing an output encoding of utf8 with the utf8 option. Add + a corresponding --utf8 option to pod2text. Document the PerlIO + limitations of the current utf8 support. + + Quote all module version numbers to preserve any trailing zeroes. + + Skip spelling tests unless RRA_MAINTAINER_TESTS is set in the + environment. Spelling dictionaries are too different between systems. + +podlators 2.1.4 (2008-09-21) + + Support aspell as a spell checker for spelling tests. + + Skip UTF-8 tests for versions of Perl prior to 5.8. + +podlators 2.1.3 (2008-09-14) + + Add a stderr option to Pod::Man and Pod::Text that sends POD errors to + standard error instead of adding a POD ERRORS section to the generated + documentation. Add a corresponding --stderr option to pod2man and + pod2text. + + [Pod::Man] Stop remapping the code point for non-breaking space. This + should not be necessary and was wrong when the string from Pod::Simple + was a character string and not a byte string. It was papering over a + bug in setting the encoding of an input POD file. + + In the test suite, properly set encoding on file descriptors so that + the UTF-8 tests are handled with the correct encoding. Test that + non-breaking spaces don't interfere with hyphen detection. + +podlators 2.1.2 (2008-07-20) + + [Pod::Man] Use .SS instead of a local .Sh macro for subheadings, and + stop defining .Sh. + + [Pod::Man] Remap ISO 8850-1 non-breaking spaces produced by + Pod::Simple to the corresponding UTF-8 code point for UTF-8 output. + + Add a test for spelling and fix multiple spelling and markup errors. + +podlators 2.1.1 (2008-07-03) + + [Pod::Man] Do not include the accent mark definitions in generated + *roff if the output is in UTF-8. + + Fix the test for S<> handling with all whitespace to not give a + spurious failure with Pod::Simple 3.06. + +podlators 2.1.0 (2008-06-01) + + Add a new utf8 option to Pod::Man. If set, do not convert non-ASCII + characters to *roff escapes or X, and instead output literal UTF-8 + characters. Add a new --utf8 option to pod2man. + + [Pod::Man] Match text between \f(CW and \fP or \fR in headings + non-greedily to get the fonts right with multiple C<> formatting + codes. + + [Pod::Man] Protect .Sh text against leading *roff control characters + since some *roff implementations apparently "look through" font + escapes at the beginning of lines. + + [Pod::Man] Escape backslashes separately from processing non-ASCII + characters and do that, dash escaping, and underscore adjustment + before processing non-ASCII characters. Otherwise, we escape the + hyphen in eth characters. + +podlators 2.0.6 (2007-11-28) + + [Pod::Man] Escape apostrophes and backquotes in verbatim and C<> text. + + [Pod::Man] Define the IX macro to empty rather than leaving it + undefined when indexing is not requested to eliminate warnings when + groff warnings are enabled. + + [Pod::Man] Simplify the logic to skip lib directories to avoid Perl + warnings and unnecessary checks. + +podlators 2.0.5 (2006-09-16) + + Accept and mostly ignore a hash of options as the first option to + parse_from_file. Support an option of -cutting and configure + Pod::Simple to assume the POD has already started. This is for + backward compatibility with Pod::Parser. + + [Pod::Man] Recognize more uses of hyphens in regular English text and + allow them to be regular hyphens. + + [Pod::Man] Turn off hyphenation and, for nroff, justification after + the .TH macro since that's where groff turns them on. + + [Pod::Man] Stop mapping vertical bar to \(bv, since it produces + Unicode characters where they aren't desirable. Remove the preamble + reference to the Tr string, which was never defined. + +podlators 2.0.4 (2006-02-19) + + [Pod::Man] Pod::Simple's source_filename method returns garbage if + we're parsing from a file handle, so use the current time if stating + the returned input file fails. + + Add parse_from_filehandle methods to Pod::Man and Pod::Text for + backward compatibility with the earlier versions based on Pod::Parser. + +podlators 2.0.3 (2006-01-28) + + In the test suite, pass in a file handle for Pod::Simple output and + then close it afterwards. This works around Pod::Simple leaving file + handles open and preventing removal of temporary files on Windows. + This is temporary until a new Pod::Simple release offers a better + approach. + +podlators 2.0.2 (2006-01-25) + + In the parse_from_file method, flush the output file handle rather + than closing it. Closing it is unexpected and could break callers. + + In Pod::Text::Termcap and Pod::Text::Color, Use additional temporary + variables to avoid ${char}{0,$width}, which only works in very recent + Perls. + + Fix man test that needs an ISO 8859-1 encoding. + +podlators 2.0.1 (2006-01-20) + + Call reinit before calling the Pod::Simple parse_from_file method to + preserve the previous capability of reusing the same Pod::Man object + for multiple documents. Close the output file handle after + Pod::Simple returns to force the output to flush. + + [Pod::Text] The legacy pod2text method was broken because + Pod::Simple's parse_file method only takes one argument. Pass the + second argument to output_fh instead. + + Fix portability issues with Perl 5.005. + + Use a single object for all conversions in pod2man and pod2text for a + minor speedup. + +podlators 2.00 (2005-11-28) + + Rewrite all modules and driver scripts to use Pod::Simple instead of + Pod::Parser. The output should be identical except that C<> with no + content outputs quotes for Pod::Text-based parsers, E<> handling is + improved, and various small bugs have been fixed. Thanks, Sean Burke. + + [pod2man] Create a new parser for each file since Pod::Simple parsers + are not reusable. + + [pod2text] Add support for multiple pairs of input and output files, + similar to pod2man. + + [Pod::Man] Strip vendor_perl as well as site_perl when determining the + man page title. Thanks, Alexey Tourbin. + + Fall back on fullstop_space_harden if preserve_whitespace is not + available, for compatibility with older Pod::Simple. + + Count text lengths correctly when wrapping in Pod::Text::Color and + Pod::Text::Termcap when there are multiple adjacent escape sequences. + Use a temporary variable to make the regex clearer. + + Change section ordering in some documentation following perl5-porters + discussion. + + Remove obsolete documentation caution against enclosing URLs in L<>. + + Force a particular terminal configuration to get reliable results in + the Pod::Text::Termcap test suite. + + Enhance the test suite substantially with additional tests from Sean + Burke. + +podlators 1.27 (2003-07-09) + + [Pod::Text::Termcap] Handle the case where the HOME environment + variable isn't set, mostly for Windows. + +podlators 1.26 (2003-03-30) + + [Pod::Man] Make sure the module returns 1 to keep Perl 5.8.0 happy. + +podlators 1.25 (2003-01-04) + + [Pod::Man] Track the type of items in an =over list and only map + asterisk to a real bullet if the item type is bullet. Fix a bug where + =item 0 was treated the same as =item with no tag. + +podlators 1.24 (2002-08-03) + + Support a margin option in Pod::Text and use it to set the initial + indentation level. Fix handling of the colon in the margin when the + alt format is enabled. Add a new -m option to pod2text to set the + margin. + +podlators 1.23 (2002-07-14) + + Clean up some old-style L<> links in pod2text that were workarounds + for fixed bugs in Pod::Man and Pod::Text. + + Add a pointer to the module web site in the documentation. + +podlators 1.22 (2002-06-23) + + Tweak the regex for matching numbers in C<> to not consider a single + period to be a number, which affects whether surrounding quotes are + added. + +podlators 1.21 (2002-02-16) + + [Pod::Text::Overstrike] Fix the regex for wrapping lines to use a + non-backtracking section for each character to avoid exponential + backtracking on lines with a lot of markup. + +podlators 1.20 (2002-01-27) + + [Pod::Text::Overstrike] Use [\b] instead of \cH in regexes to match + backspaces, for platforms that use EBCDIC where \b and \cH aren't the + same character. + +podlators 1.19 (2002-01-02) + + [Pod::Man] Do not apply guesswork to the text inside the NAME section, + since it may confuse programs like catman. Do not output .UC after + the .TH macro. catman doesn't like anything between the NAME section + and .TH, and .UC doesn't appear to actually do anything on any modern + platform. + + [Pod::Man] Correctly handle a verbatim paragraph right before a + heading. + + [Pod::Text] Fix error reporting for unknown sequences and unknown + commands to be more consistent and update the documentation to match. + + [Pod::Text::Termcap] Terminal speed should be a number, not a string. + Also fall back on a hard-coded terminal speed if getospeed doesn't + work. + +podlators 1.18 (2001-11-30) + + [Pod::Text::Termcap] Fall back on a hard-coded terminal speed if + POSIX::Termios doesn't work, such as on VMS. + + [Pod::ParseLink] Escape L<> in the NAME section of the documentation. + +podlators 1.17 (2001-11-27) + + [Pod::Man] Return references to arrays rather than references to + scalars for already-formatted text. There are too many odd bugs with + scalar references in older versions of Perl. No longer bless + references since the current Pod::Parser doesn't require it. Now + requires Pod::Parser 1.13 or later. + + Change all documentation references from interior sequences to + formatting codes to match the terminology of perlpodspec. + + [Pod::Text::Termcap] Fix an incorrect heading in the documentation. + +podlators 1.16 (2001-11-26) + + Use an @INC path of ../lib and a new function to find source files for + when the module test suite is being run as part of the Perl core + tests. + +podlators 1.15 (2001-11-26) + + [Pod::Text::Termcap] Wrap the call to Term::Cap with eval because it + throws exceptions if the terminal can't be found. Fall back on the + ANSI escape sequences rather than dying if the termcap entry is + incomplete. Note the fallback in the documentation. + + Delete the lax option in pod2man before calling Pod::Man and document + that it is obsolete and podchecker should be used instead. + + Improve the pod2man and Pod::Man documentation to refer to podchecker, + add discussion of guesswork and 8-bit character handling, and mention + the fragility of the heuristics. + +podlators 1.14 (2001-11-23) + + [Pod::Text::Overstrike] Interpolate before formatting to prevent the + formatting codes from ending up in the output, and strip any existing + formatting before applying new formatting. + + [Pod::Man] Use font escapes rather than .I to avoid strange problems + with quoting, at least for =head3. =head1 and =head2 likely still + have troubles with repeated double-quotes. Fix all fixed-width font + changes for nroff, not just the simple ones, and don't hard-code the + value of any fixed-width font. + + [Pod::Man] Improve and simplify the handling of indentation shifts. + + [Pod::Man] When intuiting the man page name for a module, also strip + $^O by itself as a directory component even when not preceded or + followed by a dash and other text. + + [Pod::Text] Fix handling of =for or =begin/=end in =item paragraphs. + Default to a tag of "*" if none is given. Insert some whitespace for + empty item paragraphs to keep them from blending into subsequent text. + + [Pod::ParseLink] Fix a bug in the handling of link text that's + entirely in quotes. Double quotes are now only removed around + sections, not names. Text enclosed entirely in double quotes is + interpreted as a link to a section. + + Fix various -w warnings. + +podlators 1.13 (2001-11-15) + + Fix -w warnings with hyphen handling. + +podlators 1.12 (2001-11-15) + + Add a new module, Pod::ParseLink, to parse the contents of an L<> + sequence. Use it everywhere. Defer expansion of formatting escapes + inside L<> until after L<> is processed. Surround URLs with angle + brackets in the output. + + Remove the special handling of consecutive L links. + + Support E, E, and E. + + [Pod::Man] Completely rewrite the name parsing code for modules to use + File::Spec. In the process, fix a bug in dealing with the new + three-component version number directories. Swap the order of date + and release in the .TH line to better comply with the man macro + documentation. + + [Pod::Man] Rewrite the handling of dashes and hyphens. Be much more + conservative about which hyphens are turned into dashes, and make all + hyphens non-breaking unless we can be fairly sure that they're inside + normal words. + + [Pod::Man] Handle indentation of =item-less =over/=back blocks. + + [Pod::Man] Include the version of Pod::Parser in the header. + + [Pod::Man] Only try to determine a module name from the path for the + man page name if the man page we're generating is in section 3. + + [Pod::Man] No longer insert a timestamp into the generated man page; + it just causes unnecessary differences and merge conflicts. + + [Pod::Text] Inside S<>, convert all whitespace to non-breaking spaces, + not just spaces. + + Add the --name option to pod2man and document the name option in + Pod::Man. + + [Pod::Man] Use L<> for all man page references in the documentation + that should be highlighted. Switch the rest to bold versions of the + program name. Change func(n) to func(3) in the example of things that + are automatically formatted so that it will be formatted. Remove from + BUGS the note that some of the path mangling assumes Unix directory + separators. Don't give anchor text for L<> links that no longer + require it. + + Update the documentation in Pod::Text and subclasses to use + now-allowable POD constructs like C<< >>. Don't escape angle brackets + that don't require escaping. Don't give anchor text for L<> links + that no longer require it. + +podlators 1.11 (2001-10-20) + + Add the code option to Pod::Text to include the non-POD text of the + input file and document it. Add the corresponding --code flag to + pod2text. + + Converted warnings for unknown escapes, unknown sequences, and + unmatched =back into warnings from carps and include the file and line + number of the POD data instead of the Perl code. + + [Pod::Text::Overstrike] Better handle the case where a highlighted + portion of text ends a line. + + Add --verbose flag to pod2man to print out each output file as it is + generated. + + [Pod::Man] Fix *roff syntax error from using .if with .el during quote + handling. + + [Pod::Man] Fix output for X<> sequences. + +podlators 1.10 (2001-07-10) + + Add heuristics to decide whether to quote the argument of C<>. + + [Pod::Man] Remove font changes for nroff with C<> to work around a bug + in the Solaris 2.6 version of nroff's handling of \fP in headings. No + longer add an extra level of quoting for =item; it isn't necessary. + + [Pod::Man] Remove the logic turning PI into a pretty pi character. It + produces too many false positives. + + [Pod::Man] Remove the definition .Ip from the preamble. Remove .bd B + 3 from the preamble; this isn't part of the accent mark definitions + but instead changes the way bolding is done, confusing some other + translators. Use .IP instead of .Ip everywhere. + + In the POD style section of pod2man, add a description of the + COPYRIGHT AND LICENSE section, add a mention of a mailing list in SEE + ALSO, and mention that large logs are better kept separate from + HISTORY in the description of a standard manual page. + + Standardize on COPYRIGHT AND LICENSE for licensing information across + all of the package documentation. + +podlators 1.09 (2001-04-09) + + [Pod::Man] Fine-tune formatting guesswork. Don't allow colons after + sequences to put in small caps since they're already handled by being + rolled into the sequence and were causing weird things to happen in + references to functions. Allow small caps before an open paren. + Teach the handling of functions and manual page references about small + caps escapes, and be pickier about what constitutes a manual page + reference. + + [Pod::Text] Fix again the incorrect mappings for E and + E, and this time for E and E too. Thanks, + Sean Burke. + +podlators 1.08 (2001-02-09) + + Output anything that looks like a URL verbatim rather than + interpreting it as a manual page reference. + +podlators 1.07 (2001-01-16) + + [Pod::Man] Remove newlines from heading contents. + + [Pod::Man] Quote the file name in the man page header if it contains + spaces. + +podlators 1.06 (2000-12-25) + + New Pod::Text::Overstrike contributed by Joe Smith. Add -o or + --overstrike to pod2text to use it for formatting. + + [Pod::Man] =item text requires another level of quoting of double + quotes, which was already present but not working for C<> text because + it was in the wrong order. Fix. + +podlators 1.05 (2000-11-18) + + Change the default quote character for C<> to be double quotes rather + than matched left/right single quotes. + + Add support for =head3 and =head4. + + Allow pod2man to take multiple pairs of input and output files on the + command line to decrease the time that it takes to process all of + Perl's documentation. + + [Pod::Man] Switch \*C` and \*C' sequences from C<> as well as literal + double-quotes if the quote character contains double quotes. Not + doing this was causing weird output on some systems in some + circumstances. Use a separate quote mapping function for text blocks + to work around a Solaris 2.6 nroff bug. + + [Pod::Man] Use \fP to switch back to the default font rather than + changing back to \fR so that font changes work correctly in headings + using a different font. Sprinkle \fP through all font changes so that + the default font is always the "previous" font so that the above + works. + +podlators 1.04 (2000-10-09) + + [Pod::Man] Output .PD 0 and .PD around repeated =item tags so that + they're formatted without intervening blank lines, improving + formatting of, e.g., perlfunc.pod. + + [Pod::Text] Fix incorrect mappings for E and E. + Thanks, Sean Burke. + +podlators 1.03 (2000-09-03) + + Support configuration of what quote characters to use around C<> + text. Add a new --quotes option to pod2man and pod2text. + + Report nicer errors when encountering an unknown paragraph command. + + Add support for E and E. + + [Pod::Man] Fix the regex for stripping bullets from index entries so + that it doesn't strip a leading "o". + + [Pod::Man] In the prelude, terminate the .IX definition with ".." + instead of ". ." for groff. + + [Pod::Text] The pod2text method, when given two arguments, was + incorrectly assigning to $_[0], causing other sane problems. Fix. + +podlators 1.02 (2000-04-25) + + [Pod::Man] Fix hyphens and underscores only in literal C<> content, + fixing mangling of hyphens and underscores that are the result of + other sequence processing. + +podlators 1.01 (2000-03-30) + + Install the modules in the Perl core area if the Perl version is 5.6.0 + or higher. + + [Pod::Man] Strip a leading lib/ from a file name for module man pages, + needed for ExtUtils::MakeMaker. + +podlators 1.00 (2000-03-16) + + This has now been incorporated into Perl core as pod2man and pod2text. + Rename pod2roff to pod2man accordingly. + + Hide "-" arguments to the driver scripts from Getopt::Long so that + Pod::Parser will interpret them as STDIN or STDOUT. + + [Pod::Man] Protect any line that starts with a backlash and leading + periods following font escapes. Replace embedded newlines in titles + with spaces. + + [Pod::Man] Use "perl v5.6.0" instead of "perl 5.6, patch 0" for the + default release string, handle both pre-5.6 and post-5.6 version + numbering schemes. Zero-pad the month and day in the modification + date. Avoid warnings when center, date, or release aren't set. + + [Pod::Man] Allow for two-character fonts. + + [Pod::Man] Work around a Perl 5.6 bug affecting L<> text generation. + Fix Z<> handling with current Perl. + + [Pod::Man] Make filename munging safe even when $* is set and the + filenames contain embedded newlines. + + [Pod::Man] Fix the regex to concatenate multiple L<> section links and + fix whitespace handling for it around "and". + + [Pod::Text] Add the remaining ISO 8859-1 HTML entities. Thanks, Tim + Jenness. + + [pod2man] Change Getopt::Long config from bundling to + bundling_override so that options like -center work for backwards + compatibility. + + [pod2text] Don't default to Pod::Text::Termcap even if STDOUT is a tty + until it works right on Windows, VMS, etc. + +podlators 0.08 (1999-10-07) + + Add support for numeric E<> escapes. + + [Pod::Man] Fix doubled quotes in links to sections. + + [Pod::Text] Export pod2text for backwards compatibility. + + [pod2roff] Fix argument passing to Pod::Parser to use an expanded hash + instead of a hash reference. + +podlators 0.07 (1999-09-25) + + [Pod::Man] Change the parsing model so that, rather than deferring E<> + escapes until just before output, *roff output is generated by the + interior sequence parsing and the result is passed up the parse trees + as Pod::Man::String objects instead of scalars to mark the output as + already processed. In the process, clean up what *roff escaping and + guesswork is applied where, and clean up the whole process of applying + guesswork. Improve the escaping of dashes and hyphens to use a single + pass. + + [Pod::Man] Improve the small caps guesswork to allow for more cases, + including several adjacent all caps words. + + [Pod::Man] Fix some bugs with the link text generation for man page + references. + + [Pod::Man] Improve the index generation slightly. + + [Pod::Man] Fix several places that were clobbering the caller's $_. + +podlators 0.06 (1999-09-20) + + Add pod2roff and Pod::Man, which convert POD to man pages. + + Rename pod2txt to pod2text and Pod::PlainText to Pod::Text. + + [Pod::Text] =begin text blocks are now output verbatim rather than + interpreted as POD. + + [Pod::Text] Document the oddity with Ctrl-As as a restriction. + + [Pod::Text] Always treat =for paragraphs as verbatim text. + + [Pod::Text::Color] Add a BUGS note that the implementation is rather + incomplete, and document the reliance on Term::ANSIColor. + + [pod2text] Add an explicit check for Term::ANSIColor if -c was given. + + [Pod::Man] Add a BUGS entry for index entries for stuff in NAME. + + [Pod::Text] Document two more diagnostics and a cross-reference to + pod2text. + + [pod2text] Add documentation of -h and expand the DIAGNOSTICS section + to include directly-generated error messages and the most common + Getopt::Long message. + +podlators 0.05 (1999-09-18) + + [Pod::Text::Color] Rename Pod::SimpleText to Pod::PlainText in one + more place in the documentation. + +podlators 0.04 (1999-08-30) + + Use File::Spec during the build to build file paths for portability, + and remove the dist setting since current Perls get this right. + + Fix the #! line in pod2txt during the build. + +podlators 0.03 (1999-08-30) + + Rename Pod::SimpleText to Pod::PlainText. + + [pod2txt] Document that Pod::Text::Termcap is used by default if + STDOUT is a tty. Clarify the documentation of --loose. + +podlators 0.02 (1999-07-29) + + Rename the package itself from Pod::SimpleText to podlators. + + [Pod::SimpleText] Add a pod2text function for backwards compatibility. + + [Pod::SimpleText] Properly wrap multiline =item tags. + + [Pod::SimpleText] Fix a spurious space with =for text commands. + + [Pod::SimpleText] Check the content of sequences against the empty + string specifically rather than testing truth so that it does the + right thing with 0. + + [Pod::SimpleText] Process sequences for =head headings. + +podlators 0.01 (1999-06-12) + + Initial release with pod2txt and Pod::SimpleText. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bccfcea --- /dev/null +++ b/LICENSE @@ -0,0 +1,57 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Comment: This file documents the copyright statements and licenses for + every file in this package in a machine-readable format. For a less + detailed, higher-level overview, see README. + . + For any copyright year range specified as YYYY-ZZZZ in this file, the + range specifies every single year in that closed interval. + +Files: * +Copyright: 1999-2010, 2012-2018 Russ Allbery + 2000 Joe Smith + 2016 Niko Tyni +License: Perl + This program is free software; you may redistribute it and/or modify it + under the same terms as Perl itself. This means that you may choose + between the two licenses that Perl is released under: the GNU GPL and the + Artistic License. Please see your Perl distribution for the details and + copies of the licenses. + +Files: pod/perlpodstyle.pod t/data/basic.cap t/data/basic.clr + t/data/basic.man t/data/basic.ovr t/data/basic.pod t/data/basic.txt + t/data/snippets/README +Copyright: 1999-2001, 2004, 2006, 2008, 2010, 2015-2016, 2018 + Russ Allbery +License: all-permissive + Copying and distribution of this file, with or without modification, are + permitted in any medium without royalty provided the copyright notice and + this notice are preserved. This file is offered as-is, without any + warranty. + +Files: t/docs/pod-spelling.t t/docs/pod.t t/docs/spdx-license.t + t/docs/synopsis.t t/docs/urls.t t/lib/Test/RRA.pm t/lib/Test/RRA/Config.pm + t/lib/Test/RRA/ModuleVersion.pm t/style/minimum-version.t + t/style/module-version.t t/style/strict.t +Copyright: 2012-2014 + The Board of Trustees of the Leland Stanford Junior University + 2014-2016, 2018 Russ Allbery +License: Expat + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + . + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..2fbdc48 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,128 @@ +.gitignore +Changes +docs/metadata/blurb +docs/metadata/description +docs/metadata/metadata.json +docs/metadata/quote +docs/metadata/requirements +lib/Pod/Man.pm +lib/Pod/ParseLink.pm +lib/Pod/Text.pm +lib/Pod/Text/Color.pm +lib/Pod/Text/Overstrike.pm +lib/Pod/Text/Termcap.pm +LICENSE +Makefile.PL +MANIFEST This list of files +MANIFEST.SKIP +NOTES +pod/perlpodstyle.pod +README +README.md +scripts/pod2man.PL +scripts/pod2text.PL +t/data/basic.cap +t/data/basic.clr +t/data/basic.man +t/data/basic.ovr +t/data/basic.pod +t/data/basic.txt +t/data/perl.conf +t/data/snippets/color/escape-wrapping +t/data/snippets/color/tag-width +t/data/snippets/color/tag-wrapping +t/data/snippets/color/width +t/data/snippets/color/wrapping +t/data/snippets/man/agrave +t/data/snippets/man/backslash-man-ref +t/data/snippets/man/bullet-after-nonbullet +t/data/snippets/man/bullets +t/data/snippets/man/c-in-header +t/data/snippets/man/c-in-name +t/data/snippets/man/cpp +t/data/snippets/man/dollar-magic +t/data/snippets/man/error-die +t/data/snippets/man/error-none +t/data/snippets/man/error-normal +t/data/snippets/man/error-pod +t/data/snippets/man/error-stderr +t/data/snippets/man/error-stderr-opt +t/data/snippets/man/eth +t/data/snippets/man/fixed-font +t/data/snippets/man/fixed-font-in-item +t/data/snippets/man/for-blocks +t/data/snippets/man/hyphen-in-s +t/data/snippets/man/iso-8859-1 +t/data/snippets/man/item-fonts +t/data/snippets/man/link-quoting +t/data/snippets/man/link-to-url +t/data/snippets/man/long-quote +t/data/snippets/man/lquote-and-quote +t/data/snippets/man/lquote-rquote +t/data/snippets/man/markup-in-name +t/data/snippets/man/multiline-x +t/data/snippets/man/name-guesswork +t/data/snippets/man/nested-lists +t/data/snippets/man/newlines-in-c +t/data/snippets/man/non-ascii +t/data/snippets/man/not-bullet +t/data/snippets/man/not-numbers +t/data/snippets/man/nourls +t/data/snippets/man/paired-quotes +t/data/snippets/man/periods +t/data/snippets/man/quote-escaping +t/data/snippets/man/rquote-none +t/data/snippets/man/small-caps-magic +t/data/snippets/man/soft-hyphens +t/data/snippets/man/trailing-space +t/data/snippets/man/true-false +t/data/snippets/man/uppercase-license +t/data/snippets/man/utf8-nonbreaking +t/data/snippets/man/utf8-verbatim +t/data/snippets/man/x-whitespace +t/data/snippets/man/x-whitespace-entry +t/data/snippets/README +t/data/snippets/termcap/escape-wrapping +t/data/snippets/termcap/tag-width +t/data/snippets/termcap/tag-wrapping +t/data/snippets/termcap/width +t/data/snippets/termcap/wrapping +t/data/snippets/text/cpp +t/data/termcap +t/docs/pod-spelling.t +t/docs/pod.t +t/docs/spdx-license.t +t/docs/synopsis.t +t/docs/urls.t +t/general/basic.t +t/general/filehandle.t +t/general/pod-parser.t +t/lib/Test/Podlators.pm +t/lib/Test/RRA.pm +t/lib/Test/RRA/Config.pm +t/lib/Test/RRA/ModuleVersion.pm +t/man/devise-date.t +t/man/devise-title.t +t/man/empty.t +t/man/heading.t +t/man/iso-8859-1.t +t/man/no-encode.t +t/man/snippets.t +t/man/utf8-io.t +t/parselink/basic.t +t/style/minimum-version.t +t/style/module-version.t +t/style/strict.t +t/text/basic.t +t/text/color.t +t/text/empty.t +t/text/encoding.t +t/text/options.t +t/text/overstrike.t +t/text/perlio.t +t/text/termcap.t +t/text/utf8.t +THANKS +TODO +META.yml Module YAML meta-data (added by MakeMaker) +META.json Module JSON meta-data (added by MakeMaker) diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP new file mode 100644 index 0000000..53ee9b9 --- /dev/null +++ b/MANIFEST.SKIP @@ -0,0 +1,41 @@ +# -*- conf -*- + +# Avoid version control files. +^\.git/ + +# Avoid generated build files. +^Makefile$ +\bblib/ +^pm_to_blib$ +^scripts/pod2man$ +^scripts/pod2text$ + +# Avoid temp and backup files. +~$ +\.old$ +\#$ +\b\.# +\.bak$ +\.tmp$ +\.# +\.rej$ + +# Avoid OS-specific files/dirs +# Mac OSX metadata +\B\.DS_Store +# Mac OSX SMB mount metadata files +\B\._ + +# Avoid Devel::Cover and Devel::CoverX::Covered files. +\bcover_db\b +\bcovered\b + +# Avoid MYMETA files +^MYMETA\. + +# Avoid archives of this distribution +\bpodlators-[\d\.\_]+ + +# CI configuration. Do not include in the distribution so that it doesn't +# make its way into Perl core. +^\.travis\.yml$ diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..a2008fe --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,187 @@ +# Build instructions for podlators. +# +# We need to use ExtUtils::MakeMaker since this module is part of Perl core, +# which only supports that build method, and because it is a dependency of +# other build systems like Module::Build. +# +# Copyright 1999-2001, 2008, 2010, 2012, 2014-2016, 2018 +# Russ Allbery +# +# This program is free software; you may redistribute it and/or modify it +# under the same terms as Perl itself. +# +# SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl + +use 5.006; +use strict; +use warnings; + +use Config; +use ExtUtils::MakeMaker; +use File::Spec; + +# Determine the version of the distribution so that we can construct the +# provides metadata that unfortunately ExtUtils::MakeMaker does not build. +# This is a very simple $VERSION parser, since it only has to handle the +# syntax Pod::Man uses. +# +# Returns: Distribution version as a string +sub dist_version { + open(my $fh, '<', File::Spec->catfile('lib', 'Pod', 'Man.pm')) + or die "$0: cannot open lib/Pod/Man.pm: $!\n"; + while (defined(my $line = <$fh>)) { + if ($line =~ m{ \A \$VERSION \s+ = \s+ '([^\']+)' }xms) { + close($fh) or die "$0: cannot close lib/Pod/Man.pm\n"; + return $1; + } + } + close($fh) or die "$0: cannot close lib/Pod/Man.pm\n"; + die "$0: cannot find version in lib/Pod/Man.pm\n"; +} + +# Generate full paths for scripts distributed in the bin directory. Appends +# the .com extension to scripts on VMS, unless they already have the .PL +# extension. +# +# @scripts - List of script names +# +# Returns: (Array) List of relative paths from top of distribution +# (Scalar) Space-separated relative paths from top of distribution +sub scripts { + my (@scripts) = @_; + my @paths = map { File::Spec->catfile('scripts', $_) } @scripts; + if ($^O eq 'VMS') { + @paths = map { m{ [.] PL \z }xms ? $_ : $_ . '.com' } @paths; + } + return wantarray ? @paths : join(q{ }, @paths); +} + +# Generate an association between a source file and a destination man page for +# non-module man pages. ExtUtils::MakeMaker only really understands how to +# generate man pages for modules, so we need to help it for the script man +# pages and (particularly) the perlpodstyle man page. +# +# $directory - Directory containing the file +# $file - File containing POD in that directory +# +# Returns: The path to the file with POD and the output man page, as a pair +sub man1pod { + my ($directory, $file) = @_; + + # Build the base name of the file by stripping any *.pod or *.PL suffix. + my $basename = $file; + $basename =~ s{ [.] (?: pod | PL ) \z }{}xms; + + # Determine the output file name for the generated man page. + my $outname = $basename . q{.} . $Config{man1ext}; + my $outpath = File::Spec->catfile(qw(blib man1), $outname); + return (File::Spec->catfile($directory, $file), $outpath); +} + +# The hash of all the metadata. This will be modified before WriteMakefile to +# remove keys not supported by the local version of ExtUtils::MakeMaker. +my $dist_version = dist_version(); +my %metadata = ( + NAME => 'Pod', + DISTNAME => 'podlators', + ABSTRACT => 'Convert POD data to various other formats', + AUTHOR => 'Russ Allbery ', + LICENSE => 'perl_5', + EXE_FILES => [scripts('pod2text', 'pod2man')], + VERSION_FROM => 'lib/Pod/Man.pm', + MIN_PERL_VERSION => '5.006', + + # Use *.PL files to generate the driver scripts so that we get the correct + # invocation of Perl on non-UNIX platforms. + PL_FILES => { + scripts('pod2man.PL', 'pod2man'), scripts('pod2text.PL', 'pod2text'), + }, + + # Override the files that generate section 1 man pages. + MAN1PODS => { + man1pod('scripts', 'pod2man.PL'), + man1pod('scripts', 'pod2text.PL'), + + # Perl core uses a separate copy in the top-level pod directory. + ($ENV{PERL_CORE} ? () : man1pod('pod', 'perlpodstyle.pod')), + }, + + # Clean some additional files. + clean => { FILES => File::Spec->catdir('t', 'tmp') }, + realclean => { FILES => scalar(scripts('pod2text', 'pod2man')) }, + + # Dependencies on other modules. + PREREQ_PM => { + 'Encode' => 0, + 'Pod::Simple' => 3.06, + }, + + # Older versions of ExtUtils::MakeMaker don't pick up nested test + # directories by default. + test => { TESTS => 't/*/*.t' }, + + # For older versions of Perl, we have to force installation into the Perl + # module directories since site modules did not take precedence over core + # modules. + INSTALLDIRS => $] lt '5.011' ? 'perl' : 'site', + + # Additional metadata. + META_ADD => { + 'meta-spec' => { version => 2 }, + provides => { + 'Pod::Man' => { + file => 'lib/Pod/Man.pm', + version => $dist_version, + }, + 'Pod::ParseLink' => { + file => 'lib/Pod/ParseLink.pm', + version => $dist_version, + }, + 'Pod::Text' => { + file => 'lib/Pod/Text.pm', + version => $dist_version, + }, + 'Pod::Text::Color' => { + file => 'lib/Pod/Text/Color.pm', + version => $dist_version, + }, + 'Pod::Text::Overstrike' => { + file => 'lib/Pod/Text/Overstrike.pm', + version => $dist_version, + }, + 'Pod::Text::Termcap' => { + file => 'lib/Pod/Text/Termcap.pm', + version => $dist_version, + }, + }, + resources => { + bugtracker => { + mailto => 'bug-podlators@rt.cpan.org', + web => 'https://rt.cpan.org/Dist/Display.html?Name=podlators', + }, + homepage => 'https://www.eyrie.org/~eagle/software/podlators/', + repository => { + url => 'https://github.com/rra/podlators.git', + web => 'https://github.com/rra/podlators', + type => 'git', + }, + }, + }, +); + +# Remove keys that aren't supported by this version of ExtUtils::MakeMaker. +# This hash maps keys to the minimum supported version. +my %supported = ( + LICENSE => 6.31, + META_ADD => 6.46, + MIN_PERL_VERSION => 6.48, +); +for my $key (keys(%supported)) { + if ($ExtUtils::MakeMaker::VERSION < $supported{$key}) { + delete $metadata{$key}; + } +} + +# Generate the actual Makefile. Pick an arbitrary module to pull the version +# from, since they should all have the same version. +WriteMakefile(%metadata); diff --git a/NOTES b/NOTES new file mode 100644 index 0000000..d567e23 --- /dev/null +++ b/NOTES @@ -0,0 +1,348 @@ +These are various mostly unorganized development notes related to things +that could later be done but haven't been done yet. + + ------------------------------ + +Jon Ericson sent the following two +patches for preliminary footnote support in Pod::Text and Pod::Man to +pod-people. The code isn't quite the approach that I'd use, but it would +be a good starting point if the decision is ever made to implement +footnote support. + +Here's his documentation followed by the patches. + +=head1 Footnotes + +Two POD elements are added to support footnotes: + +=over + +=item * + +CE> interior sequenceN> + +=item * + +C<=footnote> directiveN<1> + +=back + +=footnote 1 + +This method requires you to keep track of unique footnote IDs. It +allows multiple paragraphs,N<0> + + verbatim paragraphs, + +=begin text + +and *format* specific paragraphs. + +=end text + +=begin html + +

and format specific paragraphs.

+ +=end html + +=footnote 0 + +I suppose this is neither here nor there, but I'm not a fan of +multi-sentence (much less multi-paragraph) footnotes. If the +information is important, why not work it into the main text or put it +in the Appendix? If it isn't important, why include it at all? + +But some people seem to love them. They put stories, jokes, code +examples, detailed arguments, disclaimers, etc. in footnotes. As a +matter of principle, I wish they were disallowed in POD. +Unfortunately, it would then be impossible for Larry to write the next +I in standard POD!N embed footnotes in the +multi-paragraph style, but I don't think it should be supported.> + +=footnote + +The most common use of the footnote is for short parenthetical +statements: + + =head1 Why I love Perl.N + + [Insert reasons here] + +which gets formatted: + + Why I love Perl.[1] + + [Insert reasons here] + + ___ + 1 + www.perl.com + +For the vast majority of footnotes, this is all you need to know. The +pod2X translators take care of the details for putting footnotes in X. +pod2latex uses C<\footnote>, pod2html uses tags, pod2text puts +notes at the bottom of the document, etc. + +There is a limitation to the interior sequence version of +footnotes---they can't contain pod paragraphs.N<*> A general solution +for the problem would be to add a macro language to pod. I thought +that it would be overkill.N<**> Instead I added a footnote directive +that associates footnote text with a specific footnote mark. For +instance if you wanted to make the HTML footnote different from the +text version you could do something like: + + =head1 Why I love Perl.N<12> + + [Insert reasons here] + + =footnote 12 + + =for text + + www.perl.com + + =for html + + The Perl web-site. + + =footnote + +First place a mark with the C interior sequence. Pod translators +use the contents of the mark as a footnote ID which must match +C. Sometime after the mark is placed, use the footnote +directive to start the footnote section for that footnote ID. +Footnote sections are ended with another footnote directive. Note +that the footnote ID is only used to tie a specific footnote mark to +its text---the formatter is free to renumber (or re-mark) your +footnotes. + +=footnote ** + +Not to mention beyond my abilities to do right. :) + +=footnote * + +LaTeX doesn't allow C<\verb> within footnotes, at least not without an +optional package. (See +http://www.tex.ac.uk/cgi-bin/texfaq2html?keyword=footnote&question=143) + +=footnote 42 + +This is an orphaned footnote. It's just sort of stuck in here with a +footnote mark that doesn't go anywhere in the text. Does anyone know +where, if anywhere, it makes sense to put these? + +=cut + +--- /src/podlators-1.08/lib/Pod/Text.pm Sat Feb 10 06:50:23 2001 ++++ /src/podlators/lib/Pod/Text.pm Tue Mar 13 20:35:23 2001 +@@ -330,6 +330,7 @@ + elsif ($command eq 'F') { return $self->seq_f ($_) } + elsif ($command eq 'I') { return $self->seq_i ($_) } + elsif ($command eq 'L') { return $self->seq_l ($_) } ++ elsif ($command eq 'N') { return $self->seq_n ($_) } + else { carp "Unknown sequence $command<$_>" } + } + +@@ -461,6 +462,24 @@ + $self->verbatim ($_, $line); + } + ++sub cmd_footnote { ++ my $self = shift; ++ local $_ = shift; ++ s/\s+$//; ++ undef $$self{FOOTNOTE}, return unless length $_; ++ my $i = 0; ++ for my $note (@{$self->{NOTES}}) { ++ if ($note =~ /^[\d*]+$/) { ++ if ($note eq $_) { ++ $$self{FOOTNOTE} = $i; ++ $self->{NOTES}[$i] = ''; ++ return; ++ } ++ } ++ $i++; ++ } ++ $$self{FOOTNOTE} = $i; # orphan footnote case ++} + + ############################################################################ + # Interior sequences +@@ -526,6 +545,35 @@ + $text; + } + ++sub seq_n { ++ my $self = shift; ++ push @{$self->{NOTES}}, shift; ++ return '[' . @{$self->{NOTES}} . ']'; ++} ++ ++sub notes { ++ my $self = shift; ++ undef $$self{FOOTNOTE}; ++ if (defined $self->{NOTES}){ ++ $self->output('_' x 3 . "\n"); # "___\n" doesn't work ++ for my $note (0..$#{$self->{NOTES}}) { ++ $self->output ($note + 1 . "\n"); ++ for (split /\n\n/, $self->{NOTES}[$note]) { ++ if (/^\s/) { ++ $_ = "$_\n"; ++ } else { ++ $_ = $self->reformat("$_\n"); ++ } ++ $self->output ($_); ++ } ++ } ++ undef $self->{NOTES}; ++ } ++}; ++ ++sub end_input { ++ $_[0]->notes; ++} + + ############################################################################ + # List handling +@@ -615,7 +663,16 @@ + } + + # Output text to the output device. +-sub output { $_[1] =~ tr/\01/ /; print { $_[0]->output_handle } $_[1] } ++sub output { ++ my $self = shift; ++ local $_ = shift; ++ tr/\01/ /; ++ if (defined $$self{FOOTNOTE}) { ++ $self->{NOTES}[$$self{FOOTNOTE}] .= "$_\n"; ++ } else { ++ print { $self->output_handle } $_; ++ } ++} + + + ############################################################################ + + +--- /src/podlators-1.08/lib/Pod/Man.pm Sat Feb 10 06:50:22 2001 ++++ /src/podlators/lib/Pod/Man.pm Thu Mar 15 03:18:01 2001 +@@ -614,6 +614,12 @@ + # Add an index entry to the list of ones waiting to be output. + if ($command eq 'X') { push (@{ $$self{INDEX} }, $_); return '' } + ++ if ($command eq 'N') { ++ push @{ $$self{NOTES} }, $_; ++ return bless \ ('\u\f(BS' . @{ $$self{NOTES} } . '\f(BE\d'), ++ 'Pod::Man::String'; ++ } ++ + # Anything else is unknown. + carp "Unknown sequence $command<$_>"; + } +@@ -785,6 +791,22 @@ + $self->output ($_); + } + ++sub cmd_footnote { ++ my $self = shift; ++ local $_ = shift; ++ s/\s+$//; ++ undef $$self{FOOTNOTE}, return unless length $_; ++ my $i = 0; ++ for my $note (@{$self->{NOTES}}) { ++ if ($note eq $_) { ++ $$self{FOOTNOTE} = $i; ++ $self->{NOTES}[$i] = ''; ++ return; ++ } ++ $i++; ++ } ++ $$self{FOOTNOTE} = $i; # orphan footnote case ++} + + ############################################################################ + # Link handling +@@ -1067,7 +1089,35 @@ + } + + # Output text to the output device. +-sub output { print { $_[0]->output_handle } $_[1] } ++sub output { ++ my $self = shift; ++ local $_ = shift; ++ if (defined $$self{FOOTNOTE}) { ++ $self->{NOTES}[$$self{FOOTNOTE}] .= $_; ++ } else { ++ print { $self->output_handle } $_; ++ } ++} ++ ++sub notes { ++ my $self = shift; ++ undef $$self{FOOTNOTE}; ++ if (defined $self->{NOTES}){ ++ $self->makespace; ++ $self->output("___\n"); ++ for my $note (0..$#{$self->{NOTES}}) { ++ $self->makespace; ++ $self->output ("\n" . $note + 1 . "\n"); ++ $self->makespace; ++ $self->output ("$self->{NOTES}[$note]\n"); ++ } ++ undef $self->{NOTES}; ++ } ++}; ++ ++sub end_input { ++ $_[0]->notes; ++} + + # Given a command and a single argument that may or may not contain double + # quotes, handle double-quote formatting for it. If there are no double + + ------------------------------ + +The following extra bits of *roff were in the original pod2man. They're +not currently used, but I don't want to lose track of them in case they're +useful later. They're for accents and special characters that Pod::Man +currently doesn't have E<> escapes for. + +.if n \{\ +. ds ? ? +. ds ! ! +. ds q +.\} +.if t \{\ +. ds ? \s-2c\h'-\w'c'u*7/10'\u\h'\*(#H'\zi\d\s+2\h'\w'c'u*8/10' +. ds ! \s-2\(or\s+2\h'-\w'\(or'u'\v'-.8m'.\v'.8m' +. ds q o\h'-\w'o'u*8/10'\s-4\v'.4m'\z\(*i\v'-.4m'\s+4\h'\w'o'u*8/10' +.\} +.ds v \\k:\h'-(\\n(.wu*9/10-\*(#H)'\v'-\*(#V'\*(#[\s-4v\s0\v'\*(#V'\h'|\\n:u'\*( +#] +.ds _ \\k:\h'-(\\n(.wu*9/10-\*(#H+(\*(#F*2/3))'\v'-.4m'\z\(hy\v'.4m'\h'|\\n:u' +.ds . \\k:\h'-(\\n(.wu*8/10)'\v'\*(#V*4/10'\z.\v'-\*(#V*4/10'\h'|\\n:u' +.ds 3 \*(#[\v'.2m'\s-2\&3\s0\v'-.2m'\*(#] +.ds oe o\h'-(\w'o'u*4/10)'e +.ds Oe O\h'-(\w'O'u*4/10)'E +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds v \h'-1'\o'\(aa\(ga' +. ds _ \h'-1'^ +. ds . \h'-1'. +. ds 3 3 +. ds oe oe +. ds Oe OE +.\} + + ------------------------------ + +Copyright 2001, 2003, 2016, 2018 Russ Allbery + +This file is free software; you may redistribute it and/or modify it under +the same terms as Perl itself. + +SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl diff --git a/README b/README new file mode 100644 index 0000000..f4746db --- /dev/null +++ b/README @@ -0,0 +1,166 @@ + podlators 4.11 + (format POD source into various output formats) + Maintained by Russ Allbery + + Copyright 1999-2010, 2012-2018 Russ Allbery . This + software is distributed under the same terms as Perl itself. Please see + the section LICENSE below for more information. + +BLURB + + podlators contains Pod::Man and Pod::Text modules which convert POD + input to *roff source output, suitable for man pages, or plain text. It + also includes several subclasses of Pod::Text for formatted output to + terminals with various capabilities. It is the source package for the + Pod::Man and Pod::Text modules included with Perl. + +DESCRIPTION + + POD is the Plain Old Documentation format, the documentation language + used for all of Perl's documentation. I learned it to document Perl + modules, started using it for Perl scripts as well, and discovered it + was the most convenient way I've found to write program documentation. + It's extremely simple, well-designed for writing Unix manual pages (and + I'm a traditionalist who thinks that any program should have a regular + manual page), and easily readable in the raw format by humans. + + The translators into text and nroff (for manual pages) included in the + Perl distribution had various bugs, however, and used their own ad hoc + parsers, so when I started running into those bugs and when a new + generic parser (Pod::Parser) was written, I decided to rewrite the two + translators that I use the most and fix the bugs that were bothering me. + This package is the result. + + podlators contains two main modules, Pod::Man and Pod::Text. The former + converts POD into nroff/troff source and the latter into plain text + (with various options controlling some of the formatting). There are + also several subclasses of Pod::Text for generating slightly formatted + text using color or other terminal control escapes, and a general + utility module, Pod::ParseLink, for parsing the POD L<> formatting + sequences. Also included in this package are the pod2text and pod2man + driver scripts. + + Both Pod::Text and Pod::Man provide a variety of options for fine-tuning + their output. Pod::Man also tries to massage input text where + appropriate to produce better output when run through nroff or troff, + such as distinguishing between different types of hyphens and using + slightly smaller case for acronyms. + + As of Perl 5.6.0, my implementation was included in Perl core, and each + release of Perl will have the at-the-time most current version of + podlators included. You therefore only need to install this package + yourself if you have an old version of Perl or need a newer version than + came with Perl (to get some bug fixes, for example). + +REQUIREMENTS + + Perl 5.6.0 or later and Module::Build are required to build this module. + Both Pod::Man and Pod::Text are built on Pod::Simple, which handles the + basic POD parsing and character set conversion. Pod::Simple 3.06 or + later is required (and Pod::Simple 3.07 is recommended). It is + available from CPAN and part of Perl core as of 5.10.0. Encode is also + required (included in Perl core since 5.8.0). + + The troff/nroff generated by Pod::Man should be compatible with any + troff or nroff implementation with the -man macro set. It is primarily + tested by me under GNU groff, but Perl users send bug reports for a wide + variety of implementations and Pod::Man is used to generate all of + Perl's own manual pages, so most of the bugs have been weeded out. + + The test suite requires Test::More (part of Perl since 5.6.2). The + following additional Perl modules will be used by the test suite if + present: + + * Test::MinimumVersion + * Test::Pod + * Test::Spelling + * Test::Strict + * Test::Synopsis + + All are available on CPAN. Those tests will be skipped if the modules + are not available. + +BUILDING AND INSTALLATION + + podlators uses ExtUtils::MakeMaker and can be installed using the same + process as any other ExtUtils::MakeMaker module: + + perl Makefile.PL + make + make test + make install + + You'll probably need to do the last as root unless you're installing + into a local Perl module tree in your home directory. + + To enable tests that don't detect functionality problems but are used to + sanity-check the release, set the environment variable RELEASE_TESTING + to a true value. To enable tests that may be sensitive to the local + environment or that produce a lot of false positives without uncovering + many problems, set the environment variable AUTHOR_TESTING to a true + value. + +SUPPORT + + The podlators web page at: + + https://www.eyrie.org/~eagle/software/podlators/ + + will always have the current version of this package, the current + documentation, and pointers to any additional resources. + + For bug tracking, use the CPAN bug tracker at: + + https://rt.cpan.org/Dist/Display.html?Name=podlators + + However, please be aware that I tend to be extremely busy and work + projects often take priority. I'll save your report and get to it as + soon as I can, but it may take me a couple of months. + +SOURCE REPOSITORY + + podlators is maintained using Git. You can access the current source on + GitHub at: + + https://github.com/rra/podlators + + or by cloning the repository at: + + https://git.eyrie.org/git/perl/podlators.git + + or view the repository via the web at: + + https://git.eyrie.org/?p=perl/podlators.git + + The eyrie.org repository is the canonical one, maintained by the author, + but using GitHub is probably more convenient for most purposes. Pull + requests are gratefully reviewed and normally accepted. It's probably + better to use the CPAN bug tracker than GitHub issues, though, to keep + all Perl module issues in the same place. + +LICENSE + + The podlators package as a whole is covered by the following copyright + statement and license: + + Copyright 1999-2010, 2012-2018 Russ Allbery + + This program is free software; you may redistribute it and/or modify + it under the same terms as Perl itself. This means that you may + choose between the two licenses that Perl is released under: the GNU + GPL and the Artistic License. Please see your Perl distribution for + the details and copies of the licenses. + + Some files in this distribution are individually released under + different licenses, all of which are compatible with the above general + package license but which may require preservation of additional + notices. All required notices, and detailed information about the + licensing of each file, are recorded in the LICENSE file. + + Files covered by a license with an assigned SPDX License Identifier + include SPDX-License-Identifier tags to enable automated processing of + license information. See https://spdx.org/licenses/ for more + information. + + For any copyright range specified by files in this package as YYYY-ZZZZ, + the range specifies every single year in that closed interval. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0b41605 --- /dev/null +++ b/README.md @@ -0,0 +1,162 @@ +# podlators 4.11 + +[![Build +status](https://travis-ci.org/rra/podlators.svg?branch=master)](https://travis-ci.org/rra/podlators) +[![CPAN +version](https://img.shields.io/cpan/v/podlators.svg)](https://metacpan.org/release/podlators) + +Copyright 1999-2010, 2012-2018 Russ Allbery . This software +is distributed under the same terms as Perl itself. Please see the +section [License](#license) below for more information. + +## Blurb + +podlators contains Pod::Man and Pod::Text modules which convert POD input +to *roff source output, suitable for man pages, or plain text. It also +includes several subclasses of Pod::Text for formatted output to terminals +with various capabilities. It is the source package for the Pod::Man and +Pod::Text modules included with Perl. + +## Description + +POD is the Plain Old Documentation format, the documentation language used +for all of Perl's documentation. I learned it to document Perl modules, +started using it for Perl scripts as well, and discovered it was the most +convenient way I've found to write program documentation. It's extremely +simple, well-designed for writing Unix manual pages (and I'm a +traditionalist who thinks that any program should have a regular manual +page), and easily readable in the raw format by humans. + +The translators into text and nroff (for manual pages) included in the +Perl distribution had various bugs, however, and used their own ad hoc +parsers, so when I started running into those bugs and when a new generic +parser (Pod::Parser) was written, I decided to rewrite the two translators +that I use the most and fix the bugs that were bothering me. This package +is the result. + +podlators contains two main modules, Pod::Man and Pod::Text. The former +converts POD into nroff/troff source and the latter into plain text (with +various options controlling some of the formatting). There are also +several subclasses of Pod::Text for generating slightly formatted text +using color or other terminal control escapes, and a general utility +module, Pod::ParseLink, for parsing the POD `L<>` formatting sequences. +Also included in this package are the `pod2text` and `pod2man` driver +scripts. + +Both Pod::Text and Pod::Man provide a variety of options for fine-tuning +their output. Pod::Man also tries to massage input text where appropriate +to produce better output when run through nroff or troff, such as +distinguishing between different types of hyphens and using slightly +smaller case for acronyms. + +As of Perl 5.6.0, my implementation was included in Perl core, and each +release of Perl will have the at-the-time most current version of +podlators included. You therefore only need to install this package +yourself if you have an old version of Perl or need a newer version than +came with Perl (to get some bug fixes, for example). + +## Requirements + +Perl 5.6.0 or later and Module::Build are required to build this module. +Both Pod::Man and Pod::Text are built on Pod::Simple, which handles the +basic POD parsing and character set conversion. Pod::Simple 3.06 or later +is required (and Pod::Simple 3.07 is recommended). It is available from +CPAN and part of Perl core as of 5.10.0. Encode is also required +(included in Perl core since 5.8.0). + +The troff/nroff generated by Pod::Man should be compatible with any troff +or nroff implementation with the `-man` macro set. It is primarily tested +by me under GNU groff, but Perl users send bug reports for a wide variety +of implementations and Pod::Man is used to generate all of Perl's own +manual pages, so most of the bugs have been weeded out. + +The test suite requires Test::More (part of Perl since 5.6.2). The +following additional Perl modules will be used by the test suite if +present: + +* Test::MinimumVersion +* Test::Pod +* Test::Spelling +* Test::Strict +* Test::Synopsis + +All are available on CPAN. Those tests will be skipped if the modules are +not available. + +## Building and Installation + +podlators uses ExtUtils::MakeMaker and can be installed using the same +process as any other ExtUtils::MakeMaker module: + +``` + perl Makefile.PL + make + make test + make install +``` + +You'll probably need to do the last as root unless you're installing into +a local Perl module tree in your home directory. + +To enable tests that don't detect functionality problems but are used to +sanity-check the release, set the environment variable `RELEASE_TESTING` +to a true value. To enable tests that may be sensitive to the local +environment or that produce a lot of false positives without uncovering +many problems, set the environment variable `AUTHOR_TESTING` to a true +value. + +## Support + +The [podlators web page](https://www.eyrie.org/~eagle/software/podlators/) +will always have the current version of this package, the current +documentation, and pointers to any additional resources. + +For bug tracking, use the [CPAN bug +tracker](https://rt.cpan.org/Dist/Display.html?Name=podlators). However, +please be aware that I tend to be extremely busy and work projects often +take priority. I'll save your report and get to it as soon as I can, but +it may take me a couple of months. + +## Source Repository + +podlators is maintained using Git. You can access the current source on +[GitHub](https://github.com/rra/podlators) or by cloning the repository +at: + +https://git.eyrie.org/git/perl/podlators.git + +or [view the repository on the +web](https://git.eyrie.org/?p=perl/podlators.git). + +The eyrie.org repository is the canonical one, maintained by the author, +but using GitHub is probably more convenient for most purposes. Pull +requests are gratefully reviewed and normally accepted. It's probably +better to use the CPAN bug tracker than GitHub issues, though, to keep all +Perl module issues in the same place. + +## License + +The podlators package as a whole is covered by the following copyright +statement and license: + +> Copyright 1999-2010, 2012-2018 +> Russ Allbery +> +> This program is free software; you may redistribute it and/or modify it +> under the same terms as Perl itself. This means that you may choose +> between the two licenses that Perl is released under: the GNU GPL and the +> Artistic License. Please see your Perl distribution for the details and +> copies of the licenses. + +Some files in this distribution are individually released under different +licenses, all of which are compatible with the above general package +license but which may require preservation of additional notices. All +required notices, and detailed information about the licensing of each +file, are recorded in the LICENSE file. + +Files covered by a license with an assigned SPDX License Identifier +include SPDX-License-Identifier tags to enable automated processing of +license information. See https://spdx.org/licenses/ for more information. + +For any copyright range specified by files in this package as YYYY-ZZZZ, +the range specifies every single year in that closed interval. diff --git a/THANKS b/THANKS new file mode 100644 index 0000000..2a2841d --- /dev/null +++ b/THANKS @@ -0,0 +1,217 @@ + podlators Thanks + +Thanks to all of the following people for helping with the development of +these modules. + +Tom Christiansen, for writing the original Pod::Text and pod2man. These +modules are based very heavily on those, particularly the termcap handling +and pretty much all of Pod::Man. + +Brad Appleton, for writing Pod::Parser, which made writing Pod::Text the +work of a single Saturday and Pod::Man the work of another single +Saturday, and for finding lots of bugs in the first try. + +Sean Burke, for writing up a detailed specification of the POD language +that cleaned up a lot of edge cases and for his patience in explaining and +defending the decisions of that specification. Thanks also for writing +detailed instructions on how to parse L<> codes that I just implemented +nearly verbatim for Pod::ParseLink. Sean also contributed the initial +port of Pod::Man to Pod::Simple, so much of the current Pod::Man code is +heavily based on his work. + +Gurusamy Sarathy, for pointing out the need for a pod2text() compatibility +interface for older applications, and for being willing to roll this code +into the Perl core distribution. + +Larry Virden, for feedback on the section on writing a man page in +pod2roff and lots of good suggestions for improving it. + +Michael Schwern, for pointing out that pod2text() needs to be exported for +backwards compatibility and for pointing out a bug in the collapsing of +adjacent L links in Pod::Man. + +Marek Rochal, for pointing out a bug in handling of Z<> in Pod::Man, that +even periods preceded by font escapes need protection at the beginning of +lines from *roff, and that the handling of =item text with embedded +newlines was buggy in a previous version of Pod::Man. Thanks also for +finding a bug with C<> in headings confusing nroff. + +Tim Jenness, for providing the remaining ISO 8859-1 escapes for Pod::Text. +Volunteers to implement the same for Pod::Man are welcome. + +Johan Vromans, for pointing out a bug in the filename parsing in Pod::Man +and help with various packaging problems. + +Abigail, for better error handling code for unknown command paragraphs. + +Zack Weinberg, for suggesting the right *roff magic to prevent blank lines +between consecutive =item tags in lists and for explaining \fP and how to +prevent escapes like C<> from breaking the font in headings. + +Nicholas Clark, for the original patch to pod2man to allow it to process +multiple files with one invocation and for the analysis of problems with F +register handling with roffitall. + +Joe Smith, for Pod::Text::Overstrike. + +Robin Barker, for finding problems with multiline =head* headings and +input filenames containing spaces. + +Brendan O'Dea and Robin Barker (again!), for finding problems with +Pod::Man guesswork and function and man page references that contained +words in all caps and proposing fixes. + +Barrie Slaymaker, for the initial version of the heuristics in Pod::Man +and Pod::Text used to decide whether to add quotes around the argument of +C<>. + +Colin Watson, for finally pointing me in the right direction to find the +problem with excessive double-quoting of text in =item's on some platforms +and see how to fix it, and also for finding a problem with Pod::Man's +output of section headings for troff. + +Jarkko Hietaniemi, for the original language for pod2man.PL explaining the +COPYRIGHT AND LICENSE section, the modifications to the test suite needed +to run it as part of Perl's core tests, and testing and bug reports for +OS/390 and EBCDIC. + +Peter Prymmer, for pointing out the error reporting in Pod::Text and +Pod::Man didn't include enough information to find the errant POD. + +Michael Schwern, for the initial patch to support --code in pod2text, the +patch for --verbose in pod2man, finding a problem with the handling of +X<>, and diagnosing a problem with the pod2text() backward compatibility +function.. + +Kurt Hirchert, for pointing out that the path mangling used to derive the +man page name should only be done for section three manual pages, and for +suggesting a --name option for pod2man. + +Mike Fry, for pointing out that the intuiting of the manual page name from +the directory path didn't deal with three-component version numbers, +serving as the impetus to rewrite that code to use File::Spec, and finding +another bug with the module name intuition on OS/2. + +Craig A. Berry, for reporting that POSIX::Termios doesn't work on VMS and +providing the information necessary to add a workaround in +Pod::Text::Termcap, and for lots of help with build system changes for the +merge with Perl core. + +Autrijus Tang, for finding a bug in error reporting in Pod::Text and +providing a couple of test cases that became the beginning of the error +test suite. + +Marcus Shawcroft, for suggesting that guesswork not be applied to the +NAME section since that text is frequently pulled out by tools like +catman that don't understand *roff. + +Hugo van der Sanden, for reporting that the anti-quoting regexes thought +that a period was a number. + +Martin Quinson, for finding a bug in the handling of =item 0. + +Allison Randal, for taking over maintainership of Pod::Simple and +providing a fix for reusing the same formatting object for multiple +pages. + +Sergey Skvortsov, for a patch for compatibility with Perl 5.005. + +Yitzchak Scott-Thoennes, for diagnosing and providing patches for a few +incompatibilities with the Pod::Simple calling syntax, pointing out that +Pod::Simple didn't provide parse_from_filehandle, and pointing out the +initial hash of options that parse_from_file and parse_from_filehandle +accepted with Pod::Parser. + +Ron Savage, for pointing out a problematic regular expression construct in +Pod::Text::Termcap and Pod::Text::Color that broke in older versions of +Perl. + +Steve Peters, for ongoing work integrating into Perl core and reporting +problems that crop up when that is done. + +Jerry D. Hedden, for finding a test suite problem on Windows with +Pod::Simple 3.04. + +Craig A. Berry, for pointing out a bug in the Pod::Man devise_title logic +that may cause it to look past the end of the path array and produce Perl +warnings. + +Brendan O'Dea, for the initial patch to escape apostrophes in C<> and +verbatim text so that they won't be converted to Unicode single quotes and +the preamble magic to work with non-groff formatters. + +Colin Watson, for the preamble change to define the IX macro to an empty +macro when indexing is not requested, thus suppressing groff warnings. + +Kevin Ryde, for diagnosing and providing a patch for the =head2 problem +with some *roff implementations "looking through" the font escapes at the +beginning of a line and still seeing *roff metacharacters, and for finding +and fixing an issue with X<> formatting codes containing newlines. + +Steve Peters, for finding a problem with font settings in headings with +multiple C<> formatting codes. + +H. Merijn Brand and Juerd Waalboer, for explaining the Unicode test suite +failures, PERL_UNICODE support, and the correct way to handle Unicode +input and output in Perl. This resolved several confusions, including a +bad assumption about how non-breaking spaces should be handled. + +Niko Tyni, for lots of helpful bug reports and testing in combination with +the Perl packages in Debian, for the proposal and implementation of +POD_MAN_DATE and SOURCE_DATE_EPOCH to support reproducible builds, and for +Pod::Man graceful fallback from a missing Encode module. + +Jerry D. Hedden, for spelling fixes and pointing out differences in +aspell's dictionary on different systems. + +Steve Hay, for a test suite bug fix on Windows. + +Renee Baecker, for a patch to fix indentation of verbatim paragraphs that +contain lines with only whitespace. + +John E. Malmberg, for pointing out problems with the test suite leaving +versions of temporary files behind on VMS. + +David Hull, for pointing out the problem with choosing whether an item tag +will fit in the margin of the paragraph in Pod::Text subclasses that add +zero-length formatting codes and providing a patch to fix the problem. + +Bjarni Ingi Gislason, for help in suppressing groff warnings from +undefined strings and numeric registers. + +James E. Keenan, for reporting an issue with formatting L<> links +containing only URLs when the URL receives some formatting (such as +escaping of hyphens). + +Brian Gottreu, for fixing excessively long lines across all of the Perl +core documentation, including perlpodstyle. + +Andreas Koenig, for discovering an error in handling otherwise empty +documents that have POD syntax errors and a POD ERRORS section. + +Dagfinn Ilmari Mannsåker, for multiple performance optimizations after +profiling all of the modules in Perl core. + +Peter Rabbitson, for lots of assistance in getting the right build +configuration for a dual-life module included in Perl core, including +correct installation with old versions of Perl. + +Dave Mitchell, for a bug fix for warnings when determining the man page +title of a simple module and for how best to suppress Encode warnings +during Perl core builds. + +Guillem Jover, for the formatting change for man page references and +function names to match the Linux man page standard, and reporting a +diagnostic bug when pod2man or pod2text gets empty input on standard +input. + +Zefram, for analyzing and fixing a problem with the UTF-8 layer detection +code in Pod::Man. + +eponymous alias, for finding a bug in honoring the width option in +Pod::Text::Termcap and a bug in the Pod::Text sentence option +documentation. + +Olly Betts, for fixing errors=none behavior to fully suppress the POD +errata section, even with unusual errors that still trigger with no +whining set. diff --git a/TODO b/TODO new file mode 100644 index 0000000..4e96681 --- /dev/null +++ b/TODO @@ -0,0 +1,120 @@ + podlators To-Do List + +This is a somewhat random and unordered list of things I'd like to see +fixed or improved, but which I've not yet had a chance to do. Patches for +any of the following are very much welcome. + + * Revisit the handling of non-ASCII characters. At this point, it + probably makes sense to output UTF-8 by default, which also eliminates + all of the frustrations in Pod::Man with turning valid characters into + X and would allow massive simplification of the preamble for most + pages. We could also move some of the remaining *roff macros to the + accents section and only conditionally output them. Unfortunately, it + looks like all non-man-db, non-groff *roff implementations still don't + support Unicode characters, though, and even some groff setups may not + support them properly. So this is still a portability issue. + + * Support an output mode that uses groff escapes for all Unicode + characters. We might be able to just use \[uNNNN] for all Unicode + code points. This would work portably on any system that uses groff, + and may make sense as the default output format on Linux. + + * Escape all hyphens in the text of L links. + + * Add a =for license stanza that takes license text and embeds it as a + *roff comment. + + * Abstract the shared code between Pod::Man and Pod::Text to a new + Pod::Simple inheritance layer that both modules can use. + + * Suppress the URL for L<|> if the link is just the anchor part of the + tag with mailto: added to the front. Also strip the mailto: part if + there is no anchor text. + + * Add a test suite for the pod2man and pod2text driver programs. + + * There should be some way to turn off all heuristics when people are + using POD for some purpose other than Perl or some other programming + language with similar needs. The hooks are there in the code but we + need an interface to set or unset them. + + * The test suite is still fairly basic, and doesn't test all of the + options to the various modules, the scripts, =over/=back, or the + guesswork in Pod::Man. The best way forward would be to add coverage + testing and then aim for 100% coverage. That won't guarantee + everything is tested, but it will be much closer. + + * Pod::Text::Termcap can leave underlining turned on across a newline, + resulting in weird visual artifacts. Ideally, underlining should be + turned off at the end of each line, if still on, and then turned back + on at the start of the subsequent line. + + * Update coding style to my current standards. + + * Abstract the commonalities between the various test programs into a + generic driver for testing POD formatters, and then use it to handle + all of the test cases. (This is mostly done, but the Pod::Text tests + still have to be converted.) + + * Document all the standard module interfaces from Pod::Simple. + + * Optionally suppress the generation of empty man pages in Pod::Man. + +The following items require changes to the POD specification and are +therefore of broader scope than just this code: + + * Introduce a new interior sequence for metasyntactic variables, probably + M<>, and reserve I<> exclusively for emphasis. This resolves a + significant ambiguity in the current POD specification in a way that + would make the Pod::Text output much better. (Metasyntactic variables + should be surrounded in angle brackets and emphasized text should be + surrounded by asterisks.) + + * Introduce a new interior sequence for footnotes. There has been + extensive discussion of this on pod-people@perl.org. One proposal is + to use a new formatting code for footnotes, probably N<>, and just + in-line the footnote as part of the interior sequence. This doesn't + allow multi-paragraph footnotes, however, so a second proposal is to + have the content of the N<> formatting code be a unique marker that + matches an =item tag in a new =begin footnotes section processed by + translators that know how to do footnotes. (The translator should + probably number the footnotes and insert some sort of numerical marker + into the text at the point of the footnote.) This would require + translators to formatting languages that do something more interesting + with footnotes to parse the entire document, extract the footnote + section, and then stick the footnotes back into the main text at the + point where they occur, however. + + There are some preliminary patches for Pod::Man and Pod::Text in NOTES. + It's possible to do footnotes directly in *roff (it's section T4 of the + troff paper), but that relies on header and footer triggers and for + terminal display it's becoming common to suppress the headers and + footers. For the purposes of Pod::Man, end notes are probably a better + model and can be handled about the same way as they are for Pod::Text. + +The following ideas about guesswork and heuristics were all taken from a +post by Tom Christiansen to pod-people@perl.org: + + * All of the following should be okay to use verbatim in any POD text and + have the translator do something appropriate: + + FILEHANDLE PackageName + $variable @variable %variable &function + $var::iable @vari::able %variab::le &functio::n + function() fun::ction() fun::ct::ion() + manpage(3r) + user@host.com + http://somewhere.com/stuff/ ftp://somewhere.com/stuff/ + + Pod::Man and Pod::Text handle much of this already, but not all of it + (and I've not checked to see exactly where they break). + + * Something in __ALLCAPS__ should be in code font but perhaps not small, + and maybe some magic between the unders, as in \f(CW_\|_ALLCAPS_\|_\fP. + (Pod::Man handles the spaces between the underbars, but not putting + this into code font.) + + * The module version number should be included in the headers/footers + where appropriate. That means that, when processing a module, ideally + one wants to pull out the module's $VERSION to use in the footer rather + than Perl's version. diff --git a/docs/metadata/blurb b/docs/metadata/blurb new file mode 100644 index 0000000..a7f64e7 --- /dev/null +++ b/docs/metadata/blurb @@ -0,0 +1,5 @@ +podlators contains Pod::Man and Pod::Text modules which convert POD input +to *roff source output, suitable for man pages, or plain text. It also +includes several subclasses of Pod::Text for formatted output to terminals +with various capabilities. It is the source package for the Pod::Man and +Pod::Text modules included with Perl. diff --git a/docs/metadata/description b/docs/metadata/description new file mode 100644 index 0000000..08a4481 --- /dev/null +++ b/docs/metadata/description @@ -0,0 +1,35 @@ +POD is the Plain Old Documentation format, the documentation language used +for all of Perl's documentation. I learned it to document Perl modules, +started using it for Perl scripts as well, and discovered it was the most +convenient way I've found to write program documentation. It's extremely +simple, well-designed for writing Unix manual pages (and I'm a +traditionalist who thinks that any program should have a regular manual +page), and easily readable in the raw format by humans. + +The translators into text and nroff (for manual pages) included in the +Perl distribution had various bugs, however, and used their own ad hoc +parsers, so when I started running into those bugs and when a new generic +parser (Pod::Parser) was written, I decided to rewrite the two translators +that I use the most and fix the bugs that were bothering me. This package +is the result. + +podlators contains two main modules, Pod::Man and Pod::Text. The former +converts POD into nroff/troff source and the latter into plain text (with +various options controlling some of the formatting). There are also +several subclasses of Pod::Text for generating slightly formatted text +using color or other terminal control escapes, and a general utility +module, Pod::ParseLink, for parsing the POD `L<>` formatting sequences. +Also included in this package are the `pod2text` and `pod2man` driver +scripts. + +Both Pod::Text and Pod::Man provide a variety of options for fine-tuning +their output. Pod::Man also tries to massage input text where appropriate +to produce better output when run through nroff or troff, such as +distinguishing between different types of hyphens and using slightly +smaller case for acronyms. + +As of Perl 5.6.0, my implementation was included in Perl core, and each +release of Perl will have the at-the-time most current version of +podlators included. You therefore only need to install this package +yourself if you have an old version of Perl or need a newer version than +came with Perl (to get some bug fixes, for example). diff --git a/docs/metadata/metadata.json b/docs/metadata/metadata.json new file mode 100644 index 0000000..aff880d --- /dev/null +++ b/docs/metadata/metadata.json @@ -0,0 +1,82 @@ +{ + "name": "podlators", + "version": "4.11", + "synopsis": "format POD source into various output formats", + "maintainer": "Russ Allbery ", + "copyrights": [ + { + "holder": "Russ Allbery ", + "years": "1999-2010, 2012-2018", + }, + ], + "license": "Perl", + "build": { + "lancaster": true, + "type": "ExtUtils::MakeMaker", + }, + "support": { + "cpan": "podlators", + "email": "rra@cpan.org", + "web": "https://www.eyrie.org/~eagle/software/podlators/", + }, + "vcs": { + "type": "Git", + "url": "https://git.eyrie.org/git/perl/podlators.git", + "browse": "https://git.eyrie.org/?p=perl/podlators.git", + "github": "rra/podlators", + "openhub": "https://www.openhub.net/p/podlators", + "travis": "rra/podlators", + }, + "quote": { + "author": "Robert Fripp", + "work": "\"The Road to Graceland\"", + }, + "distribution": { + "section": "perl", + "tarname": "podlators", + "version": "podlators", + "cpan": "podlators", + }, + "docs": { + "user": [ + { + "name": "perlpodstyle", + "title": "POD style guide", + }, + { + "name": "pod2man", + "title": "pod2man documentation", + }, + { + "name": "pod2text", + "title": "pod2text documentation", + }, + { + "name": "thanks", + "title": "Thanks and credits", + }, + ], + "api": [ + { + "name": "pod-man", + "title": "Pod::Man", + }, + { + "name": "pod-text", + "title": "Pod::Text", + }, + { + "name": "pod-text-color", + "title": "Pod::Text::Color", + }, + { + "name": "pod-text-overstrike", + "title": "Pod::Text::Overstrike", + }, + { + "name": "pod-text-termcap", + "title": "Pod::Text::Termcap", + } + ], + }, +} diff --git a/docs/metadata/quote b/docs/metadata/quote new file mode 100644 index 0000000..8fcdfa5 --- /dev/null +++ b/docs/metadata/quote @@ -0,0 +1,3 @@ +We move from making unnecessary efforts, the exertions of force, to making +necessary efforts: the direction of effortlessness. In this the prime +maxim is: honor necessity, honor sufficiency. diff --git a/docs/metadata/requirements b/docs/metadata/requirements new file mode 100644 index 0000000..e57df58 --- /dev/null +++ b/docs/metadata/requirements @@ -0,0 +1,25 @@ +Perl 5.6.0 or later and Module::Build are required to build this module. +Both Pod::Man and Pod::Text are built on Pod::Simple, which handles the +basic POD parsing and character set conversion. Pod::Simple 3.06 or later +is required (and Pod::Simple 3.07 is recommended). It is available from +CPAN and part of Perl core as of 5.10.0. Encode is also required +(included in Perl core since 5.8.0). + +The troff/nroff generated by Pod::Man should be compatible with any troff +or nroff implementation with the `-man` macro set. It is primarily tested +by me under GNU groff, but Perl users send bug reports for a wide variety +of implementations and Pod::Man is used to generate all of Perl's own +manual pages, so most of the bugs have been weeded out. + +The test suite requires Test::More (part of Perl since 5.6.2). The +following additional Perl modules will be used by the test suite if +present: + +* Test::MinimumVersion +* Test::Pod +* Test::Spelling +* Test::Strict +* Test::Synopsis + +All are available on CPAN. Those tests will be skipped if the modules are +not available. diff --git a/lib/Pod/Man.pm b/lib/Pod/Man.pm new file mode 100644 index 0000000..6ebab1e --- /dev/null +++ b/lib/Pod/Man.pm @@ -0,0 +1,2045 @@ +# Convert POD data to formatted *roff input. +# +# This module translates POD documentation into *roff markup using the man +# macro set, and is intended for converting POD documents written as Unix +# manual pages to manual pages that can be read by the man(1) command. It is +# a replacement for the pod2man command distributed with versions of Perl +# prior to 5.6. +# +# SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl + +############################################################################## +# Modules and declarations +############################################################################## + +package Pod::Man; + +use 5.006; +use strict; +use warnings; + +use subs qw(makespace); +use vars qw(@ISA %ESCAPES $PREAMBLE $VERSION); + +use Carp qw(carp croak); +use Pod::Simple (); + +# Conditionally import Encode and set $HAS_ENCODE if it is available. +our $HAS_ENCODE; +BEGIN { + $HAS_ENCODE = eval { require Encode }; +} + +@ISA = qw(Pod::Simple); + +$VERSION = '4.11'; + +# Set the debugging level. If someone has inserted a debug function into this +# class already, use that. Otherwise, use any Pod::Simple debug function +# that's defined, and failing that, define a debug level of 10. +BEGIN { + my $parent = defined (&Pod::Simple::DEBUG) ? \&Pod::Simple::DEBUG : undef; + unless (defined &DEBUG) { + *DEBUG = $parent || sub () { 10 }; + } +} + +# Import the ASCII constant from Pod::Simple. This is true iff we're in an +# ASCII-based universe (including such things as ISO 8859-1 and UTF-8), and is +# generally only false for EBCDIC. +BEGIN { *ASCII = \&Pod::Simple::ASCII } + +# Pretty-print a data structure. Only used for debugging. +BEGIN { *pretty = \&Pod::Simple::pretty } + +# Formatting instructions for various types of blocks. cleanup makes hyphens +# hard, adds spaces between consecutive underscores, and escapes backslashes. +# convert translates characters into escapes. guesswork means to apply the +# transformations done by the guesswork sub. literal says to protect literal +# quotes from being turned into UTF-8 quotes. By default, all transformations +# are on except literal, but some elements override. +# +# DEFAULT specifies the default settings. All other elements should list only +# those settings that they are overriding. Data indicates =for roff blocks, +# which should be passed along completely verbatim. +# +# Formatting inherits negatively, in the sense that if the parent has turned +# off guesswork, all child elements should leave it off. +my %FORMATTING = ( + DEFAULT => { cleanup => 1, convert => 1, guesswork => 1, literal => 0 }, + Data => { cleanup => 0, convert => 0, guesswork => 0, literal => 0 }, + Verbatim => { guesswork => 0, literal => 1 }, + C => { guesswork => 0, literal => 1 }, + X => { cleanup => 0, guesswork => 0 }, +); + +############################################################################## +# Object initialization +############################################################################## + +# Initialize the object and set various Pod::Simple options that we need. +# Here, we also process any additional options passed to the constructor or +# set up defaults if none were given. Note that all internal object keys are +# in all-caps, reserving all lower-case object keys for Pod::Simple and user +# arguments. +sub new { + my $class = shift; + my $self = $class->SUPER::new; + + # Tell Pod::Simple not to handle S<> by automatically inserting  . + $self->nbsp_for_S (1); + + # Tell Pod::Simple to keep whitespace whenever possible. + if (my $preserve_whitespace = $self->can ('preserve_whitespace')) { + $self->$preserve_whitespace (1); + } else { + $self->fullstop_space_harden (1); + } + + # The =for and =begin targets that we accept. + $self->accept_targets (qw/man MAN roff ROFF/); + + # Ensure that contiguous blocks of code are merged together. Otherwise, + # some of the guesswork heuristics don't work right. + $self->merge_text (1); + + # Pod::Simple doesn't do anything useful with our arguments, but we want + # to put them in our object as hash keys and values. This could cause + # problems if we ever clash with Pod::Simple's own internal class + # variables. + %$self = (%$self, @_); + + # Send errors to stderr if requested. + if ($$self{stderr} and not $$self{errors}) { + $$self{errors} = 'stderr'; + } + delete $$self{stderr}; + + # Validate the errors parameter and act on it. + if (not defined $$self{errors}) { + $$self{errors} = 'pod'; + } + if ($$self{errors} eq 'stderr' || $$self{errors} eq 'die') { + $self->no_errata_section (1); + $self->complain_stderr (1); + if ($$self{errors} eq 'die') { + $$self{complain_die} = 1; + } + } elsif ($$self{errors} eq 'pod') { + $self->no_errata_section (0); + $self->complain_stderr (0); + } elsif ($$self{errors} eq 'none') { + $self->no_errata_section (1); + $self->no_whining (1); + } else { + croak (qq(Invalid errors setting: "$$self{errors}")); + } + delete $$self{errors}; + + # Degrade back to non-utf8 if Encode is not available. + # + # Suppress the warning message when PERL_CORE is set, indicating this is + # running as part of the core Perl build. Perl builds podlators (and all + # pure Perl modules) before Encode and other XS modules, so Encode won't + # yet be available. Rely on the Perl core build to generate man pages + # later, after all the modules are available, so that UTF-8 handling will + # be correct. + if ($$self{utf8} and !$HAS_ENCODE) { + if (!$ENV{PERL_CORE}) { + carp ('utf8 mode requested but Encode module not available,' + . ' falling back to non-utf8'); + } + delete $$self{utf8}; + } + + # Initialize various other internal constants based on our arguments. + $self->init_fonts; + $self->init_quotes; + $self->init_page; + + # For right now, default to turning on all of the magic. + $$self{MAGIC_CPP} = 1; + $$self{MAGIC_EMDASH} = 1; + $$self{MAGIC_FUNC} = 1; + $$self{MAGIC_MANREF} = 1; + $$self{MAGIC_SMALLCAPS} = 1; + $$self{MAGIC_VARS} = 1; + + return $self; +} + +# Translate a font string into an escape. +sub toescape { (length ($_[0]) > 1 ? '\f(' : '\f') . $_[0] } + +# Determine which fonts the user wishes to use and store them in the object. +# Regular, italic, bold, and bold-italic are constants, but the fixed width +# fonts may be set by the user. Sets the internal hash key FONTS which is +# used to map our internal font escapes to actual *roff sequences later. +sub init_fonts { + my ($self) = @_; + + # Figure out the fixed-width font. If user-supplied, make sure that they + # are the right length. + for (qw/fixed fixedbold fixeditalic fixedbolditalic/) { + my $font = $$self{$_}; + if (defined ($font) && (length ($font) < 1 || length ($font) > 2)) { + croak qq(roff font should be 1 or 2 chars, not "$font"); + } + } + + # Set the default fonts. We can't be sure portably across different + # implementations what fixed bold-italic may be called (if it's even + # available), so default to just bold. + $$self{fixed} ||= 'CW'; + $$self{fixedbold} ||= 'CB'; + $$self{fixeditalic} ||= 'CI'; + $$self{fixedbolditalic} ||= 'CB'; + + # Set up a table of font escapes. First number is fixed-width, second is + # bold, third is italic. + $$self{FONTS} = { '000' => '\fR', '001' => '\fI', + '010' => '\fB', '011' => '\f(BI', + '100' => toescape ($$self{fixed}), + '101' => toescape ($$self{fixeditalic}), + '110' => toescape ($$self{fixedbold}), + '111' => toescape ($$self{fixedbolditalic}) }; +} + +# Initialize the quotes that we'll be using for C<> text. This requires some +# special handling, both to parse the user parameters if given and to make +# sure that the quotes will be safe against *roff. Sets the internal hash +# keys LQUOTE and RQUOTE. +sub init_quotes { + my ($self) = (@_); + + # Handle the quotes option first, which sets both quotes at once. + $$self{quotes} ||= '"'; + if ($$self{quotes} eq 'none') { + $$self{LQUOTE} = $$self{RQUOTE} = ''; + } elsif (length ($$self{quotes}) == 1) { + $$self{LQUOTE} = $$self{RQUOTE} = $$self{quotes}; + } elsif (length ($$self{quotes}) % 2 == 0) { + my $length = length ($$self{quotes}) / 2; + $$self{LQUOTE} = substr ($$self{quotes}, 0, $length); + $$self{RQUOTE} = substr ($$self{quotes}, $length); + } else { + croak(qq(Invalid quote specification "$$self{quotes}")) + } + + # Now handle the lquote and rquote options. + if (defined $$self{lquote}) { + $$self{LQUOTE} = $$self{lquote} eq 'none' ? q{} : $$self{lquote}; + } + if (defined $$self{rquote}) { + $$self{RQUOTE} = $$self{rquote} eq 'none' ? q{} : $$self{rquote}; + } + + # Double the first quote; note that this should not be s///g as two double + # quotes is represented in *roff as three double quotes, not four. Weird, + # I know. + $$self{LQUOTE} =~ s/\"/\"\"/; + $$self{RQUOTE} =~ s/\"/\"\"/; +} + +# Initialize the page title information and indentation from our arguments. +sub init_page { + my ($self) = @_; + + # We used to try first to get the version number from a local binary, but + # we shouldn't need that any more. Get the version from the running Perl. + # Work a little magic to handle subversions correctly under both the + # pre-5.6 and the post-5.6 version numbering schemes. + my @version = ($] =~ /^(\d+)\.(\d{3})(\d{0,3})$/); + $version[2] ||= 0; + $version[2] *= 10 ** (3 - length $version[2]); + for (@version) { $_ += 0 } + my $version = join ('.', @version); + + # Set the defaults for page titles and indentation if the user didn't + # override anything. + $$self{center} = 'User Contributed Perl Documentation' + unless defined $$self{center}; + $$self{release} = 'perl v' . $version + unless defined $$self{release}; + $$self{indent} = 4 + unless defined $$self{indent}; + + # Double quotes in things that will be quoted. + for (qw/center release/) { + $$self{$_} =~ s/\"/\"\"/g if $$self{$_}; + } +} + +############################################################################## +# Core parsing +############################################################################## + +# This is the glue that connects the code below with Pod::Simple itself. The +# goal is to convert the event stream coming from the POD parser into method +# calls to handlers once the complete content of a tag has been seen. Each +# paragraph or POD command will have textual content associated with it, and +# as soon as all of a paragraph or POD command has been seen, that content +# will be passed in to the corresponding method for handling that type of +# object. The exceptions are handlers for lists, which have opening tag +# handlers and closing tag handlers that will be called right away. +# +# The internal hash key PENDING is used to store the contents of a tag until +# all of it has been seen. It holds a stack of open tags, each one +# represented by a tuple of the attributes hash for the tag, formatting +# options for the tag (which are inherited), and the contents of the tag. + +# Add a block of text to the contents of the current node, formatting it +# according to the current formatting instructions as we do. +sub _handle_text { + my ($self, $text) = @_; + DEBUG > 3 and print "== $text\n"; + my $tag = $$self{PENDING}[-1]; + $$tag[2] .= $self->format_text ($$tag[1], $text); +} + +# Given an element name, get the corresponding method name. +sub method_for_element { + my ($self, $element) = @_; + $element =~ tr/A-Z-/a-z_/; + $element =~ tr/_a-z0-9//cd; + return $element; +} + +# Handle the start of a new element. If cmd_element is defined, assume that +# we need to collect the entire tree for this element before passing it to the +# element method, and create a new tree into which we'll collect blocks of +# text and nested elements. Otherwise, if start_element is defined, call it. +sub _handle_element_start { + my ($self, $element, $attrs) = @_; + DEBUG > 3 and print "++ $element (<", join ('> <', %$attrs), ">)\n"; + my $method = $self->method_for_element ($element); + + # If we have a command handler, we need to accumulate the contents of the + # tag before calling it. Turn off IN_NAME for any command other than + # and the formatting codes so that IN_NAME isn't still set for the + # first heading after the NAME heading. + if ($self->can ("cmd_$method")) { + DEBUG > 2 and print "<$element> starts saving a tag\n"; + $$self{IN_NAME} = 0 if ($element ne 'Para' && length ($element) > 1); + + # How we're going to format embedded text blocks depends on the tag + # and also depends on our parent tags. Thankfully, inside tags that + # turn off guesswork and reformatting, nothing else can turn it back + # on, so this can be strictly inherited. + my $formatting = { + %{ $$self{PENDING}[-1][1] || $FORMATTING{DEFAULT} }, + %{ $FORMATTING{$element} || {} }, + }; + push (@{ $$self{PENDING} }, [ $attrs, $formatting, '' ]); + DEBUG > 4 and print "Pending: [", pretty ($$self{PENDING}), "]\n"; + } elsif (my $start_method = $self->can ("start_$method")) { + $self->$start_method ($attrs, ''); + } else { + DEBUG > 2 and print "No $method start method, skipping\n"; + } +} + +# Handle the end of an element. If we had a cmd_ method for this element, +# this is where we pass along the tree that we built. Otherwise, if we have +# an end_ method for the element, call that. +sub _handle_element_end { + my ($self, $element) = @_; + DEBUG > 3 and print "-- $element\n"; + my $method = $self->method_for_element ($element); + + # If we have a command handler, pull off the pending text and pass it to + # the handler along with the saved attribute hash. + if (my $cmd_method = $self->can ("cmd_$method")) { + DEBUG > 2 and print " stops saving a tag\n"; + my $tag = pop @{ $$self{PENDING} }; + DEBUG > 4 and print "Popped: [", pretty ($tag), "]\n"; + DEBUG > 4 and print "Pending: [", pretty ($$self{PENDING}), "]\n"; + my $text = $self->$cmd_method ($$tag[0], $$tag[2]); + if (defined $text) { + if (@{ $$self{PENDING} } > 1) { + $$self{PENDING}[-1][2] .= $text; + } else { + $self->output ($text); + } + } + } elsif (my $end_method = $self->can ("end_$method")) { + $self->$end_method (); + } else { + DEBUG > 2 and print "No $method end method, skipping\n"; + } +} + +############################################################################## +# General formatting +############################################################################## + +# Format a text block. Takes a hash of formatting options and the text to +# format. Currently, the only formatting options are guesswork, cleanup, and +# convert, all of which are boolean. +sub format_text { + my ($self, $options, $text) = @_; + my $guesswork = $$options{guesswork} && !$$self{IN_NAME}; + my $cleanup = $$options{cleanup}; + my $convert = $$options{convert}; + my $literal = $$options{literal}; + + # Cleanup just tidies up a few things, telling *roff that the hyphens are + # hard, putting a bit of space between consecutive underscores, and + # escaping backslashes. Be careful not to mangle our character + # translations by doing this before processing character translation. + if ($cleanup) { + $text =~ s/\\/\\e/g; + $text =~ s/-/\\-/g; + $text =~ s/_(?=_)/_\\|/g; + } + + # Normally we do character translation, but we won't even do that in + # blocks or if UTF-8 output is desired. + if ($convert && !$$self{utf8} && ASCII) { + $text =~ s/([^\x00-\x7F])/$ESCAPES{ord ($1)} || "X"/eg; + } + + # Ensure that *roff doesn't convert literal quotes to UTF-8 single quotes, + # but don't mess up our accept escapes. + if ($literal) { + $text =~ s/(?guesswork ($text); + } + + return $text; +} + +# Handles C<> text, deciding whether to put \*C` around it or not. This is a +# whole bunch of messy heuristics to try to avoid overquoting, originally from +# Barrie Slaymaker. This largely duplicates similar code in Pod::Text. +sub quote_literal { + my $self = shift; + local $_ = shift; + + # A regex that matches the portion of a variable reference that's the + # array or hash index, separated out just because we want to use it in + # several places in the following regex. + my $index = '(?: \[.*\] | \{.*\} )?'; + + # If in NAME section, just return an ASCII quoted string to avoid + # confusing tools like whatis. + return qq{"$_"} if $$self{IN_NAME}; + + # Check for things that we don't want to quote, and if we find any of + # them, return the string with just a font change and no quoting. + m{ + ^\s* + (?: + ( [\'\`\"] ) .* \1 # already quoted + | \\\*\(Aq .* \\\*\(Aq # quoted and escaped + | \\?\` .* ( \' | \\\*\(Aq ) # `quoted' + | \$+ [\#^]? \S $index # special ($^Foo, $") + | [\$\@%&*]+ \#? [:\'\w]+ $index # plain var or func + | [\$\@%&*]* [:\'\w]+ (?: -> )? \(\s*[^\s,]\s*\) # 0/1-arg func call + | [-+]? ( \d[\d.]* | \.\d+ ) (?: [eE][-+]?\d+ )? # a number + | 0x [a-fA-F\d]+ # a hex constant + ) + \s*\z + }xso and return '\f(FS' . $_ . '\f(FE'; + + # If we didn't return, go ahead and quote the text. + return '\f(FS\*(C`' . $_ . "\\*(C'\\f(FE"; +} + +# Takes a text block to perform guesswork on. Returns the text block with +# formatting codes added. This is the code that marks up various Perl +# constructs and things commonly used in man pages without requiring the user +# to add any explicit markup, and is applied to all non-literal text. We're +# guaranteed that the text we're applying guesswork to does not contain any +# *roff formatting codes. Note that the inserted font sequences must be +# treated later with mapfonts or textmapfonts. +# +# This method is very fragile, both in the regular expressions it uses and in +# the ordering of those modifications. Care and testing is required when +# modifying it. +sub guesswork { + my $self = shift; + local $_ = shift; + DEBUG > 5 and print " Guesswork called on [$_]\n"; + + # By the time we reach this point, all hyphens will be escaped by adding a + # backslash. We want to undo that escaping if they're part of regular + # words and there's only a single dash, since that's a real hyphen that + # *roff gets to consider a possible break point. Make sure that a dash + # after the first character of a word stays non-breaking, however. + # + # Note that this is not user-controllable; we pretty much have to do this + # transformation or *roff will mangle the output in unacceptable ways. + s{ + ( (?:\G|^|\s) [\(\"]* [a-zA-Z] ) ( \\- )? + ( (?: [a-zA-Z\']+ \\-)+ ) + ( [a-zA-Z\']+ ) (?= [\)\".?!,;:]* (?:\s|\Z|\\\ ) ) + \b + } { + my ($prefix, $hyphen, $main, $suffix) = ($1, $2, $3, $4); + $hyphen ||= ''; + $main =~ s/\\-/-/g; + $prefix . $hyphen . $main . $suffix; + }egx; + + # Translate "--" into a real em-dash if it's used like one. This means + # that it's either surrounded by whitespace, it follows a regular word, or + # it occurs between two regular words. + if ($$self{MAGIC_EMDASH}) { + s{ (\s) \\-\\- (\s) } { $1 . '\*(--' . $2 }egx; + s{ (\b[a-zA-Z]+) \\-\\- (\s|\Z|[a-zA-Z]+\b) } { $1 . '\*(--' . $2 }egx; + } + + # Make words in all-caps a little bit smaller; they look better that way. + # However, we don't want to change Perl code (like @ARGV), nor do we want + # to fix the MIME in MIME-Version since it looks weird with the + # full-height V. + # + # We change only a string of all caps (2) either at the beginning of the + # line or following regular punctuation (like quotes) or whitespace (1), + # and followed by either similar punctuation, an em-dash, or the end of + # the line (3). + # + # Allow the text we're changing to small caps to include double quotes, + # commas, newlines, and periods as long as it doesn't otherwise interrupt + # the string of small caps and still fits the criteria. This lets us turn + # entire warranty disclaimers in man page output into small caps. + if ($$self{MAGIC_SMALLCAPS}) { + s{ + ( ^ | [\s\(\"\'\`\[\{<>] | \\[ ] ) # (1) + ( [A-Z] [A-Z] (?: \s? [/A-Z+:\d_\$&] | \\- | \s? [.,\"] )* ) # (2) + (?= [\s>\}\]\(\)\'\".?!,;] | \\*\(-- | \\[ ] | $ ) # (3) + } { + $1 . '\s-1' . $2 . '\s0' + }egx; + } + + # Note that from this point forward, we have to adjust for \s-1 and \s-0 + # strings inserted around things that we've made small-caps if later + # transforms should work on those strings. + + # Embolden functions in the form func(), including functions that are in + # all capitals, but don't embolden if there's anything between the parens. + # The function must start with an alphabetic character or underscore and + # then consist of word characters or colons. + if ($$self{MAGIC_FUNC}) { + s{ + ( \b | \\s-1 ) + ( [A-Za-z_] ([:\w] | \\s-?[01])+ \(\) ) + } { + $1 . '\f(BS' . $2 . '\f(BE' + }egx; + } + + # Change references to manual pages to put the page name in bold but + # the number in the regular font, with a thin space between the name and + # the number. Only recognize func(n) where func starts with an alphabetic + # character or underscore and contains only word characters, periods (for + # configuration file man pages), or colons, and n is a single digit, + # optionally followed by some number of lowercase letters. Note that this + # does not recognize man page references like perl(l) or socket(3SOCKET). + if ($$self{MAGIC_MANREF}) { + s{ + ( \b | \\s-1 ) + (? 5 and print " Guesswork returning [$_]\n"; + return $_; +} + +############################################################################## +# Output +############################################################################## + +# When building up the *roff code, we don't use real *roff fonts. Instead, we +# embed font codes of the form \f([SE] where is one of B, I, or +# F, S stands for start, and E stands for end. This method turns these into +# the right start and end codes. +# +# We add this level of complexity because the old pod2man didn't get code like +# B else> right; after I<> it switched back to normal text rather +# than bold. We take care of this by using variables that state whether bold, +# italic, or fixed are turned on as a combined pointer to our current font +# sequence, and set each to the number of current nestings of start tags for +# that font. +# +# \fP changes to the previous font, but only one previous font is kept. We +# don't know what the outside level font is; normally it's R, but if we're +# inside a heading it could be something else. So arrange things so that the +# outside font is always the "previous" font and end with \fP instead of \fR. +# Idea from Zack Weinberg. +sub mapfonts { + my ($self, $text) = @_; + my ($fixed, $bold, $italic) = (0, 0, 0); + my %magic = (F => \$fixed, B => \$bold, I => \$italic); + my $last = '\fR'; + $text =~ s< + \\f\((.)(.) + > < + my $sequence = ''; + my $f; + if ($last ne '\fR') { $sequence = '\fP' } + ${ $magic{$1} } += ($2 eq 'S') ? 1 : -1; + $f = $$self{FONTS}{ ($fixed && 1) . ($bold && 1) . ($italic && 1) }; + if ($f eq $last) { + ''; + } else { + if ($f ne '\fR') { $sequence .= $f } + $last = $f; + $sequence; + } + >gxe; + return $text; +} + +# Unfortunately, there is a bug in Solaris 2.6 nroff (not present in GNU +# groff) where the sequence \fB\fP\f(CW\fP leaves the font set to B rather +# than R, presumably because \f(CW doesn't actually do a font change. To work +# around this, use a separate textmapfonts for text blocks where the default +# font is always R and only use the smart mapfonts for headings. +sub textmapfonts { + my ($self, $text) = @_; + my ($fixed, $bold, $italic) = (0, 0, 0); + my %magic = (F => \$fixed, B => \$bold, I => \$italic); + $text =~ s< + \\f\((.)(.) + > < + ${ $magic{$1} } += ($2 eq 'S') ? 1 : -1; + $$self{FONTS}{ ($fixed && 1) . ($bold && 1) . ($italic && 1) }; + >gxe; + return $text; +} + +# Given a command and a single argument that may or may not contain double +# quotes, handle double-quote formatting for it. If there are no double +# quotes, just return the command followed by the argument in double quotes. +# If there are double quotes, use an if statement to test for nroff, and for +# nroff output the command followed by the argument in double quotes with +# embedded double quotes doubled. For other formatters, remap paired double +# quotes to LQUOTE and RQUOTE. +sub switchquotes { + my ($self, $command, $text, $extra) = @_; + $text =~ s/\\\*\([LR]\"/\"/g; + + # We also have to deal with \*C` and \*C', which are used to add the + # quotes around C<> text, since they may expand to " and if they do this + # confuses the .SH macros and the like no end. Expand them ourselves. + # Also separate troff from nroff if there are any fixed-width fonts in use + # to work around problems with Solaris nroff. + my $c_is_quote = ($$self{LQUOTE} =~ /\"/) || ($$self{RQUOTE} =~ /\"/); + my $fixedpat = join '|', @{ $$self{FONTS} }{'100', '101', '110', '111'}; + $fixedpat =~ s/\\/\\\\/g; + $fixedpat =~ s/\(/\\\(/g; + if ($text =~ m/\"/ || $text =~ m/$fixedpat/) { + $text =~ s/\"/\"\"/g; + my $nroff = $text; + my $troff = $text; + $troff =~ s/\"\"([^\"]*)\"\"/\`\`$1\'\'/g; + if ($c_is_quote and $text =~ m/\\\*\(C[\'\`]/) { + $nroff =~ s/\\\*\(C\`/$$self{LQUOTE}/g; + $nroff =~ s/\\\*\(C\'/$$self{RQUOTE}/g; + $troff =~ s/\\\*\(C[\'\`]//g; + } + $nroff = qq("$nroff") . ($extra ? " $extra" : ''); + $troff = qq("$troff") . ($extra ? " $extra" : ''); + + # Work around the Solaris nroff bug where \f(CW\fP leaves the font set + # to Roman rather than the actual previous font when used in headings. + # troff output may still be broken, but at least we can fix nroff by + # just switching the font changes to the non-fixed versions. + my $font_end = "(?:\\f[PR]|\Q$$self{FONTS}{100}\E)"; + $nroff =~ s/\Q$$self{FONTS}{100}\E(.*?)\\f([PR])/$1/g; + $nroff =~ s/\Q$$self{FONTS}{101}\E(.*?)$font_end/\\fI$1\\fP/g; + $nroff =~ s/\Q$$self{FONTS}{110}\E(.*?)$font_end/\\fB$1\\fP/g; + $nroff =~ s/\Q$$self{FONTS}{111}\E(.*?)$font_end/\\f\(BI$1\\fP/g; + + # Now finally output the command. Bother with .ie only if the nroff + # and troff output aren't the same. + if ($nroff ne $troff) { + return ".ie n $command $nroff\n.el $command $troff\n"; + } else { + return "$command $nroff\n"; + } + } else { + $text = qq("$text") . ($extra ? " $extra" : ''); + return "$command $text\n"; + } +} + +# Protect leading quotes and periods against interpretation as commands. Also +# protect anything starting with a backslash, since it could expand or hide +# something that *roff would interpret as a command. This is overkill, but +# it's much simpler than trying to parse *roff here. +sub protect { + my ($self, $text) = @_; + $text =~ s/^([.\'\\])/\\&$1/mg; + return $text; +} + +# Make vertical whitespace if NEEDSPACE is set, appropriate to the indentation +# level the situation. This function is needed since in *roff one has to +# create vertical whitespace after paragraphs and between some things, but +# other macros create their own whitespace. Also close out a sequence of +# repeated =items, since calling makespace means we're about to begin the item +# body. +sub makespace { + my ($self) = @_; + $self->output (".PD\n") if $$self{ITEMS} > 1; + $$self{ITEMS} = 0; + $self->output ($$self{INDENT} > 0 ? ".Sp\n" : ".PP\n") + if $$self{NEEDSPACE}; +} + +# Output any pending index entries, and optionally an index entry given as an +# argument. Support multiple index entries in X<> separated by slashes, and +# strip special escapes from index entries. +sub outindex { + my ($self, $section, $index) = @_; + my @entries = map { split m%\s*/\s*% } @{ $$self{INDEX} }; + return unless ($section || @entries); + + # We're about to output all pending entries, so clear our pending queue. + $$self{INDEX} = []; + + # Build the output. Regular index entries are marked Xref, and headings + # pass in their own section. Undo some *roff formatting on headings. + my @output; + if (@entries) { + push @output, [ 'Xref', join (' ', @entries) ]; + } + if ($section) { + $index =~ s/\\-/-/g; + $index =~ s/\\(?:s-?\d|.\(..|.)//g; + push @output, [ $section, $index ]; + } + + # Print out the .IX commands. + for (@output) { + my ($type, $entry) = @$_; + $entry =~ s/\s+/ /g; + $entry =~ s/\"/\"\"/g; + $entry =~ s/\\/\\\\/g; + $self->output (".IX $type " . '"' . $entry . '"' . "\n"); + } +} + +# Output some text, without any additional changes. +sub output { + my ($self, @text) = @_; + if ($$self{ENCODE}) { + print { $$self{output_fh} } Encode::encode ('UTF-8', join ('', @text)); + } else { + print { $$self{output_fh} } @text; + } +} + +############################################################################## +# Document initialization +############################################################################## + +# Handle the start of the document. Here we handle empty documents, as well +# as setting up our basic macros in a preamble and building the page title. +sub start_document { + my ($self, $attrs) = @_; + if ($$attrs{contentless} && !$$self{ALWAYS_EMIT_SOMETHING}) { + DEBUG and print "Document is contentless\n"; + $$self{CONTENTLESS} = 1; + } else { + delete $$self{CONTENTLESS}; + } + + # When UTF-8 output is set, check whether our output file handle already + # has a PerlIO encoding layer set. If it does not, we'll need to encode + # our output before printing it (handled in the output() sub). Wrap the + # check in an eval to handle versions of Perl without PerlIO. + # + # PerlIO::get_layers still requires its argument be a glob, so coerce the + # file handle to a glob. + $$self{ENCODE} = 0; + if ($$self{utf8}) { + $$self{ENCODE} = 1; + eval { + my @options = (output => 1, details => 1); + my @layers = PerlIO::get_layers (*{$$self{output_fh}}, @options); + if ($layers[-1] & PerlIO::F_UTF8 ()) { + $$self{ENCODE} = 0; + } + } + } + + # Determine information for the preamble and then output it unless the + # document was content-free. + if (!$$self{CONTENTLESS}) { + my ($name, $section); + if (defined $$self{name}) { + $name = $$self{name}; + $section = $$self{section} || 1; + } else { + ($name, $section) = $self->devise_title; + } + my $date = defined($$self{date}) ? $$self{date} : $self->devise_date; + $self->preamble ($name, $section, $date) + unless $self->bare_output or DEBUG > 9; + } + + # Initialize a few per-document variables. + $$self{INDENT} = 0; # Current indentation level. + $$self{INDENTS} = []; # Stack of indentations. + $$self{INDEX} = []; # Index keys waiting to be printed. + $$self{IN_NAME} = 0; # Whether processing the NAME section. + $$self{ITEMS} = 0; # The number of consecutive =items. + $$self{ITEMTYPES} = []; # Stack of =item types, one per list. + $$self{SHIFTWAIT} = 0; # Whether there is a shift waiting. + $$self{SHIFTS} = []; # Stack of .RS shifts. + $$self{PENDING} = [[]]; # Pending output. +} + +# Handle the end of the document. This handles dying on POD errors, since +# Pod::Parser currently doesn't. Otherwise, does nothing but print out a +# final comment at the end of the document under debugging. +sub end_document { + my ($self) = @_; + if ($$self{complain_die} && $self->errors_seen) { + croak ("POD document had syntax errors"); + } + return if $self->bare_output; + return if ($$self{CONTENTLESS} && !$$self{ALWAYS_EMIT_SOMETHING}); + $self->output (q(.\" [End document]) . "\n") if DEBUG; +} + +# Try to figure out the name and section from the file name and return them as +# a list, returning an empty name and section 1 if we can't find any better +# information. Uses File::Basename and File::Spec as necessary. +sub devise_title { + my ($self) = @_; + my $name = $self->source_filename || ''; + my $section = $$self{section} || 1; + $section = 3 if (!$$self{section} && $name =~ /\.pm\z/i); + $name =~ s/\.p(od|[lm])\z//i; + + # If Pod::Parser gave us an IO::File reference as the source file name, + # convert that to the empty string as well. Then, if we don't have a + # valid name, convert it to STDIN. + # + # In podlators 4.00 through 4.07, this also produced a warning, but that + # was surprising to a lot of programs that had expected to be able to pipe + # POD through pod2man without specifying the name. In the name of + # backward compatibility, just quietly set STDIN as the page title. + if ($name =~ /^IO::File(?:=\w+)\(0x[\da-f]+\)$/i) { + $name = ''; + } + if ($name eq '') { + $name = 'STDIN'; + } + + # If the section isn't 3, then the name defaults to just the basename of + # the file. + if ($section !~ /^3/) { + require File::Basename; + $name = uc File::Basename::basename ($name); + } else { + require File::Spec; + my ($volume, $dirs, $file) = File::Spec->splitpath ($name); + + # Otherwise, assume we're dealing with a module. We want to figure + # out the full module name from the path to the file, but we don't + # want to include too much of the path into the module name. Lose + # anything up to the first of: + # + # */lib/*perl*/ standard or site_perl module + # */*perl*/lib/ from -Dprefix=/opt/perl + # */*perl*/ random module hierarchy + # + # Also strip off a leading site, site_perl, or vendor_perl component, + # any OS-specific component, and any version number component, and + # strip off an initial component of "lib" or "blib/lib" since that's + # what ExtUtils::MakeMaker creates. + # + # splitdir requires at least File::Spec 0.8. + my @dirs = File::Spec->splitdir ($dirs); + if (@dirs) { + my $cut = 0; + my $i; + for ($i = 0; $i < @dirs; $i++) { + if ($dirs[$i] =~ /perl/) { + $cut = $i + 1; + $cut++ if ($dirs[$i + 1] && $dirs[$i + 1] eq 'lib'); + last; + } + } + if ($cut > 0) { + splice (@dirs, 0, $cut); + shift @dirs if ($dirs[0] =~ /^(site|vendor)(_perl)?$/); + shift @dirs if ($dirs[0] =~ /^[\d.]+$/); + shift @dirs if ($dirs[0] =~ /^(.*-$^O|$^O-.*|$^O)$/); + } + shift @dirs if $dirs[0] eq 'lib'; + splice (@dirs, 0, 2) if ($dirs[0] eq 'blib' && $dirs[1] eq 'lib'); + } + + # Remove empty directories when building the module name; they + # occur too easily on Unix by doubling slashes. + $name = join ('::', (grep { $_ ? $_ : () } @dirs), $file); + } + return ($name, $section); +} + +# Determine the modification date and return that, properly formatted in ISO +# format. +# +# If POD_MAN_DATE is set, that overrides anything else. This can be used for +# reproducible generation of the same file even if the input file timestamps +# are unpredictable or the POD comes from standard input. +# +# Otherwise, if SOURCE_DATE_EPOCH is set and can be parsed as seconds since +# the UNIX epoch, base the timestamp on that. See +# +# +# Otherwise, use the modification date of the input if we can stat it. Be +# aware that Pod::Simple returns the stringification of the file handle as +# source_filename for input from a file handle, so we'll stat some random ref +# string in that case. If that fails, instead use the current time. +# +# $self - Pod::Man object, used to get the source file +# +# Returns: YYYY-MM-DD date suitable for the left-hand footer +sub devise_date { + my ($self) = @_; + + # If POD_MAN_DATE is set, always use it. + if (defined($ENV{POD_MAN_DATE})) { + return $ENV{POD_MAN_DATE}; + } + + # If SOURCE_DATE_EPOCH is set and can be parsed, use that. + my $time; + if (defined($ENV{SOURCE_DATE_EPOCH}) && $ENV{SOURCE_DATE_EPOCH} !~ /\D/) { + $time = $ENV{SOURCE_DATE_EPOCH}; + } + + # Otherwise, get the input filename and try to stat it. If that fails, + # use the current time. + if (!defined $time) { + my $input = $self->source_filename; + if ($input) { + $time = (stat($input))[9] || time(); + } else { + $time = time(); + } + } + + # Can't use POSIX::strftime(), which uses Fcntl, because MakeMaker uses + # this and it has to work in the core which can't load dynamic libraries. + # Use gmtime instead of localtime so that the generated man page does not + # depend on the local time zone setting and is more reproducible + my ($year, $month, $day) = (gmtime($time))[5,4,3]; + return sprintf("%04d-%02d-%02d", $year + 1900, $month + 1, $day); +} + +# Print out the preamble and the title. The meaning of the arguments to .TH +# unfortunately vary by system; some systems consider the fourth argument to +# be a "source" and others use it as a version number. Generally it's just +# presented as the left-side footer, though, so it doesn't matter too much if +# a particular system gives it another interpretation. +# +# The order of date and release used to be reversed in older versions of this +# module, but this order is correct for both Solaris and Linux. +sub preamble { + my ($self, $name, $section, $date) = @_; + my $preamble = $self->preamble_template (!$$self{utf8}); + + # Build the index line and make sure that it will be syntactically valid. + my $index = "$name $section"; + $index =~ s/\"/\"\"/g; + + # If name or section contain spaces, quote them (section really never + # should, but we may as well be cautious). + for ($name, $section) { + if (/\s/) { + s/\"/\"\"/g; + $_ = '"' . $_ . '"'; + } + } + + # Double quotes in date, since it will be quoted. + $date =~ s/\"/\"\"/g; + + # Substitute into the preamble the configuration options. + $preamble =~ s/\@CFONT\@/$$self{fixed}/; + $preamble =~ s/\@LQUOTE\@/$$self{LQUOTE}/; + $preamble =~ s/\@RQUOTE\@/$$self{RQUOTE}/; + chomp $preamble; + + # Get the version information. + my $version = $self->version_report; + + # Finally output everything. + $self->output (<<"----END OF HEADER----"); +.\\" Automatically generated by $version +.\\" +.\\" Standard preamble: +.\\" ======================================================================== +$preamble +.\\" ======================================================================== +.\\" +.IX Title "$index" +.TH $name $section "$date" "$$self{release}" "$$self{center}" +.\\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\\" way too many mistakes in technical documents. +.if n .ad l +.nh +----END OF HEADER---- + $self->output (".\\\" [End of preamble]\n") if DEBUG; +} + +############################################################################## +# Text blocks +############################################################################## + +# Handle a basic block of text. The only tricky part of this is if this is +# the first paragraph of text after an =over, in which case we have to change +# indentations for *roff. +sub cmd_para { + my ($self, $attrs, $text) = @_; + my $line = $$attrs{start_line}; + + # Output the paragraph. We also have to handle =over without =item. If + # there's an =over without =item, SHIFTWAIT will be set, and we need to + # handle creation of the indent here. Add the shift to SHIFTS so that it + # will be cleaned up on =back. + $self->makespace; + if ($$self{SHIFTWAIT}) { + $self->output (".RS $$self{INDENT}\n"); + push (@{ $$self{SHIFTS} }, $$self{INDENT}); + $$self{SHIFTWAIT} = 0; + } + + # Add the line number for debugging, but not in the NAME section just in + # case the comment would confuse apropos. + $self->output (".\\\" [At source line $line]\n") + if defined ($line) && DEBUG && !$$self{IN_NAME}; + + # Force exactly one newline at the end and strip unwanted trailing + # whitespace at the end, but leave "\ " backslashed space from an S< > at + # the end of a line. Reverse the text first, to avoid having to scan the + # entire paragraph. + $text = reverse $text; + $text =~ s/\A\s*?(?= \\|\S|\z)/\n/; + $text = reverse $text; + + # Output the paragraph. + $self->output ($self->protect ($self->textmapfonts ($text))); + $self->outindex; + $$self{NEEDSPACE} = 1; + return ''; +} + +# Handle a verbatim paragraph. Put a null token at the beginning of each line +# to protect against commands and wrap in .Vb/.Ve (which we define in our +# prelude). +sub cmd_verbatim { + my ($self, $attrs, $text) = @_; + + # Ignore an empty verbatim paragraph. + return unless $text =~ /\S/; + + # Force exactly one newline at the end and strip unwanted trailing + # whitespace at the end. Reverse the text first, to avoid having to scan + # the entire paragraph. + $text = reverse $text; + $text =~ s/\A\s*/\n/; + $text = reverse $text; + + # Get a count of the number of lines before the first blank line, which + # we'll pass to .Vb as its parameter. This tells *roff to keep that many + # lines together. We don't want to tell *roff to keep huge blocks + # together. + my @lines = split (/\n/, $text); + my $unbroken = 0; + for (@lines) { + last if /^\s*$/; + $unbroken++; + } + $unbroken = 10 if ($unbroken > 12 && !$$self{MAGIC_VNOPAGEBREAK_LIMIT}); + + # Prepend a null token to each line. + $text =~ s/^/\\&/gm; + + # Output the results. + $self->makespace; + $self->output (".Vb $unbroken\n$text.Ve\n"); + $$self{NEEDSPACE} = 1; + return ''; +} + +# Handle literal text (produced by =for and similar constructs). Just output +# it with the minimum of changes. +sub cmd_data { + my ($self, $attrs, $text) = @_; + $text =~ s/^\n+//; + $text =~ s/\n{0,2}$/\n/; + $self->output ($text); + return ''; +} + +############################################################################## +# Headings +############################################################################## + +# Common code for all headings. This is called before the actual heading is +# output. It returns the cleaned up heading text (putting the heading all on +# one line) and may do other things, like closing bad =item blocks. +sub heading_common { + my ($self, $text, $line) = @_; + $text =~ s/\s+$//; + $text =~ s/\s*\n\s*/ /g; + + # This should never happen; it means that we have a heading after =item + # without an intervening =back. But just in case, handle it anyway. + if ($$self{ITEMS} > 1) { + $$self{ITEMS} = 0; + $self->output (".PD\n"); + } + + # Output the current source line. + $self->output ( ".\\\" [At source line $line]\n" ) + if defined ($line) && DEBUG; + return $text; +} + +# First level heading. We can't output .IX in the NAME section due to a bug +# in some versions of catman, so don't output a .IX for that section. .SH +# already uses small caps, so remove \s0 and \s-1. Maintain IN_NAME as +# appropriate. +sub cmd_head1 { + my ($self, $attrs, $text) = @_; + $text =~ s/\\s-?\d//g; + $text = $self->heading_common ($text, $$attrs{start_line}); + my $isname = ($text eq 'NAME' || $text =~ /\(NAME\)/); + $self->output ($self->switchquotes ('.SH', $self->mapfonts ($text))); + $self->outindex ('Header', $text) unless $isname; + $$self{NEEDSPACE} = 0; + $$self{IN_NAME} = $isname; + return ''; +} + +# Second level heading. +sub cmd_head2 { + my ($self, $attrs, $text) = @_; + $text = $self->heading_common ($text, $$attrs{start_line}); + $self->output ($self->switchquotes ('.SS', $self->mapfonts ($text))); + $self->outindex ('Subsection', $text); + $$self{NEEDSPACE} = 0; + return ''; +} + +# Third level heading. *roff doesn't have this concept, so just put the +# heading in italics as a normal paragraph. +sub cmd_head3 { + my ($self, $attrs, $text) = @_; + $text = $self->heading_common ($text, $$attrs{start_line}); + $self->makespace; + $self->output ($self->textmapfonts ('\f(IS' . $text . '\f(IE') . "\n"); + $self->outindex ('Subsection', $text); + $$self{NEEDSPACE} = 1; + return ''; +} + +# Fourth level heading. *roff doesn't have this concept, so just put the +# heading as a normal paragraph. +sub cmd_head4 { + my ($self, $attrs, $text) = @_; + $text = $self->heading_common ($text, $$attrs{start_line}); + $self->makespace; + $self->output ($self->textmapfonts ($text) . "\n"); + $self->outindex ('Subsection', $text); + $$self{NEEDSPACE} = 1; + return ''; +} + +############################################################################## +# Formatting codes +############################################################################## + +# All of the formatting codes that aren't handled internally by the parser, +# other than L<> and X<>. +sub cmd_b { return $_[0]->{IN_NAME} ? $_[2] : '\f(BS' . $_[2] . '\f(BE' } +sub cmd_i { return $_[0]->{IN_NAME} ? $_[2] : '\f(IS' . $_[2] . '\f(IE' } +sub cmd_f { return $_[0]->{IN_NAME} ? $_[2] : '\f(IS' . $_[2] . '\f(IE' } +sub cmd_c { return $_[0]->quote_literal ($_[2]) } + +# Index entries are just added to the pending entries. +sub cmd_x { + my ($self, $attrs, $text) = @_; + push (@{ $$self{INDEX} }, $text); + return ''; +} + +# Links reduce to the text that we're given, wrapped in angle brackets if it's +# a URL, followed by the URL. We take an option to suppress the URL if anchor +# text is given. We need to format the "to" value of the link before +# comparing it to the text since we may escape hyphens. +sub cmd_l { + my ($self, $attrs, $text) = @_; + if ($$attrs{type} eq 'url') { + my $to = $$attrs{to}; + if (defined $to) { + my $tag = $$self{PENDING}[-1]; + $to = $self->format_text ($$tag[1], $to); + } + if (not defined ($to) or $to eq $text) { + return "<$text>"; + } elsif ($$self{nourls}) { + return $text; + } else { + return "$text <$$attrs{to}>"; + } + } else { + return $text; + } +} + +############################################################################## +# List handling +############################################################################## + +# Handle the beginning of an =over block. Takes the type of the block as the +# first argument, and then the attr hash. This is called by the handlers for +# the four different types of lists (bullet, number, text, and block). +sub over_common_start { + my ($self, $type, $attrs) = @_; + my $line = $$attrs{start_line}; + my $indent = $$attrs{indent}; + DEBUG > 3 and print " Starting =over $type (line $line, indent ", + ($indent || '?'), "\n"; + + # Find the indentation level. + unless (defined ($indent) && $indent =~ /^[-+]?\d{1,4}\s*$/) { + $indent = $$self{indent}; + } + + # If we've gotten multiple indentations in a row, we need to emit the + # pending indentation for the last level that we saw and haven't acted on + # yet. SHIFTS is the stack of indentations that we've actually emitted + # code for. + if (@{ $$self{SHIFTS} } < @{ $$self{INDENTS} }) { + $self->output (".RS $$self{INDENT}\n"); + push (@{ $$self{SHIFTS} }, $$self{INDENT}); + } + + # Now, do record-keeping. INDENTS is a stack of indentations that we've + # seen so far, and INDENT is the current level of indentation. ITEMTYPES + # is a stack of list types that we've seen. + push (@{ $$self{INDENTS} }, $$self{INDENT}); + push (@{ $$self{ITEMTYPES} }, $type); + $$self{INDENT} = $indent + 0; + $$self{SHIFTWAIT} = 1; +} + +# End an =over block. Takes no options other than the class pointer. +# Normally, once we close a block and therefore remove something from INDENTS, +# INDENTS will now be longer than SHIFTS, indicating that we also need to emit +# *roff code to close the indent. This isn't *always* true, depending on the +# circumstance. If we're still inside an indentation, we need to emit another +# .RE and then a new .RS to unconfuse *roff. +sub over_common_end { + my ($self) = @_; + DEBUG > 3 and print " Ending =over\n"; + $$self{INDENT} = pop @{ $$self{INDENTS} }; + pop @{ $$self{ITEMTYPES} }; + + # If we emitted code for that indentation, end it. + if (@{ $$self{SHIFTS} } > @{ $$self{INDENTS} }) { + $self->output (".RE\n"); + pop @{ $$self{SHIFTS} }; + } + + # If we're still in an indentation, *roff will have now lost track of the + # right depth of that indentation, so fix that. + if (@{ $$self{INDENTS} } > 0) { + $self->output (".RE\n"); + $self->output (".RS $$self{INDENT}\n"); + } + $$self{NEEDSPACE} = 1; + $$self{SHIFTWAIT} = 0; +} + +# Dispatch the start and end calls as appropriate. +sub start_over_bullet { my $s = shift; $s->over_common_start ('bullet', @_) } +sub start_over_number { my $s = shift; $s->over_common_start ('number', @_) } +sub start_over_text { my $s = shift; $s->over_common_start ('text', @_) } +sub start_over_block { my $s = shift; $s->over_common_start ('block', @_) } +sub end_over_bullet { $_[0]->over_common_end } +sub end_over_number { $_[0]->over_common_end } +sub end_over_text { $_[0]->over_common_end } +sub end_over_block { $_[0]->over_common_end } + +# The common handler for all item commands. Takes the type of the item, the +# attributes, and then the text of the item. +# +# Emit an index entry for anything that's interesting, but don't emit index +# entries for things like bullets and numbers. Newlines in an item title are +# turned into spaces since *roff can't handle them embedded. +sub item_common { + my ($self, $type, $attrs, $text) = @_; + my $line = $$attrs{start_line}; + DEBUG > 3 and print " $type item (line $line): $text\n"; + + # Clean up the text. We want to end up with two variables, one ($text) + # which contains any body text after taking out the item portion, and + # another ($item) which contains the actual item text. + $text =~ s/\s+$//; + my ($item, $index); + if ($type eq 'bullet') { + $item = "\\\(bu"; + $text =~ s/\n*$/\n/; + } elsif ($type eq 'number') { + $item = $$attrs{number} . '.'; + } else { + $item = $text; + $item =~ s/\s*\n\s*/ /g; + $text = ''; + $index = $item if ($item =~ /\w/); + } + + # Take care of the indentation. If shifts and indents are equal, close + # the top shift, since we're about to create an indentation with .IP. + # Also output .PD 0 to turn off spacing between items if this item is + # directly following another one. We only have to do that once for a + # whole chain of items so do it for the second item in the change. Note + # that makespace is what undoes this. + if (@{ $$self{SHIFTS} } == @{ $$self{INDENTS} }) { + $self->output (".RE\n"); + pop @{ $$self{SHIFTS} }; + } + $self->output (".PD 0\n") if ($$self{ITEMS} == 1); + + # Now, output the item tag itself. + $item = $self->textmapfonts ($item); + $self->output ($self->switchquotes ('.IP', $item, $$self{INDENT})); + $$self{NEEDSPACE} = 0; + $$self{ITEMS}++; + $$self{SHIFTWAIT} = 0; + + # If body text for this item was included, go ahead and output that now. + if ($text) { + $text =~ s/\s*$/\n/; + $self->makespace; + $self->output ($self->protect ($self->textmapfonts ($text))); + $$self{NEEDSPACE} = 1; + } + $self->outindex ($index ? ('Item', $index) : ()); +} + +# Dispatch the item commands to the appropriate place. +sub cmd_item_bullet { my $self = shift; $self->item_common ('bullet', @_) } +sub cmd_item_number { my $self = shift; $self->item_common ('number', @_) } +sub cmd_item_text { my $self = shift; $self->item_common ('text', @_) } +sub cmd_item_block { my $self = shift; $self->item_common ('block', @_) } + +############################################################################## +# Backward compatibility +############################################################################## + +# Reset the underlying Pod::Simple object between calls to parse_from_file so +# that the same object can be reused to convert multiple pages. +sub parse_from_file { + my $self = shift; + $self->reinit; + + # Fake the old cutting option to Pod::Parser. This fiddles with internal + # Pod::Simple state and is quite ugly; we need a better approach. + if (ref ($_[0]) eq 'HASH') { + my $opts = shift @_; + if (defined ($$opts{-cutting}) && !$$opts{-cutting}) { + $$self{in_pod} = 1; + $$self{last_was_blank} = 1; + } + } + + # Do the work. + my $retval = $self->SUPER::parse_from_file (@_); + + # Flush output, since Pod::Simple doesn't do this. Ideally we should also + # close the file descriptor if we had to open one, but we can't easily + # figure this out. + my $fh = $self->output_fh (); + my $oldfh = select $fh; + my $oldflush = $|; + $| = 1; + print $fh ''; + $| = $oldflush; + select $oldfh; + return $retval; +} + +# Pod::Simple failed to provide this backward compatibility function, so +# implement it ourselves. File handles are one of the inputs that +# parse_from_file supports. +sub parse_from_filehandle { + my $self = shift; + return $self->parse_from_file (@_); +} + +# Pod::Simple's parse_file doesn't set output_fh. Wrap the call and do so +# ourself unless it was already set by the caller, since our documentation has +# always said that this should work. +sub parse_file { + my ($self, $in) = @_; + unless (defined $$self{output_fh}) { + $self->output_fh (\*STDOUT); + } + return $self->SUPER::parse_file ($in); +} + +# Do the same for parse_lines, just to be polite. Pod::Simple's man page +# implies that the caller is responsible for setting this, but I don't see any +# reason not to set a default. +sub parse_lines { + my ($self, @lines) = @_; + unless (defined $$self{output_fh}) { + $self->output_fh (\*STDOUT); + } + return $self->SUPER::parse_lines (@lines); +} + +# Likewise for parse_string_document. +sub parse_string_document { + my ($self, $doc) = @_; + unless (defined $$self{output_fh}) { + $self->output_fh (\*STDOUT); + } + return $self->SUPER::parse_string_document ($doc); +} + +############################################################################## +# Translation tables +############################################################################## + +# The following table is adapted from Tom Christiansen's pod2man. It assumes +# that the standard preamble has already been printed, since that's what +# defines all of the accent marks. We really want to do something better than +# this when *roff actually supports other character sets itself, since these +# results are pretty poor. +# +# This only works in an ASCII world. What to do in a non-ASCII world is very +# unclear -- hopefully we can assume UTF-8 and just leave well enough alone. +@ESCAPES{0xA0 .. 0xFF} = ( + "\\ ", undef, undef, undef, undef, undef, undef, undef, + undef, undef, undef, undef, undef, "\\%", undef, undef, + + undef, undef, undef, undef, undef, undef, undef, undef, + undef, undef, undef, undef, undef, undef, undef, undef, + + "A\\*`", "A\\*'", "A\\*^", "A\\*~", "A\\*:", "A\\*o", "\\*(Ae", "C\\*,", + "E\\*`", "E\\*'", "E\\*^", "E\\*:", "I\\*`", "I\\*'", "I\\*^", "I\\*:", + + "\\*(D-", "N\\*~", "O\\*`", "O\\*'", "O\\*^", "O\\*~", "O\\*:", undef, + "O\\*/", "U\\*`", "U\\*'", "U\\*^", "U\\*:", "Y\\*'", "\\*(Th", "\\*8", + + "a\\*`", "a\\*'", "a\\*^", "a\\*~", "a\\*:", "a\\*o", "\\*(ae", "c\\*,", + "e\\*`", "e\\*'", "e\\*^", "e\\*:", "i\\*`", "i\\*'", "i\\*^", "i\\*:", + + "\\*(d-", "n\\*~", "o\\*`", "o\\*'", "o\\*^", "o\\*~", "o\\*:", undef, + "o\\*/" , "u\\*`", "u\\*'", "u\\*^", "u\\*:", "y\\*'", "\\*(th", "y\\*:", +) if ASCII; + +############################################################################## +# Premable +############################################################################## + +# The following is the static preamble which starts all *roff output we +# generate. Most is static except for the font to use as a fixed-width font, +# which is designed by @CFONT@, and the left and right quotes to use for C<> +# text, designated by @LQOUTE@ and @RQUOTE@. However, the second part, which +# defines the accent marks, is only used if $escapes is set to true. +sub preamble_template { + my ($self, $accents) = @_; + my $preamble = <<'----END OF PREAMBLE----'; +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft @CFONT@ +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` @LQUOTE@ +. ds C' @RQUOTE@ +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{\ +. if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +----END OF PREAMBLE---- +#'# for cperl-mode + + if ($accents) { + $preamble .= <<'----END OF PREAMBLE----' +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +----END OF PREAMBLE---- +#`# for cperl-mode + } + return $preamble; +} + +############################################################################## +# Module return value and documentation +############################################################################## + +1; +__END__ + +=for stopwords +en em ALLCAPS teeny fixedbold fixeditalic fixedbolditalic stderr utf8 UTF-8 +Allbery Sean Burke Ossanna Solaris formatters troff uppercased Christiansen +nourls parsers Kernighan lquote rquote + +=head1 NAME + +Pod::Man - Convert POD data to formatted *roff input + +=head1 SYNOPSIS + + use Pod::Man; + my $parser = Pod::Man->new (release => $VERSION, section => 8); + + # Read POD from STDIN and write to STDOUT. + $parser->parse_file (\*STDIN); + + # Read POD from file.pod and write to file.1. + $parser->parse_from_file ('file.pod', 'file.1'); + +=head1 DESCRIPTION + +Pod::Man is a module to convert documentation in the POD format (the +preferred language for documenting Perl) into *roff input using the man +macro set. The resulting *roff code is suitable for display on a terminal +using L, normally via L, or printing using L. +It is conventionally invoked using the driver script B, but it can +also be used directly. + +As a derived class from Pod::Simple, Pod::Man supports the same methods and +interfaces. See L for all the details. + +new() can take options, in the form of key/value pairs that control the +behavior of the parser. See below for details. + +If no options are given, Pod::Man uses the name of the input file with any +trailing C<.pod>, C<.pm>, or C<.pl> stripped as the man page title, to +section 1 unless the file ended in C<.pm> in which case it defaults to +section 3, to a centered title of "User Contributed Perl Documentation", to +a centered footer of the Perl version it is run with, and to a left-hand +footer of the modification date of its input (or the current date if given +C for input). + +Pod::Man assumes that your *roff formatters have a fixed-width font named +C. If yours is called something else (like C), use the C +option to specify it. This generally only matters for troff output for +printing. Similarly, you can set the fonts used for bold, italic, and +bold italic fixed-width output. + +Besides the obvious pod conversions, Pod::Man also takes care of +formatting func(), func(3), and simple variable references like $foo or +@bar so you don't have to use code escapes for them; complex expressions +like C<$fred{'stuff'}> will still need to be escaped, though. It also +translates dashes that aren't used as hyphens into en dashes, makes long +dashes--like this--into proper em dashes, fixes "paired quotes," makes C++ +look right, puts a little space between double underscores, makes ALLCAPS +a teeny bit smaller in B, and escapes stuff that *roff treats as +special so that you don't have to. + +The recognized options to new() are as follows. All options take a single +argument. + +=over 4 + +=item center + +Sets the centered page header for the C<.TH> macro. The default, if this +option is not specified, is "User Contributed Perl Documentation". + +=item date + +Sets the left-hand footer for the C<.TH> macro. If this option is not set, +the contents of the environment variable POD_MAN_DATE, if set, will be used. +Failing that, the value of SOURCE_DATE_EPOCH, the modification date of the +input file, or the current time if stat() can't find that file (which will be +the case if the input is from C) will be used. If obtained from the +file modification date or the current time, the date will be formatted as +C and will be based on UTC (so that the output will be +reproducible regardless of local time zone). + +=item errors + +How to report errors. C says to throw an exception on any POD +formatting error. C says to report errors on standard error, but +not to throw an exception. C says to include a POD ERRORS section +in the resulting documentation summarizing the errors. C ignores +POD errors entirely, as much as possible. + +The default is C. + +=item fixed + +The fixed-width font to use for verbatim text and code. Defaults to +C. Some systems may want C instead. Only matters for B +output. + +=item fixedbold + +Bold version of the fixed-width font. Defaults to C. Only matters +for B output. + +=item fixeditalic + +Italic version of the fixed-width font (actually, something of a misnomer, +since most fixed-width fonts only have an oblique version, not an italic +version). Defaults to C. Only matters for B output. + +=item fixedbolditalic + +Bold italic (probably actually oblique) version of the fixed-width font. +Pod::Man doesn't assume you have this, and defaults to C. Some +systems (such as Solaris) have this font available as C. Only matters +for B output. + +=item lquote + +=item rquote + +Sets the quote marks used to surround CE> text. C sets the +left quote mark and C sets the right quote mark. Either may also +be set to the special value C, in which case no quote mark is added +on that side of CE> text (but the font is still changed for troff +output). + +Also see the C option, which can be used to set both quotes at once. +If both C and one of the other options is set, C or C +overrides C. + +=item name + +Set the name of the manual page for the C<.TH> macro. Without this +option, the manual name is set to the uppercased base name of the file +being converted unless the manual section is 3, in which case the path is +parsed to see if it is a Perl module path. If it is, a path like +C<.../lib/Pod/Man.pm> is converted into a name like C. This +option, if given, overrides any automatic determination of the name. + +If generating a manual page from standard input, the name will be set to +C if this option is not provided. Providing this option is strongly +recommended to set a meaningful manual page name. + +=item nourls + +Normally, LZ<><> formatting codes with a URL but anchor text are formatted +to show both the anchor text and the URL. In other words: + + L + +is formatted as: + + foo + +This option, if set to a true value, suppresses the URL when anchor text +is given, so this example would be formatted as just C. This can +produce less cluttered output in cases where the URLs are not particularly +important. + +=item quotes + +Sets the quote marks used to surround CE> text. If the value is a +single character, it is used as both the left and right quote. Otherwise, +it is split in half, and the first half of the string is used as the left +quote and the second is used as the right quote. + +This may also be set to the special value C, in which case no quote +marks are added around CE> text (but the font is still changed for troff +output). + +Also see the C and C options, which can be used to set the +left and right quotes independently. If both C and one of the other +options is set, C or C overrides C. + +=item release + +Set the centered footer for the C<.TH> macro. By default, this is set to +the version of Perl you run Pod::Man under. Setting this to the empty +string will cause some *roff implementations to use the system default +value. + +Note that some system C macro sets assume that the centered footer +will be a modification date and will prepend something like "Last +modified: ". If this is the case for your target system, you may want to +set C to the last modified date and C to the version +number. + +=item section + +Set the section for the C<.TH> macro. The standard section numbering +convention is to use 1 for user commands, 2 for system calls, 3 for +functions, 4 for devices, 5 for file formats, 6 for games, 7 for +miscellaneous information, and 8 for administrator commands. There is a lot +of variation here, however; some systems (like Solaris) use 4 for file +formats, 5 for miscellaneous information, and 7 for devices. Still others +use 1m instead of 8, or some mix of both. About the only section numbers +that are reliably consistent are 1, 2, and 3. + +By default, section 1 will be used unless the file ends in C<.pm> in which +case section 3 will be selected. + +=item stderr + +Send error messages about invalid POD to standard error instead of +appending a POD ERRORS section to the generated *roff output. This is +equivalent to setting C to C if C is not already +set. It is supported for backward compatibility. + +=item utf8 + +By default, Pod::Man produces the most conservative possible *roff output +to try to ensure that it will work with as many different *roff +implementations as possible. Many *roff implementations cannot handle +non-ASCII characters, so this means all non-ASCII characters are converted +either to a *roff escape sequence that tries to create a properly accented +character (at least for troff output) or to C. + +If this option is set, Pod::Man will instead output UTF-8. If your *roff +implementation can handle it, this is the best output format to use and +avoids corruption of documents containing non-ASCII characters. However, +be warned that *roff source with literal UTF-8 characters is not supported +by many implementations and may even result in segfaults and other bad +behavior. + +Be aware that, when using this option, the input encoding of your POD +source should be properly declared unless it's US-ASCII. Pod::Simple will +attempt to guess the encoding and may be successful if it's Latin-1 or +UTF-8, but it will produce warnings. Use the C<=encoding> command to +declare the encoding. See L for more information. + +=back + +The standard Pod::Simple method parse_file() takes one argument naming the +POD file to read from. By default, the output is sent to C, but +this can be changed with the output_fh() method. + +The standard Pod::Simple method parse_from_file() takes up to two +arguments, the first being the input file to read POD from and the second +being the file to write the formatted output to. + +You can also call parse_lines() to parse an array of lines or +parse_string_document() to parse a document already in memory. As with +parse_file(), parse_lines() and parse_string_document() default to sending +their output to C unless changed with the output_fh() method. + +To put the output from any parse method into a string instead of a file +handle, call the output_string() method instead of output_fh(). + +See L for more specific details on the methods available to +all derived parsers. + +=head1 DIAGNOSTICS + +=over 4 + +=item roff font should be 1 or 2 chars, not "%s" + +(F) You specified a *roff font (using C, C, etc.) that +wasn't either one or two characters. Pod::Man doesn't support *roff fonts +longer than two characters, although some *roff extensions do (the +canonical versions of B and B don't either). + +=item Invalid errors setting "%s" + +(F) The C parameter to the constructor was set to an unknown value. + +=item Invalid quote specification "%s" + +(F) The quote specification given (the C option to the +constructor) was invalid. A quote specification must be either one +character long or an even number (greater than one) characters long. + +=item POD document had syntax errors + +(F) The POD document being formatted had syntax errors and the C +option was set to C. + +=back + +=head1 ENVIRONMENT + +=over 4 + +=item PERL_CORE + +If set and Encode is not available, silently fall back to non-UTF-8 mode +without complaining to standard error. This environment variable is set +during Perl core builds, which build Encode after podlators. Encode is +expected to not (yet) be available in that case. + +=item POD_MAN_DATE + +If set, this will be used as the value of the left-hand footer unless the +C option is explicitly set, overriding the timestamp of the input +file or the current time. This is primarily useful to ensure reproducible +builds of the same output file given the same source and Pod::Man version, +even when file timestamps may not be consistent. + +=item SOURCE_DATE_EPOCH + +If set, and POD_MAN_DATE and the C options are not set, this will be +used as the modification time of the source file, overriding the timestamp of +the input file or the current time. It should be set to the desired time in +seconds since UNIX epoch. This is primarily useful to ensure reproducible +builds of the same output file given the same source and Pod::Man version, +even when file timestamps may not be consistent. See +L for the full +specification. + +(Arguably, according to the specification, this variable should be used only +if the timestamp of the input file is not available and Pod::Man uses the +current time. However, for reproducible builds in Debian, results were more +reliable if this variable overrode the timestamp of the input file.) + +=back + +=head1 BUGS + +Encoding handling assumes that PerlIO is available and does not work +properly if it isn't. The C option is therefore not supported +unless Perl is built with PerlIO support. + +There is currently no way to turn off the guesswork that tries to format +unmarked text appropriately, and sometimes it isn't wanted (particularly +when using POD to document something other than Perl). Most of the work +toward fixing this has now been done, however, and all that's still needed +is a user interface. + +The NAME section should be recognized specially and index entries emitted +for everything in that section. This would have to be deferred until the +next section, since extraneous things in NAME tends to confuse various man +page processors. Currently, no index entries are emitted for anything in +NAME. + +Pod::Man doesn't handle font names longer than two characters. Neither do +most B implementations, but GNU troff does as an extension. It would +be nice to support as an option for those who want to use it. + +The preamble added to each output file is rather verbose, and most of it +is only necessary in the presence of non-ASCII characters. It would +ideally be nice if all of those definitions were only output if needed, +perhaps on the fly as the characters are used. + +Pod::Man is excessively slow. + +=head1 CAVEATS + +If Pod::Man is given the C option, the encoding of its output file +handle will be forced to UTF-8 if possible, overriding any existing +encoding. This will be done even if the file handle is not created by +Pod::Man and was passed in from outside. This maintains consistency +regardless of PERL_UNICODE and other settings. + +The handling of hyphens and em dashes is somewhat fragile, and one may get +the wrong one under some circumstances. This should only matter for +B output. + +When and whether to use small caps is somewhat tricky, and Pod::Man doesn't +necessarily get it right. + +Converting neutral double quotes to properly matched double quotes doesn't +work unless there are no formatting codes between the quote marks. This +only matters for troff output. + +=head1 AUTHOR + +Russ Allbery , based I heavily on the original B +by Tom Christiansen . The modifications to work with +Pod::Simple instead of Pod::Parser were originally contributed by Sean Burke + (but I've since hacked them beyond recognition and all bugs +are mine). + +=head1 COPYRIGHT AND LICENSE + +Copyright 1999-2010, 2012-2018 Russ Allbery + +Substantial contributions by Sean Burke . + +This program is free software; you may redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L, L, L, L, L, +L, L + +Ossanna, Joseph F., and Brian W. Kernighan. "Troff User's Manual," +Computing Science Technical Report No. 54, AT&T Bell Laboratories. This is +the best documentation of standard B and B. At the time of +this writing, it's available at L. + +The man page documenting the man macro set may be L instead of +L on your system. Also, please see L for extensive +documentation on writing manual pages if you've not done it before and +aren't familiar with the conventions. + +The current version of this module is always available from its web site at +L. It is also part of the +Perl core distribution as of 5.6.0. + +=cut + +# Local Variables: +# copyright-at-end-flag: t +# End: diff --git a/lib/Pod/ParseLink.pm b/lib/Pod/ParseLink.pm new file mode 100644 index 0000000..0be5323 --- /dev/null +++ b/lib/Pod/ParseLink.pm @@ -0,0 +1,190 @@ +# Parse an L<> formatting code in POD text. +# +# This module implements parsing of the text of an L<> formatting code as +# defined in perlpodspec. It should be suitable for any POD formatter. It +# exports only one function, parselink(), which returns the five-item parse +# defined in perlpodspec. +# +# SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl + +############################################################################## +# Modules and declarations +############################################################################## + +package Pod::ParseLink; + +use 5.006; +use strict; +use warnings; + +use vars qw(@EXPORT @ISA $VERSION); + +use Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(parselink); + +$VERSION = '4.11'; + +############################################################################## +# Implementation +############################################################################## + +# Parse the name and section portion of a link into a name and section. +sub _parse_section { + my ($link) = @_; + $link =~ s/^\s+//; + $link =~ s/\s+$//; + + # If the whole link is enclosed in quotes, interpret it all as a section + # even if it contains a slash. + return (undef, $1) if ($link =~ /^"\s*(.*?)\s*"$/); + + # Split into page and section on slash, and then clean up quoting in the + # section. If there is no section and the name contains spaces, also + # guess that it's an old section link. + my ($page, $section) = split (/\s*\/\s*/, $link, 2); + $section =~ s/^"\s*(.*?)\s*"$/$1/ if $section; + if ($page && $page =~ / / && !defined ($section)) { + $section = $page; + $page = undef; + } else { + $page = undef unless $page; + $section = undef unless $section; + } + return ($page, $section); +} + +# Infer link text from the page and section. +sub _infer_text { + my ($page, $section) = @_; + my $inferred; + if ($page && !$section) { + $inferred = $page; + } elsif (!$page && $section) { + $inferred = '"' . $section . '"'; + } elsif ($page && $section) { + $inferred = '"' . $section . '" in ' . $page; + } + return $inferred; +} + +# Given the contents of an L<> formatting code, parse it into the link text, +# the possibly inferred link text, the name or URL, the section, and the type +# of link (pod, man, or url). +sub parselink { + my ($link) = @_; + $link =~ s/\s+/ /g; + my $text; + if ($link =~ /\|/) { + ($text, $link) = split (/\|/, $link, 2); + } + if ($link =~ /\A\w+:[^:\s]\S*\Z/) { + my $inferred; + if (defined ($text) && length ($text) > 0) { + return ($text, $text, $link, undef, 'url'); + } else { + return ($text, $link, $link, undef, 'url'); + } + } else { + my ($name, $section) = _parse_section ($link); + my $inferred; + if (defined ($text) && length ($text) > 0) { + $inferred = $text; + } else { + $inferred = _infer_text ($name, $section); + } + my $type = ($name && $name =~ /\(\S*\)/) ? 'man' : 'pod'; + return ($text, $inferred, $name, $section, $type); + } +} + +############################################################################## +# Module return value and documentation +############################################################################## + +# Ensure we evaluate to true. +1; +__END__ + +=for stopwords +markup Allbery URL + +=head1 NAME + +Pod::ParseLink - Parse an LEE formatting code in POD text + +=head1 SYNOPSIS + + use Pod::ParseLink; + my $link = get_link(); + my ($text, $inferred, $name, $section, $type) = parselink($link); + +=head1 DESCRIPTION + +This module only provides a single function, parselink(), which takes the +text of an LEE formatting code and parses it. It returns the +anchor text for the link (if any was given), the anchor text possibly +inferred from the name and section, the name or URL, the section if any, +and the type of link. The type will be one of C, C, or C, +indicating a URL, a link to a POD page, or a link to a Unix manual page. + +Parsing is implemented per L. For backward compatibility, +links where there is no section and name contains spaces, or links where the +entirety of the link (except for the anchor text if given) is enclosed in +double-quotes are interpreted as links to a section (LE/sectionE). + +The inferred anchor text is implemented per L: + + L => L + L => L<"section"|/section> + L => L<"section" in name|name/section> + +The name may contain embedded EEE and ZEE formatting codes, +and the section, anchor text, and inferred anchor text may contain any +formatting codes. Any double quotes around the section are removed as part +of the parsing, as is any leading or trailing whitespace. + +If the text of the LEE escape is entirely enclosed in double +quotes, it's interpreted as a link to a section for backward +compatibility. + +No attempt is made to resolve formatting codes. This must be done after +calling parselink() (since EEE formatting codes can be used to +escape characters that would otherwise be significant to the parser and +resolving them before parsing would result in an incorrect parse of a +formatting code like: + + LbarEslash> + +which should be interpreted as a link to the C POD page +and not as a link to the C section of the C POD page with an +anchor text of C. Note that not only the anchor text will need to +have formatting codes expanded, but so will the target of the link (to deal +with EEE and ZEE formatting codes), and special handling of +the section may be necessary depending on whether the translator wants to +consider markup in sections to be significant when resolving links. See +L for more information. + +=head1 AUTHOR + +Russ Allbery . + +=head1 COPYRIGHT AND LICENSE + +Copyright 2001, 2008, 2009, 2014, 2018 Russ Allbery + +This program is free software; you may redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L + +The current version of this module is always available from its web site at +L. + +=cut + +# Local Variables: +# copyright-at-end-flag: t +# End: diff --git a/lib/Pod/Text.pm b/lib/Pod/Text.pm new file mode 100644 index 0000000..b05730e --- /dev/null +++ b/lib/Pod/Text.pm @@ -0,0 +1,1027 @@ +# Convert POD data to formatted text. +# +# This module converts POD to formatted text. It replaces the old Pod::Text +# module that came with versions of Perl prior to 5.6.0 and attempts to match +# its output except for some specific circumstances where other decisions +# seemed to produce better output. It uses Pod::Parser and is designed to be +# very easy to subclass. +# +# SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl + +############################################################################## +# Modules and declarations +############################################################################## + +package Pod::Text; + +use 5.006; +use strict; +use warnings; + +use vars qw(@ISA @EXPORT %ESCAPES $VERSION); + +use Carp qw(carp croak); +use Encode qw(encode); +use Exporter (); +use Pod::Simple (); + +@ISA = qw(Pod::Simple Exporter); + +# We have to export pod2text for backward compatibility. +@EXPORT = qw(pod2text); + +$VERSION = '4.11'; + +# Ensure that $Pod::Simple::nbsp and $Pod::Simple::shy are available. Code +# taken from Pod::Simple 3.32, but was only added in 3.30. +my ($NBSP, $SHY); +if ($Pod::Simple::VERSION ge 3.30) { + $NBSP = $Pod::Simple::nbsp; + $SHY = $Pod::Simple::shy; +} else { + if ($] ge 5.007_003) { + $NBSP = chr utf8::unicode_to_native(0xA0); + $SHY = chr utf8::unicode_to_native(0xAD); + } elsif (Pod::Simple::ASCII) { + $NBSP = "\xA0"; + $SHY = "\xAD"; + } else { + $NBSP = "\x41"; + $SHY = "\xCA"; + } +} + +############################################################################## +# Initialization +############################################################################## + +# This function handles code blocks. It's registered as a callback to +# Pod::Simple and therefore doesn't work as a regular method call, but all it +# does is call output_code with the line. +sub handle_code { + my ($line, $number, $parser) = @_; + $parser->output_code ($line . "\n"); +} + +# Initialize the object and set various Pod::Simple options that we need. +# Here, we also process any additional options passed to the constructor or +# set up defaults if none were given. Note that all internal object keys are +# in all-caps, reserving all lower-case object keys for Pod::Simple and user +# arguments. +sub new { + my $class = shift; + my $self = $class->SUPER::new; + + # Tell Pod::Simple to handle S<> by automatically inserting  . + $self->nbsp_for_S (1); + + # Tell Pod::Simple to keep whitespace whenever possible. + if ($self->can ('preserve_whitespace')) { + $self->preserve_whitespace (1); + } else { + $self->fullstop_space_harden (1); + } + + # The =for and =begin targets that we accept. + $self->accept_targets (qw/text TEXT/); + + # Ensure that contiguous blocks of code are merged together. Otherwise, + # some of the guesswork heuristics don't work right. + $self->merge_text (1); + + # Pod::Simple doesn't do anything useful with our arguments, but we want + # to put them in our object as hash keys and values. This could cause + # problems if we ever clash with Pod::Simple's own internal class + # variables. + my %opts = @_; + my @opts = map { ("opt_$_", $opts{$_}) } keys %opts; + %$self = (%$self, @opts); + + # Send errors to stderr if requested. + if ($$self{opt_stderr} and not $$self{opt_errors}) { + $$self{opt_errors} = 'stderr'; + } + delete $$self{opt_stderr}; + + # Validate the errors parameter and act on it. + if (not defined $$self{opt_errors}) { + $$self{opt_errors} = 'pod'; + } + if ($$self{opt_errors} eq 'stderr' || $$self{opt_errors} eq 'die') { + $self->no_errata_section (1); + $self->complain_stderr (1); + if ($$self{opt_errors} eq 'die') { + $$self{complain_die} = 1; + } + } elsif ($$self{opt_errors} eq 'pod') { + $self->no_errata_section (0); + $self->complain_stderr (0); + } elsif ($$self{opt_errors} eq 'none') { + $self->no_errata_section (1); + $self->no_whining (1); + } else { + croak (qq(Invalid errors setting: "$$self{errors}")); + } + delete $$self{errors}; + + # Initialize various things from our parameters. + $$self{opt_alt} = 0 unless defined $$self{opt_alt}; + $$self{opt_indent} = 4 unless defined $$self{opt_indent}; + $$self{opt_margin} = 0 unless defined $$self{opt_margin}; + $$self{opt_loose} = 0 unless defined $$self{opt_loose}; + $$self{opt_sentence} = 0 unless defined $$self{opt_sentence}; + $$self{opt_width} = 76 unless defined $$self{opt_width}; + + # Figure out what quotes we'll be using for C<> text. + $$self{opt_quotes} ||= '"'; + if ($$self{opt_quotes} eq 'none') { + $$self{LQUOTE} = $$self{RQUOTE} = ''; + } elsif (length ($$self{opt_quotes}) == 1) { + $$self{LQUOTE} = $$self{RQUOTE} = $$self{opt_quotes}; + } elsif (length ($$self{opt_quotes}) % 2 == 0) { + my $length = length ($$self{opt_quotes}) / 2; + $$self{LQUOTE} = substr ($$self{opt_quotes}, 0, $length); + $$self{RQUOTE} = substr ($$self{opt_quotes}, $length); + } else { + croak qq(Invalid quote specification "$$self{opt_quotes}"); + } + + # If requested, do something with the non-POD text. + $self->code_handler (\&handle_code) if $$self{opt_code}; + + # Return the created object. + return $self; +} + +############################################################################## +# Core parsing +############################################################################## + +# This is the glue that connects the code below with Pod::Simple itself. The +# goal is to convert the event stream coming from the POD parser into method +# calls to handlers once the complete content of a tag has been seen. Each +# paragraph or POD command will have textual content associated with it, and +# as soon as all of a paragraph or POD command has been seen, that content +# will be passed in to the corresponding method for handling that type of +# object. The exceptions are handlers for lists, which have opening tag +# handlers and closing tag handlers that will be called right away. +# +# The internal hash key PENDING is used to store the contents of a tag until +# all of it has been seen. It holds a stack of open tags, each one +# represented by a tuple of the attributes hash for the tag and the contents +# of the tag. + +# Add a block of text to the contents of the current node, formatting it +# according to the current formatting instructions as we do. +sub _handle_text { + my ($self, $text) = @_; + my $tag = $$self{PENDING}[-1]; + $$tag[1] .= $text; +} + +# Given an element name, get the corresponding method name. +sub method_for_element { + my ($self, $element) = @_; + $element =~ tr/-/_/; + $element =~ tr/A-Z/a-z/; + $element =~ tr/_a-z0-9//cd; + return $element; +} + +# Handle the start of a new element. If cmd_element is defined, assume that +# we need to collect the entire tree for this element before passing it to the +# element method, and create a new tree into which we'll collect blocks of +# text and nested elements. Otherwise, if start_element is defined, call it. +sub _handle_element_start { + my ($self, $element, $attrs) = @_; + my $method = $self->method_for_element ($element); + + # If we have a command handler, we need to accumulate the contents of the + # tag before calling it. + if ($self->can ("cmd_$method")) { + push (@{ $$self{PENDING} }, [ $attrs, '' ]); + } elsif ($self->can ("start_$method")) { + my $method = 'start_' . $method; + $self->$method ($attrs, ''); + } +} + +# Handle the end of an element. If we had a cmd_ method for this element, +# this is where we pass along the text that we've accumulated. Otherwise, if +# we have an end_ method for the element, call that. +sub _handle_element_end { + my ($self, $element) = @_; + my $method = $self->method_for_element ($element); + + # If we have a command handler, pull off the pending text and pass it to + # the handler along with the saved attribute hash. + if ($self->can ("cmd_$method")) { + my $tag = pop @{ $$self{PENDING} }; + my $method = 'cmd_' . $method; + my $text = $self->$method (@$tag); + if (defined $text) { + if (@{ $$self{PENDING} } > 1) { + $$self{PENDING}[-1][1] .= $text; + } else { + $self->output ($text); + } + } + } elsif ($self->can ("end_$method")) { + my $method = 'end_' . $method; + $self->$method (); + } +} + +############################################################################## +# Output formatting +############################################################################## + +# Wrap a line, indenting by the current left margin. We can't use Text::Wrap +# because it plays games with tabs. We can't use formline, even though we'd +# really like to, because it screws up non-printing characters. So we have to +# do the wrapping ourselves. +sub wrap { + my $self = shift; + local $_ = shift; + my $output = ''; + my $spaces = ' ' x $$self{MARGIN}; + my $width = $$self{opt_width} - $$self{MARGIN}; + while (length > $width) { + if (s/^([^\n]{0,$width})\s+// || s/^([^\n]{$width})//) { + $output .= $spaces . $1 . "\n"; + } else { + last; + } + } + $output .= $spaces . $_; + $output =~ s/\s+$/\n\n/; + return $output; +} + +# Reformat a paragraph of text for the current margin. Takes the text to +# reformat and returns the formatted text. +sub reformat { + my $self = shift; + local $_ = shift; + + # If we're trying to preserve two spaces after sentences, do some munging + # to support that. Otherwise, smash all repeated whitespace. + if ($$self{opt_sentence}) { + s/ +$//mg; + s/\.\n/. \n/g; + s/\n/ /g; + s/ +/ /g; + } else { + s/\s+/ /g; + } + return $self->wrap ($_); +} + +# Output text to the output device. Replace non-breaking spaces with spaces +# and soft hyphens with nothing, and then try to fix the output encoding if +# necessary to match the input encoding unless UTF-8 output is forced. This +# preserves the traditional pass-through behavior of Pod::Text. +sub output { + my ($self, @text) = @_; + my $text = join ('', @text); + if ($NBSP) { + $text =~ s/$NBSP/ /g; + } + if ($SHY) { + $text =~ s/$SHY//g; + } + unless ($$self{opt_utf8}) { + my $encoding = $$self{encoding} || ''; + if ($encoding && $encoding ne $$self{ENCODING}) { + $$self{ENCODING} = $encoding; + eval { binmode ($$self{output_fh}, ":encoding($encoding)") }; + } + } + if ($$self{ENCODE}) { + print { $$self{output_fh} } encode ('UTF-8', $text); + } else { + print { $$self{output_fh} } $text; + } +} + +# Output a block of code (something that isn't part of the POD text). Called +# by preprocess_paragraph only if we were given the code option. Exists here +# only so that it can be overridden by subclasses. +sub output_code { $_[0]->output ($_[1]) } + +############################################################################## +# Document initialization +############################################################################## + +# Set up various things that have to be initialized on a per-document basis. +sub start_document { + my ($self, $attrs) = @_; + if ($$attrs{contentless} && !$$self{ALWAYS_EMIT_SOMETHING}) { + $$self{CONTENTLESS} = 1; + } else { + delete $$self{CONTENTLESS}; + } + my $margin = $$self{opt_indent} + $$self{opt_margin}; + + # Initialize a few per-document variables. + $$self{INDENTS} = []; # Stack of indentations. + $$self{MARGIN} = $margin; # Default left margin. + $$self{PENDING} = [[]]; # Pending output. + + # We have to redo encoding handling for each document. + $$self{ENCODING} = ''; + + # When UTF-8 output is set, check whether our output file handle already + # has a PerlIO encoding layer set. If it does not, we'll need to encode + # our output before printing it (handled in the output() sub). Wrap the + # check in an eval to handle versions of Perl without PerlIO. + $$self{ENCODE} = 0; + if ($$self{opt_utf8}) { + $$self{ENCODE} = 1; + eval { + my @options = (output => 1, details => 1); + my $flag = (PerlIO::get_layers ($$self{output_fh}, @options))[-1]; + if ($flag & PerlIO::F_UTF8 ()) { + $$self{ENCODE} = 0; + $$self{ENCODING} = 'UTF-8'; + } + }; + } + + return ''; +} + +# Handle the end of the document. The only thing we do is handle dying on POD +# errors, since Pod::Parser currently doesn't. +sub end_document { + my ($self) = @_; + if ($$self{complain_die} && $self->errors_seen) { + croak ("POD document had syntax errors"); + } +} + +############################################################################## +# Text blocks +############################################################################## + +# Intended for subclasses to override, this method returns text with any +# non-printing formatting codes stripped out so that length() correctly +# returns the length of the text. For basic Pod::Text, it does nothing. +sub strip_format { + my ($self, $string) = @_; + return $string; +} + +# This method is called whenever an =item command is complete (in other words, +# we've seen its associated paragraph or know for certain that it doesn't have +# one). It gets the paragraph associated with the item as an argument. If +# that argument is empty, just output the item tag; if it contains a newline, +# output the item tag followed by the newline. Otherwise, see if there's +# enough room for us to output the item tag in the margin of the text or if we +# have to put it on a separate line. +sub item { + my ($self, $text) = @_; + my $tag = $$self{ITEM}; + unless (defined $tag) { + carp "Item called without tag"; + return; + } + undef $$self{ITEM}; + + # Calculate the indentation and margin. $fits is set to true if the tag + # will fit into the margin of the paragraph given our indentation level. + my $indent = $$self{INDENTS}[-1]; + $indent = $$self{opt_indent} unless defined $indent; + my $margin = ' ' x $$self{opt_margin}; + my $tag_length = length ($self->strip_format ($tag)); + my $fits = ($$self{MARGIN} - $indent >= $tag_length + 1); + + # If the tag doesn't fit, or if we have no associated text, print out the + # tag separately. Otherwise, put the tag in the margin of the paragraph. + if (!$text || $text =~ /^\s+$/ || !$fits) { + my $realindent = $$self{MARGIN}; + $$self{MARGIN} = $indent; + my $output = $self->reformat ($tag); + $output =~ s/^$margin /$margin:/ if ($$self{opt_alt} && $indent > 0); + $output =~ s/\n*$/\n/; + + # If the text is just whitespace, we have an empty item paragraph; + # this can result from =over/=item/=back without any intermixed + # paragraphs. Insert some whitespace to keep the =item from merging + # into the next paragraph. + $output .= "\n" if $text && $text =~ /^\s*$/; + + $self->output ($output); + $$self{MARGIN} = $realindent; + $self->output ($self->reformat ($text)) if ($text && $text =~ /\S/); + } else { + my $space = ' ' x $indent; + $space =~ s/^$margin /$margin:/ if $$self{opt_alt}; + $text = $self->reformat ($text); + $text =~ s/^$margin /$margin:/ if ($$self{opt_alt} && $indent > 0); + my $tagspace = ' ' x $tag_length; + $text =~ s/^($space)$tagspace/$1$tag/ or warn "Bizarre space in item"; + $self->output ($text); + } +} + +# Handle a basic block of text. The only tricky thing here is that if there +# is a pending item tag, we need to format this as an item paragraph. +sub cmd_para { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$/\n/; + if (defined $$self{ITEM}) { + $self->item ($text . "\n"); + } else { + $self->output ($self->reformat ($text . "\n")); + } + return ''; +} + +# Handle a verbatim paragraph. Just print it out, but indent it according to +# our margin. +sub cmd_verbatim { + my ($self, $attrs, $text) = @_; + $self->item if defined $$self{ITEM}; + return if $text =~ /^\s*$/; + $text =~ s/^(\n*)([ \t]*\S+)/$1 . (' ' x $$self{MARGIN}) . $2/gme; + $text =~ s/\s*$/\n\n/; + $self->output ($text); + return ''; +} + +# Handle literal text (produced by =for and similar constructs). Just output +# it with the minimum of changes. +sub cmd_data { + my ($self, $attrs, $text) = @_; + $text =~ s/^\n+//; + $text =~ s/\n{0,2}$/\n/; + $self->output ($text); + return ''; +} + +############################################################################## +# Headings +############################################################################## + +# The common code for handling all headers. Takes the header text, the +# indentation, and the surrounding marker for the alt formatting method. +sub heading { + my ($self, $text, $indent, $marker) = @_; + $self->item ("\n\n") if defined $$self{ITEM}; + $text =~ s/\s+$//; + if ($$self{opt_alt}) { + my $closemark = reverse (split (//, $marker)); + my $margin = ' ' x $$self{opt_margin}; + $self->output ("\n" . "$margin$marker $text $closemark" . "\n\n"); + } else { + $text .= "\n" if $$self{opt_loose}; + my $margin = ' ' x ($$self{opt_margin} + $indent); + $self->output ($margin . $text . "\n"); + } + return ''; +} + +# First level heading. +sub cmd_head1 { + my ($self, $attrs, $text) = @_; + $self->heading ($text, 0, '===='); +} + +# Second level heading. +sub cmd_head2 { + my ($self, $attrs, $text) = @_; + $self->heading ($text, $$self{opt_indent} / 2, '== '); +} + +# Third level heading. +sub cmd_head3 { + my ($self, $attrs, $text) = @_; + $self->heading ($text, $$self{opt_indent} * 2 / 3 + 0.5, '= '); +} + +# Fourth level heading. +sub cmd_head4 { + my ($self, $attrs, $text) = @_; + $self->heading ($text, $$self{opt_indent} * 3 / 4 + 0.5, '- '); +} + +############################################################################## +# List handling +############################################################################## + +# Handle the beginning of an =over block. Takes the type of the block as the +# first argument, and then the attr hash. This is called by the handlers for +# the four different types of lists (bullet, number, text, and block). +sub over_common_start { + my ($self, $attrs) = @_; + $self->item ("\n\n") if defined $$self{ITEM}; + + # Find the indentation level. + my $indent = $$attrs{indent}; + unless (defined ($indent) && $indent =~ /^\s*[-+]?\d{1,4}\s*$/) { + $indent = $$self{opt_indent}; + } + + # Add this to our stack of indents and increase our current margin. + push (@{ $$self{INDENTS} }, $$self{MARGIN}); + $$self{MARGIN} += ($indent + 0); + return ''; +} + +# End an =over block. Takes no options other than the class pointer. Output +# any pending items and then pop one level of indentation. +sub over_common_end { + my ($self) = @_; + $self->item ("\n\n") if defined $$self{ITEM}; + $$self{MARGIN} = pop @{ $$self{INDENTS} }; + return ''; +} + +# Dispatch the start and end calls as appropriate. +sub start_over_bullet { $_[0]->over_common_start ($_[1]) } +sub start_over_number { $_[0]->over_common_start ($_[1]) } +sub start_over_text { $_[0]->over_common_start ($_[1]) } +sub start_over_block { $_[0]->over_common_start ($_[1]) } +sub end_over_bullet { $_[0]->over_common_end } +sub end_over_number { $_[0]->over_common_end } +sub end_over_text { $_[0]->over_common_end } +sub end_over_block { $_[0]->over_common_end } + +# The common handler for all item commands. Takes the type of the item, the +# attributes, and then the text of the item. +sub item_common { + my ($self, $type, $attrs, $text) = @_; + $self->item if defined $$self{ITEM}; + + # Clean up the text. We want to end up with two variables, one ($text) + # which contains any body text after taking out the item portion, and + # another ($item) which contains the actual item text. Note the use of + # the internal Pod::Simple attribute here; that's a potential land mine. + $text =~ s/\s+$//; + my ($item, $index); + if ($type eq 'bullet') { + $item = '*'; + } elsif ($type eq 'number') { + $item = $$attrs{'~orig_content'}; + } else { + $item = $text; + $item =~ s/\s*\n\s*/ /g; + $text = ''; + } + $$self{ITEM} = $item; + + # If body text for this item was included, go ahead and output that now. + if ($text) { + $text =~ s/\s*$/\n/; + $self->item ($text); + } + return ''; +} + +# Dispatch the item commands to the appropriate place. +sub cmd_item_bullet { my $self = shift; $self->item_common ('bullet', @_) } +sub cmd_item_number { my $self = shift; $self->item_common ('number', @_) } +sub cmd_item_text { my $self = shift; $self->item_common ('text', @_) } +sub cmd_item_block { my $self = shift; $self->item_common ('block', @_) } + +############################################################################## +# Formatting codes +############################################################################## + +# The simple ones. +sub cmd_b { return $_[0]{alt} ? "``$_[2]''" : $_[2] } +sub cmd_f { return $_[0]{alt} ? "\"$_[2]\"" : $_[2] } +sub cmd_i { return '*' . $_[2] . '*' } +sub cmd_x { return '' } + +# Apply a whole bunch of messy heuristics to not quote things that don't +# benefit from being quoted. These originally come from Barrie Slaymaker and +# largely duplicate code in Pod::Man. +sub cmd_c { + my ($self, $attrs, $text) = @_; + + # A regex that matches the portion of a variable reference that's the + # array or hash index, separated out just because we want to use it in + # several places in the following regex. + my $index = '(?: \[.*\] | \{.*\} )?'; + + # Check for things that we don't want to quote, and if we find any of + # them, return the string with just a font change and no quoting. + $text =~ m{ + ^\s* + (?: + ( [\'\`\"] ) .* \1 # already quoted + | \` .* \' # `quoted' + | \$+ [\#^]? \S $index # special ($^Foo, $") + | [\$\@%&*]+ \#? [:\'\w]+ $index # plain var or func + | [\$\@%&*]* [:\'\w]+ (?: -> )? \(\s*[^\s,]\s*\) # 0/1-arg func call + | [+-]? ( \d[\d.]* | \.\d+ ) (?: [eE][+-]?\d+ )? # a number + | 0x [a-fA-F\d]+ # a hex constant + ) + \s*\z + }xo && return $text; + + # If we didn't return, go ahead and quote the text. + return $$self{opt_alt} + ? "``$text''" + : "$$self{LQUOTE}$text$$self{RQUOTE}"; +} + +# Links reduce to the text that we're given, wrapped in angle brackets if it's +# a URL. +sub cmd_l { + my ($self, $attrs, $text) = @_; + if ($$attrs{type} eq 'url') { + if (not defined($$attrs{to}) or $$attrs{to} eq $text) { + return "<$text>"; + } elsif ($$self{opt_nourls}) { + return $text; + } else { + return "$text <$$attrs{to}>"; + } + } else { + return $text; + } +} + +############################################################################## +# Backwards compatibility +############################################################################## + +# The old Pod::Text module did everything in a pod2text() function. This +# tries to provide the same interface for legacy applications. +sub pod2text { + my @args; + + # This is really ugly; I hate doing option parsing in the middle of a + # module. But the old Pod::Text module supported passing flags to its + # entry function, so handle -a and -. + while ($_[0] =~ /^-/) { + my $flag = shift; + if ($flag eq '-a') { push (@args, alt => 1) } + elsif ($flag =~ /^-(\d+)$/) { push (@args, width => $1) } + else { + unshift (@_, $flag); + last; + } + } + + # Now that we know what arguments we're using, create the parser. + my $parser = Pod::Text->new (@args); + + # If two arguments were given, the second argument is going to be a file + # handle. That means we want to call parse_from_filehandle(), which means + # we need to turn the first argument into a file handle. Magic open will + # handle the <&STDIN case automagically. + if (defined $_[1]) { + my @fhs = @_; + local *IN; + unless (open (IN, $fhs[0])) { + croak ("Can't open $fhs[0] for reading: $!\n"); + return; + } + $fhs[0] = \*IN; + $parser->output_fh ($fhs[1]); + my $retval = $parser->parse_file ($fhs[0]); + my $fh = $parser->output_fh (); + close $fh; + return $retval; + } else { + $parser->output_fh (\*STDOUT); + return $parser->parse_file (@_); + } +} + +# Reset the underlying Pod::Simple object between calls to parse_from_file so +# that the same object can be reused to convert multiple pages. +sub parse_from_file { + my $self = shift; + $self->reinit; + + # Fake the old cutting option to Pod::Parser. This fiddles with internal + # Pod::Simple state and is quite ugly; we need a better approach. + if (ref ($_[0]) eq 'HASH') { + my $opts = shift @_; + if (defined ($$opts{-cutting}) && !$$opts{-cutting}) { + $$self{in_pod} = 1; + $$self{last_was_blank} = 1; + } + } + + # Do the work. + my $retval = $self->Pod::Simple::parse_from_file (@_); + + # Flush output, since Pod::Simple doesn't do this. Ideally we should also + # close the file descriptor if we had to open one, but we can't easily + # figure this out. + my $fh = $self->output_fh (); + my $oldfh = select $fh; + my $oldflush = $|; + $| = 1; + print $fh ''; + $| = $oldflush; + select $oldfh; + return $retval; +} + +# Pod::Simple failed to provide this backward compatibility function, so +# implement it ourselves. File handles are one of the inputs that +# parse_from_file supports. +sub parse_from_filehandle { + my $self = shift; + $self->parse_from_file (@_); +} + +# Pod::Simple's parse_file doesn't set output_fh. Wrap the call and do so +# ourself unless it was already set by the caller, since our documentation has +# always said that this should work. +sub parse_file { + my ($self, $in) = @_; + unless (defined $$self{output_fh}) { + $self->output_fh (\*STDOUT); + } + return $self->SUPER::parse_file ($in); +} + +# Do the same for parse_lines, just to be polite. Pod::Simple's man page +# implies that the caller is responsible for setting this, but I don't see any +# reason not to set a default. +sub parse_lines { + my ($self, @lines) = @_; + unless (defined $$self{output_fh}) { + $self->output_fh (\*STDOUT); + } + return $self->SUPER::parse_lines (@lines); +} + +# Likewise for parse_string_document. +sub parse_string_document { + my ($self, $doc) = @_; + unless (defined $$self{output_fh}) { + $self->output_fh (\*STDOUT); + } + return $self->SUPER::parse_string_document ($doc); +} + +############################################################################## +# Module return value and documentation +############################################################################## + +1; +__END__ + +=for stopwords +alt stderr Allbery Sean Burke's Christiansen UTF-8 pre-Unicode utf8 nourls +parsers + +=head1 NAME + +Pod::Text - Convert POD data to formatted text + +=head1 SYNOPSIS + + use Pod::Text; + my $parser = Pod::Text->new (sentence => 1, width => 78); + + # Read POD from STDIN and write to STDOUT. + $parser->parse_from_filehandle; + + # Read POD from file.pod and write to file.txt. + $parser->parse_from_file ('file.pod', 'file.txt'); + +=head1 DESCRIPTION + +Pod::Text is a module that can convert documentation in the POD format +(the preferred language for documenting Perl) into formatted text. It +uses no special formatting controls or codes whatsoever, and its output is +therefore suitable for nearly any device. + +As a derived class from Pod::Simple, Pod::Text supports the same methods and +interfaces. See L for all the details; briefly, one creates a +new parser with C<< Pod::Text->new() >> and then normally calls parse_file(). + +new() can take options, in the form of key/value pairs, that control the +behavior of the parser. The currently recognized options are: + +=over 4 + +=item alt + +If set to a true value, selects an alternate output format that, among other +things, uses a different heading style and marks C<=item> entries with a +colon in the left margin. Defaults to false. + +=item code + +If set to a true value, the non-POD parts of the input file will be included +in the output. Useful for viewing code documented with POD blocks with the +POD rendered and the code left intact. + +=item errors + +How to report errors. C says to throw an exception on any POD +formatting error. C says to report errors on standard error, but +not to throw an exception. C says to include a POD ERRORS section +in the resulting documentation summarizing the errors. C ignores +POD errors entirely, as much as possible. + +The default is C. + +=item indent + +The number of spaces to indent regular text, and the default indentation for +C<=over> blocks. Defaults to 4. + +=item loose + +If set to a true value, a blank line is printed after a C<=head1> heading. +If set to false (the default), no blank line is printed after C<=head1>, +although one is still printed after C<=head2>. This is the default because +it's the expected formatting for manual pages; if you're formatting +arbitrary text documents, setting this to true may result in more pleasing +output. + +=item margin + +The width of the left margin in spaces. Defaults to 0. This is the margin +for all text, including headings, not the amount by which regular text is +indented; for the latter, see the I option. To set the right +margin, see the I option. + +=item nourls + +Normally, LZ<><> formatting codes with a URL but anchor text are formatted +to show both the anchor text and the URL. In other words: + + L + +is formatted as: + + foo + +This option, if set to a true value, suppresses the URL when anchor text +is given, so this example would be formatted as just C. This can +produce less cluttered output in cases where the URLs are not particularly +important. + +=item quotes + +Sets the quote marks used to surround CE> text. If the value is a +single character, it is used as both the left and right quote. Otherwise, +it is split in half, and the first half of the string is used as the left +quote and the second is used as the right quote. + +This may also be set to the special value C, in which case no quote +marks are added around CE> text. + +=item sentence + +If set to a true value, Pod::Text will assume that each sentence ends in two +spaces, and will try to preserve that spacing. If set to false, all +consecutive whitespace in non-verbatim paragraphs is compressed into a +single space. Defaults to false. + +=item stderr + +Send error messages about invalid POD to standard error instead of +appending a POD ERRORS section to the generated output. This is +equivalent to setting C to C if C is not already +set. It is supported for backward compatibility. + +=item utf8 + +By default, Pod::Text uses the same output encoding as the input encoding +of the POD source (provided that Perl was built with PerlIO; otherwise, it +doesn't encode its output). If this option is given, the output encoding +is forced to UTF-8. + +Be aware that, when using this option, the input encoding of your POD +source should be properly declared unless it's US-ASCII. Pod::Simple will +attempt to guess the encoding and may be successful if it's Latin-1 or +UTF-8, but it will produce warnings. Use the C<=encoding> command to +declare the encoding. See L for more information. + +=item width + +The column at which to wrap text on the right-hand side. Defaults to 76. + +=back + +The standard Pod::Simple method parse_file() takes one argument naming the +POD file to read from. By default, the output is sent to C, but +this can be changed with the output_fh() method. + +The standard Pod::Simple method parse_from_file() takes up to two +arguments, the first being the input file to read POD from and the second +being the file to write the formatted output to. + +You can also call parse_lines() to parse an array of lines or +parse_string_document() to parse a document already in memory. As with +parse_file(), parse_lines() and parse_string_document() default to sending +their output to C unless changed with the output_fh() method. + +To put the output from any parse method into a string instead of a file +handle, call the output_string() method instead of output_fh(). + +See L for more specific details on the methods available to +all derived parsers. + +=head1 DIAGNOSTICS + +=over 4 + +=item Bizarre space in item + +=item Item called without tag + +(W) Something has gone wrong in internal C<=item> processing. These +messages indicate a bug in Pod::Text; you should never see them. + +=item Can't open %s for reading: %s + +(F) Pod::Text was invoked via the compatibility mode pod2text() interface +and the input file it was given could not be opened. + +=item Invalid errors setting "%s" + +(F) The C parameter to the constructor was set to an unknown value. + +=item Invalid quote specification "%s" + +(F) The quote specification given (the C option to the +constructor) was invalid. A quote specification must be either one +character long or an even number (greater than one) characters long. + +=item POD document had syntax errors + +(F) The POD document being formatted had syntax errors and the C +option was set to C. + +=back + +=head1 BUGS + +Encoding handling assumes that PerlIO is available and does not work +properly if it isn't. The C option is therefore not supported +unless Perl is built with PerlIO support. + +=head1 CAVEATS + +If Pod::Text is given the C option, the encoding of its output file +handle will be forced to UTF-8 if possible, overriding any existing +encoding. This will be done even if the file handle is not created by +Pod::Text and was passed in from outside. This maintains consistency +regardless of PERL_UNICODE and other settings. + +If the C option is not given, the encoding of its output file handle +will be forced to the detected encoding of the input POD, which preserves +whatever the input text is. This ensures backward compatibility with +earlier, pre-Unicode versions of this module, without large numbers of +Perl warnings. + +This is not ideal, but it seems to be the best compromise. If it doesn't +work for you, please let me know the details of how it broke. + +=head1 NOTES + +This is a replacement for an earlier Pod::Text module written by Tom +Christiansen. It has a revamped interface, since it now uses Pod::Simple, +but an interface roughly compatible with the old Pod::Text::pod2text() +function is still available. Please change to the new calling convention, +though. + +The original Pod::Text contained code to do formatting via termcap +sequences, although it wasn't turned on by default and it was problematic to +get it to work at all. This rewrite doesn't even try to do that, but a +subclass of it does. Look for L. + +=head1 AUTHOR + +Russ Allbery , based I heavily on the original +Pod::Text by Tom Christiansen and its conversion to +Pod::Parser by Brad Appleton . Sean Burke's initial +conversion of Pod::Man to use Pod::Simple provided much-needed guidance on +how to use Pod::Simple. + +=head1 COPYRIGHT AND LICENSE + +Copyright 1999-2002, 2004, 2006, 2008-2009, 2012-2016, 2018 Russ Allbery + + +This program is free software; you may redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L, L, L, L + +The current version of this module is always available from its web site at +L. It is also part of the +Perl core distribution as of 5.6.0. + +=cut + +# Local Variables: +# copyright-at-end-flag: t +# End: diff --git a/lib/Pod/Text/Color.pm b/lib/Pod/Text/Color.pm new file mode 100644 index 0000000..8d956f2 --- /dev/null +++ b/lib/Pod/Text/Color.pm @@ -0,0 +1,206 @@ +# Convert POD data to formatted color ASCII text +# +# This is just a basic proof of concept. It should later be modified to make +# better use of color, take options changing what colors are used for what +# text, and the like. +# +# SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl + +############################################################################## +# Modules and declarations +############################################################################## + +package Pod::Text::Color; + +use 5.006; +use strict; +use warnings; + +use Pod::Text (); +use Term::ANSIColor qw(color colored); + +use vars qw(@ISA $VERSION); + +@ISA = qw(Pod::Text); + +$VERSION = '4.11'; + +############################################################################## +# Overrides +############################################################################## + +# Make level one headings bold. +sub cmd_head1 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + local $Term::ANSIColor::EACHLINE = "\n"; + $self->SUPER::cmd_head1 ($attrs, colored ($text, 'bold')); +} + +# Make level two headings bold. +sub cmd_head2 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $self->SUPER::cmd_head2 ($attrs, colored ($text, 'bold')); +} + +# Fix the various formatting codes. +sub cmd_b { return colored ($_[2], 'bold') } +sub cmd_f { return colored ($_[2], 'cyan') } +sub cmd_i { return colored ($_[2], 'yellow') } + +# Analyze a single line and return any formatting codes in effect at the end +# of that line. +sub end_format { + my ($self, $line) = @_; + my $reset = color ('reset'); + my $current; + while ($line =~ /(\e\[[\d;]+m)/g) { + my $code = $1; + if ($code eq $reset) { + undef $current; + } else { + $current .= $code; + } + } + return $current; +} + +# Output any included code in green. +sub output_code { + my ($self, $code) = @_; + local $Term::ANSIColor::EACHLINE = "\n"; + $code = colored ($code, 'green'); + $self->output ($code); +} + +# Strip all of the formatting from a provided string, returning the stripped +# version. We will eventually want to use colorstrip() from Term::ANSIColor, +# but it's fairly new so avoid the tight dependency. +sub strip_format { + my ($self, $text) = @_; + $text =~ s/\e\[[\d;]*m//g; + return $text; +} + +# We unfortunately have to override the wrapping code here, since the normal +# wrapping code gets really confused by all the escape sequences. +sub wrap { + my $self = shift; + local $_ = shift; + my $output = ''; + my $spaces = ' ' x $$self{MARGIN}; + my $width = $$self{opt_width} - $$self{MARGIN}; + + # $codes matches a single special sequence. $char matches any number of + # special sequences preceding a single character other than a newline. + # $shortchar matches some sequence of $char ending in codes followed by + # whitespace or the end of the string. $longchar matches exactly $width + # $chars, used when we have to truncate and hard wrap. + # + # $shortchar and $longchar are created in a slightly odd way because the + # construct ${char}{0,$width} didn't do the right thing until Perl 5.8.x. + my $code = '(?:\e\[[\d;]+m)'; + my $char = "(?>$code*[^\\n])"; + my $shortchar = '^(' . $char . "{0,$width}(?>$code*)" . ')(?:\s+|\z)'; + my $longchar = '^(' . $char . "{$width})"; + while (length > $width) { + if (s/$shortchar// || s/$longchar//) { + $output .= $spaces . $1 . "\n"; + } else { + last; + } + } + $output .= $spaces . $_; + + # less -R always resets terminal attributes at the end of each line, so we + # need to clear attributes at the end of lines and then set them again at + # the start of the next line. This requires a second pass through the + # wrapped string, accumulating any attributes we see, remembering them, + # and then inserting the appropriate sequences at the newline. + if ($output =~ /\n/) { + my @lines = split (/\n/, $output); + my $start_format; + for my $line (@lines) { + if ($start_format && $line =~ /\S/) { + $line =~ s/^(\s*)(\S)/$1$start_format$2/; + } + $start_format = $self->end_format ($line); + if ($start_format) { + $line .= color ('reset'); + } + } + $output = join ("\n", @lines); + } + + # Fix up trailing whitespace and return the results. + $output =~ s/\s+$/\n\n/; + $output; +} + +############################################################################## +# Module return value and documentation +############################################################################## + +1; +__END__ + +=for stopwords +Allbery + +=head1 NAME + +Pod::Text::Color - Convert POD data to formatted color ASCII text + +=head1 SYNOPSIS + + use Pod::Text::Color; + my $parser = Pod::Text::Color->new (sentence => 0, width => 78); + + # Read POD from STDIN and write to STDOUT. + $parser->parse_from_filehandle; + + # Read POD from file.pod and write to file.txt. + $parser->parse_from_file ('file.pod', 'file.txt'); + +=head1 DESCRIPTION + +Pod::Text::Color is a simple subclass of Pod::Text that highlights output +text using ANSI color escape sequences. Apart from the color, it in all +ways functions like Pod::Text. See L for details and available +options. + +Term::ANSIColor is used to get colors and therefore must be installed to use +this module. + +=head1 BUGS + +This is just a basic proof of concept. It should be seriously expanded to +support configurable coloration via options passed to the constructor, and +B should be taught about those. + +=head1 AUTHOR + +Russ Allbery . + +=head1 COPYRIGHT AND LICENSE + +Copyright 1999, 2001, 2004, 2006, 2008, 2009, 2018 Russ Allbery + + +This program is free software; you may redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L, L + +The current version of this module is always available from its web site at +L. It is also part of the +Perl core distribution as of 5.6.0. + +=cut + +# Local Variables: +# copyright-at-end-flag: t +# End: diff --git a/lib/Pod/Text/Overstrike.pm b/lib/Pod/Text/Overstrike.pm new file mode 100644 index 0000000..92a3a93 --- /dev/null +++ b/lib/Pod/Text/Overstrike.pm @@ -0,0 +1,205 @@ +# Convert POD data to formatted overstrike text +# +# This was written because the output from: +# +# pod2text Text.pm > plain.txt; less plain.txt +# +# is not as rich as the output from +# +# pod2man Text.pm | nroff -man > fancy.txt; less fancy.txt +# +# and because both Pod::Text::Color and Pod::Text::Termcap are not device +# independent. +# +# SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl + +############################################################################## +# Modules and declarations +############################################################################## + +package Pod::Text::Overstrike; + +use 5.006; +use strict; +use warnings; + +use vars qw(@ISA $VERSION); + +use Pod::Text (); + +@ISA = qw(Pod::Text); + +$VERSION = '4.11'; + +############################################################################## +# Overrides +############################################################################## + +# Make level one headings bold, overriding any existing formatting. +sub cmd_head1 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $text = $self->strip_format ($text); + $text =~ s/(.)/$1\b$1/g; + return $self->SUPER::cmd_head1 ($attrs, $text); +} + +# Make level two headings bold, overriding any existing formatting. +sub cmd_head2 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $text = $self->strip_format ($text); + $text =~ s/(.)/$1\b$1/g; + return $self->SUPER::cmd_head2 ($attrs, $text); +} + +# Make level three headings underscored, overriding any existing formatting. +sub cmd_head3 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $text = $self->strip_format ($text); + $text =~ s/(.)/_\b$1/g; + return $self->SUPER::cmd_head3 ($attrs, $text); +} + +# Level four headings look like level three headings. +sub cmd_head4 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $text = $self->strip_format ($text); + $text =~ s/(.)/_\b$1/g; + return $self->SUPER::cmd_head4 ($attrs, $text); +} + +# The common code for handling all headers. We have to override to avoid +# interpolating twice and because we don't want to honor alt. +sub heading { + my ($self, $text, $indent, $marker) = @_; + $self->item ("\n\n") if defined $$self{ITEM}; + $text .= "\n" if $$self{opt_loose}; + my $margin = ' ' x ($$self{opt_margin} + $indent); + $self->output ($margin . $text . "\n"); + return ''; +} + +# Fix the various formatting codes. +sub cmd_b { local $_ = $_[0]->strip_format ($_[2]); s/(.)/$1\b$1/g; $_ } +sub cmd_f { local $_ = $_[0]->strip_format ($_[2]); s/(.)/_\b$1/g; $_ } +sub cmd_i { local $_ = $_[0]->strip_format ($_[2]); s/(.)/_\b$1/g; $_ } + +# Output any included code in bold. +sub output_code { + my ($self, $code) = @_; + $code =~ s/(.)/$1\b$1/g; + $self->output ($code); +} + +# Strip all of the formatting from a provided string, returning the stripped +# version. +sub strip_format { + my ($self, $text) = @_; + $text =~ s/(.)[\b]\1/$1/g; + $text =~ s/_[\b]//g; + return $text; +} + +# We unfortunately have to override the wrapping code here, since the normal +# wrapping code gets really confused by all the backspaces. +sub wrap { + my $self = shift; + local $_ = shift; + my $output = ''; + my $spaces = ' ' x $$self{MARGIN}; + my $width = $$self{opt_width} - $$self{MARGIN}; + while (length > $width) { + # This regex represents a single character, that's possibly underlined + # or in bold (in which case, it's three characters; the character, a + # backspace, and a character). Use [^\n] rather than . to protect + # against odd settings of $*. + my $char = '(?:[^\n][\b])?[^\n]'; + if (s/^((?>$char){0,$width})(?:\Z|\s+)//) { + $output .= $spaces . $1 . "\n"; + } else { + last; + } + } + $output .= $spaces . $_; + $output =~ s/\s+$/\n\n/; + return $output; +} + +############################################################################## +# Module return value and documentation +############################################################################## + +1; +__END__ + +=for stopwords +overstrike overstruck Overstruck Allbery terminal's + +=head1 NAME + +Pod::Text::Overstrike - Convert POD data to formatted overstrike text + +=head1 SYNOPSIS + + use Pod::Text::Overstrike; + my $parser = Pod::Text::Overstrike->new (sentence => 0, width => 78); + + # Read POD from STDIN and write to STDOUT. + $parser->parse_from_filehandle; + + # Read POD from file.pod and write to file.txt. + $parser->parse_from_file ('file.pod', 'file.txt'); + +=head1 DESCRIPTION + +Pod::Text::Overstrike is a simple subclass of Pod::Text that highlights +output text using overstrike sequences, in a manner similar to nroff. +Characters in bold text are overstruck (character, backspace, character) +and characters in underlined text are converted to overstruck underscores +(underscore, backspace, character). This format was originally designed +for hard-copy terminals and/or line printers, yet is readable on soft-copy +(CRT) terminals. + +Overstruck text is best viewed by page-at-a-time programs that take +advantage of the terminal's B and I capabilities, such +as the less program on Unix. + +Apart from the overstrike, it in all ways functions like Pod::Text. See +L for details and available options. + +=head1 BUGS + +Currently, the outermost formatting instruction wins, so for example +underlined text inside a region of bold text is displayed as simply bold. +There may be some better approach possible. + +=head1 AUTHOR + +Originally written by Joe Smith , using the framework +created by Russ Allbery . Subsequently updated by Russ Allbery. + +=head1 COPYRIGHT AND LICENSE + +Copyright 2000 by Joe Smith + +Copyright 2001, 2004, 2008, 2014, 2018 by Russ Allbery + +This program is free software; you may redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L, L + +The current version of this module is always available from its web site at +L. It is also part of the +Perl core distribution as of 5.6.0. + +=cut + +# Local Variables: +# copyright-at-end-flag: t +# End: diff --git a/lib/Pod/Text/Termcap.pm b/lib/Pod/Text/Termcap.pm new file mode 100644 index 0000000..d36ba4f --- /dev/null +++ b/lib/Pod/Text/Termcap.pm @@ -0,0 +1,272 @@ +# Convert POD data to ASCII text with format escapes. +# +# This is a simple subclass of Pod::Text that overrides a few key methods to +# output the right termcap escape sequences for formatted text on the current +# terminal type. +# +# SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl + +############################################################################## +# Modules and declarations +############################################################################## + +package Pod::Text::Termcap; + +use 5.006; +use strict; +use warnings; + +use Pod::Text (); +use POSIX (); +use Term::Cap; + +use vars qw(@ISA $VERSION); + +@ISA = qw(Pod::Text); + +$VERSION = '4.11'; + +############################################################################## +# Overrides +############################################################################## + +# In the initialization method, grab our terminal characteristics as well as +# do all the stuff we normally do. +sub new { + my ($self, %args) = @_; + my ($ospeed, $term, $termios); + + # $ENV{HOME} is usually not set on Windows. The default Term::Cap path + # may not work on Solaris. + unless (exists $ENV{TERMPATH}) { + my $home = exists $ENV{HOME} ? "$ENV{HOME}/.termcap:" : ''; + $ENV{TERMPATH} = + "${home}/etc/termcap:/usr/share/misc/termcap:/usr/share/lib/termcap"; + } + + # Fall back on a hard-coded terminal speed if POSIX::Termios isn't + # available (such as on VMS). + eval { $termios = POSIX::Termios->new }; + if ($@) { + $ospeed = 9600; + } else { + $termios->getattr; + $ospeed = $termios->getospeed || 9600; + } + + # Get data from Term::Cap if possible. + my ($bold, $undl, $norm, $width); + eval { + my $term = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed }; + $bold = $term->Tputs('md'); + $undl = $term->Tputs('us'); + $norm = $term->Tputs('me'); + if (defined $$term{_co}) { + $width = $$term{_co}; + $width =~ s/^\#//; + } + }; + + # Figure out the terminal width before calling the Pod::Text constructor, + # since it will otherwise force 76 characters. Pod::Text::Termcap has + # historically used 2 characters less than the width of the screen, while + # the other Pod::Text classes have used 76. This is weirdly inconsistent, + # but there's probably no good reason to change it now. + unless (defined $args{width}) { + $args{width} = $ENV{COLUMNS} || $width || 80; + $args{width} -= 2; + } + + # Initialize Pod::Text. + $self = $self->SUPER::new (%args); + + # Fall back on the ANSI escape sequences if Term::Cap doesn't work. + $$self{BOLD} = $bold || "\e[1m"; + $$self{UNDL} = $undl || "\e[4m"; + $$self{NORM} = $norm || "\e[m"; + + return $self; +} + +# Make level one headings bold. +sub cmd_head1 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $self->SUPER::cmd_head1 ($attrs, "$$self{BOLD}$text$$self{NORM}"); +} + +# Make level two headings bold. +sub cmd_head2 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $self->SUPER::cmd_head2 ($attrs, "$$self{BOLD}$text$$self{NORM}"); +} + +# Fix up B<> and I<>. Note that we intentionally don't do F<>. +sub cmd_b { my $self = shift; return "$$self{BOLD}$_[1]$$self{NORM}" } +sub cmd_i { my $self = shift; return "$$self{UNDL}$_[1]$$self{NORM}" } + +# Analyze a single line and return any formatting codes in effect at the end +# of that line. +sub end_format { + my ($self, $line) = @_; + my $pattern = "(\Q$$self{BOLD}\E|\Q$$self{UNDL}\E|\Q$$self{NORM}\E)"; + my $current; + while ($line =~ /$pattern/g) { + my $code = $1; + if ($code eq $$self{NORM}) { + undef $current; + } else { + $current .= $code; + } + } + return $current; +} + +# Output any included code in bold. +sub output_code { + my ($self, $code) = @_; + $self->output ($$self{BOLD} . $code . $$self{NORM}); +} + +# Strip all of the formatting from a provided string, returning the stripped +# version. +sub strip_format { + my ($self, $text) = @_; + $text =~ s/\Q$$self{BOLD}//g; + $text =~ s/\Q$$self{UNDL}//g; + $text =~ s/\Q$$self{NORM}//g; + return $text; +} + +# Override the wrapping code to ignore the special sequences. +sub wrap { + my $self = shift; + local $_ = shift; + my $output = ''; + my $spaces = ' ' x $$self{MARGIN}; + my $width = $$self{opt_width} - $$self{MARGIN}; + + # $code matches a single special sequence. $char matches any number of + # special sequences preceding a single character other than a newline. + # $shortchar matches some sequence of $char ending in codes followed by + # whitespace or the end of the string. $longchar matches exactly $width + # $chars, used when we have to truncate and hard wrap. + # + # $shortchar and $longchar are created in a slightly odd way because the + # construct ${char}{0,$width} didn't do the right thing until Perl 5.8.x. + my $code = "(?:\Q$$self{BOLD}\E|\Q$$self{UNDL}\E|\Q$$self{NORM}\E)"; + my $char = "(?>$code*[^\\n])"; + my $shortchar = '^(' . $char . "{0,$width}(?>$code*)" . ')(?:\s+|\z)'; + my $longchar = '^(' . $char . "{$width})"; + while (length > $width) { + if (s/$shortchar// || s/$longchar//) { + $output .= $spaces . $1 . "\n"; + } else { + last; + } + } + $output .= $spaces . $_; + + # less -R always resets terminal attributes at the end of each line, so we + # need to clear attributes at the end of lines and then set them again at + # the start of the next line. This requires a second pass through the + # wrapped string, accumulating any attributes we see, remembering them, + # and then inserting the appropriate sequences at the newline. + if ($output =~ /\n/) { + my @lines = split (/\n/, $output); + my $start_format; + for my $line (@lines) { + if ($start_format && $line =~ /\S/) { + $line =~ s/^(\s*)(\S)/$1$start_format$2/; + } + $start_format = $self->end_format ($line); + if ($start_format) { + $line .= $$self{NORM}; + } + } + $output = join ("\n", @lines); + } + + # Fix up trailing whitespace and return the results. + $output =~ s/\s+$/\n\n/; + return $output; +} + +############################################################################## +# Module return value and documentation +############################################################################## + +1; +__END__ + +=head1 NAME + +Pod::Text::Termcap - Convert POD data to ASCII text with format escapes + +=for stopwords +ECMA-48 VT100 Allbery Solaris TERMPATH + +=head1 SYNOPSIS + + use Pod::Text::Termcap; + my $parser = Pod::Text::Termcap->new (sentence => 0, width => 78); + + # Read POD from STDIN and write to STDOUT. + $parser->parse_from_filehandle; + + # Read POD from file.pod and write to file.txt. + $parser->parse_from_file ('file.pod', 'file.txt'); + +=head1 DESCRIPTION + +Pod::Text::Termcap is a simple subclass of Pod::Text that highlights output +text using the correct termcap escape sequences for the current terminal. +Apart from the format codes, it in all ways functions like Pod::Text. See +L for details and available options. + +=head1 ENVIRONMENT + +This module sets the TERMPATH environment variable globally to: + + $HOME/.termcap:/etc/termcap:/usr/share/misc/termcap:/usr/share/lib/termcap + +if it isn't already set. (The first entry is omitted if the HOME +environment variable isn't set.) This is a (very old) workaround for +problems finding termcap information on older versions of Solaris, and is +not good module behavior. Please do not rely on this behavior; it may be +dropped in a future release. + +=head1 NOTES + +This module uses Term::Cap to retrieve the formatting escape sequences for +the current terminal, and falls back on the ECMA-48 (the same in this +regard as ANSI X3.64 and ISO 6429, the escape codes also used by DEC VT100 +terminals) if the bold, underline, and reset codes aren't set in the +termcap information. + +=head1 AUTHOR + +Russ Allbery . + +=head1 COPYRIGHT AND LICENSE + +Copyright 1999, 2001-2002, 2004, 2006, 2008-2009, 2014-2015, 2018 Russ Allbery + + +This program is free software; you may redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L, L, L + +The current version of this module is always available from its web site at +L. It is also part of the +Perl core distribution as of 5.6.0. + +=cut + +# Local Variables: +# copyright-at-end-flag: t +# End: diff --git a/pod/perlpodstyle.pod b/pod/perlpodstyle.pod new file mode 100644 index 0000000..22306e7 --- /dev/null +++ b/pod/perlpodstyle.pod @@ -0,0 +1,299 @@ +=head1 NAME + +perlpodstyle - Perl POD style guide + +=head1 DESCRIPTION + +These are general guidelines for how to write POD documentation for Perl +scripts and modules, based on general guidelines for writing good UNIX man +pages. All of these guidelines are, of course, optional, but following +them will make your documentation more consistent with other documentation +on the system. + +The name of the program being documented is conventionally written in bold +(using BEE) wherever it occurs, as are all program options. +Arguments should be written in italics (IEE). Function names are +traditionally written in italics; if you write a function as function(), +Pod::Man will take care of this for you. Literal code or commands should +be in CEE. References to other man pages should be in the form +C or Cmanpage(section)E>, and Pod::Man will +automatically format those appropriately. The second form, with +LEE, is used to request that a POD formatter make a link to the +man page if possible. As an exception, one normally omits the section +when referring to module documentation since it's not clear what section +module documentation will be in; use CModule::NameE> for module +references instead. + +References to other programs or functions are normally in the form of man +page references so that cross-referencing tools can provide the user with +links and the like. It's possible to overdo this, though, so be careful not +to clutter your documentation with too much markup. References to other +programs that are not given as man page references should be enclosed in +BEE. + +The major headers should be set out using a C<=head1> directive, and are +historically written in the rather startling ALL UPPER CASE format; this +is not mandatory, but it's strongly recommended so that sections have +consistent naming across different software packages. Minor headers may +be included using C<=head2>, and are typically in mixed case. + +The standard sections of a manual page are: + +=over 4 + +=item NAME + +Mandatory section; should be a comma-separated list of programs or +functions documented by this POD page, such as: + + foo, bar - programs to do something + +Manual page indexers are often extremely picky about the format of this +section, so don't put anything in it except this line. Every program or +function documented by this POD page should be listed, separated by a +comma and a space. For a Perl module, just give the module name. A +single dash, and only a single dash, should separate the list of programs +or functions from the description. Do not use any markup such as +CEE or BEE anywhere in this line. Functions should not be +qualified with C<()> or the like. The description should ideally fit on a +single line, even if a man program replaces the dash with a few tabs. + +=item SYNOPSIS + +A short usage summary for programs and functions. This section is +mandatory for section 3 pages. For Perl module documentation, it's +usually convenient to have the contents of this section be a verbatim +block showing some (brief) examples of typical ways the module is used. + +=item DESCRIPTION + +Extended description and discussion of the program or functions, or the +body of the documentation for man pages that document something else. If +particularly long, it's a good idea to break this up into subsections +C<=head2> directives like: + + =head2 Normal Usage + + =head2 Advanced Features + + =head2 Writing Configuration Files + +or whatever is appropriate for your documentation. + +For a module, this is generally where the documentation of the interfaces +provided by the module goes, usually in the form of a list with an +C<=item> for each interface. Depending on how many interfaces there are, +you may want to put that documentation in separate METHODS, FUNCTIONS, +CLASS METHODS, or INSTANCE METHODS sections instead and save the +DESCRIPTION section for an overview. + +=item OPTIONS + +Detailed description of each of the command-line options taken by the +program. This should be separate from the description for the use of +parsers like L. This is normally presented as a list, with +each option as a separate C<=item>. The specific option string should be +enclosed in BEE. Any values that the option takes should be +enclosed in IEE. For example, the section for the option +B<--section>=I would be introduced with: + + =item B<--section>=I + +Synonymous options (like both the short and long forms) are separated by a +comma and a space on the same C<=item> line, or optionally listed as their +own item with a reference to the canonical name. For example, since +B<--section> can also be written as B<-s>, the above would be: + + =item B<-s> I, B<--section>=I + +Writing the short option first is recommended because it's easier to read. +The long option is long enough to draw the eye to it anyway and the short +option can otherwise get lost in visual noise. + +=item RETURN VALUE + +What the program or function returns, if successful. This section can be +omitted for programs whose precise exit codes aren't important, provided +they return 0 on success and non-zero on failure as is standard. It +should always be present for functions. For modules, it may be useful to +summarize return values from the module interface here, or it may be more +useful to discuss return values separately in the documentation of each +function or method the module provides. + +=item ERRORS + +Exceptions, error return codes, exit statuses, and errno settings. +Typically used for function or module documentation; program documentation +uses DIAGNOSTICS instead. The general rule of thumb is that errors +printed to C or C and intended for the end user are +documented in DIAGNOSTICS while errors passed internal to the calling +program and intended for other programmers are documented in ERRORS. When +documenting a function that sets errno, a full list of the possible errno +values should be given here. + +=item DIAGNOSTICS + +All possible messages the program can print out and what they mean. You +may wish to follow the same documentation style as the Perl documentation; +see perldiag(1) for more details (and look at the POD source as well). + +If applicable, please include details on what the user should do to +correct the error; documenting an error as indicating "the input buffer is +too small" without telling the user how to increase the size of the input +buffer (or at least telling them that it isn't possible) aren't very +useful. + +=item EXAMPLES + +Give some example uses of the program or function. Don't skimp; users +often find this the most useful part of the documentation. The examples +are generally given as verbatim paragraphs. + +Don't just present an example without explaining what it does. Adding a +short paragraph saying what the example will do can increase the value of +the example immensely. + +=item ENVIRONMENT + +Environment variables that the program cares about, normally presented as +a list using C<=over>, C<=item>, and C<=back>. For example: + + =over 6 + + =item HOME + + Used to determine the user's home directory. F<.foorc> in this + directory is read for configuration details, if it exists. + + =back + +Since environment variables are normally in all uppercase, no additional +special formatting is generally needed; they're glaring enough as it is. + +=item FILES + +All files used by the program or function, normally presented as a list, +and what it uses them for. File names should be enclosed in FEE. +It's particularly important to document files that will be potentially +modified. + +=item CAVEATS + +Things to take special care with, sometimes called WARNINGS. + +=item BUGS + +Things that are broken or just don't work quite right. + +=item RESTRICTIONS + +Bugs you don't plan to fix. :-) + +=item NOTES + +Miscellaneous commentary. + +=item AUTHOR + +Who wrote it (use AUTHORS for multiple people). It's a good idea to +include your current e-mail address (or some e-mail address to which bug +reports should be sent) or some other contact information so that users +have a way of contacting you. Remember that program documentation tends +to roam the wild for far longer than you expect and pick a contact method +that's likely to last. + +=item HISTORY + +Programs derived from other sources sometimes have this. Some people keep +a modification log here, but that usually gets long and is normally better +maintained in a separate file. + +=item COPYRIGHT AND LICENSE + +For copyright + + Copyright YEAR(s) YOUR NAME(s) + +(No, (C) is not needed. No, "all rights reserved" is not needed.) + +For licensing the easiest way is to use the same licensing as Perl itself: + + This library is free software; you may redistribute it and/or + modify it under the same terms as Perl itself. + +This makes it easy for people to use your module with Perl. Note that +this licensing example is neither an endorsement or a requirement, you are +of course free to choose any licensing. + +=item SEE ALSO + +Other man pages to check out, like man(1), man(7), makewhatis(8), or +catman(8). Normally a simple list of man pages separated by commas, or a +paragraph giving the name of a reference work. Man page references, if +they use the standard C form, don't have to be enclosed in +LEE (although it's recommended), but other things in this section +probably should be when appropriate. + +If the package has a mailing list, include a URL or subscription +instructions here. + +If the package has a web site, include a URL here. + +=back + +Documentation of object-oriented libraries or modules may want to use +CONSTRUCTORS and METHODS sections, or CLASS METHODS and INSTANCE METHODS +sections, for detailed documentation of the parts of the library and save +the DESCRIPTION section for an overview. Large modules with a function +interface may want to use FUNCTIONS for similar reasons. Some people use +OVERVIEW to summarize the description if it's quite long. + +Section ordering varies, although NAME must always be the first section +(you'll break some man page systems otherwise), and NAME, SYNOPSIS, +DESCRIPTION, and OPTIONS generally always occur first and in that order if +present. In general, SEE ALSO, AUTHOR, and similar material should be +left for last. Some systems also move WARNINGS and NOTES to last. The +order given above should be reasonable for most purposes. + +Some systems use CONFORMING TO to note conformance to relevant standards +and MT-LEVEL to note safeness for use in threaded programs or signal +handlers. These headings are primarily useful when documenting parts of a +C library. + +Finally, as a general note, try not to use an excessive amount of markup. +As documented here and in L, you can safely leave Perl +variables, function names, man page references, and the like unadorned by +markup and the POD translators will figure it out for you. This makes it +much easier to later edit the documentation. Note that many existing +translators will do the wrong thing with e-mail addresses when wrapped in +LEE, so don't do that. + +=head1 AUTHOR + +Russ Allbery , with large portions of this documentation +taken from the documentation of the original B implementation by +Larry Wall and Tom Christiansen. + +=head1 COPYRIGHT AND LICENSE + +Copyright 1999, 2000, 2001, 2004, 2006, 2008, 2010, 2015, 2018 Russ +Allbery + +Copying and distribution of this file, with or without modification, are +permitted in any medium without royalty provided the copyright notice and +this notice are preserved. This file is offered as-is, without any +warranty. + +SPDX-License-Identifier: FSFAP + +=head1 SEE ALSO + +For additional information that may be more accurate for your specific +system, see either L or L depending on your system manual +section numbering conventions. + +This documentation is maintained as part of the podlators distribution. +The current version is always available from its web site at +L. + +=cut diff --git a/scripts/pod2man.PL b/scripts/pod2man.PL new file mode 100755 index 0000000..bc455d8 --- /dev/null +++ b/scripts/pod2man.PL @@ -0,0 +1,450 @@ +#!/usr/bin/perl +# +# Special wrapper script to generate the actual pod2man script. This is +# required for proper start-up code on non-UNIX platforms, and is used inside +# Perl core. + +use 5.006; +use strict; +use warnings; + +use Config qw(%Config); +use Cwd qw(cwd); +use File::Basename qw(basename dirname); + +# List explicitly here the variables you want Configure to generate. +# Metaconfig only looks for shell variables, so you have to mention them as if +# they were shell variables, not %Config entries. Thus you write +# $startperl +# to ensure Configure will look for $Config{startperl}. + +# This forces PL files to create target in same directory as PL file. +# This is so that make depend always knows where to find PL derivatives. +chdir(dirname($0)) or die "Cannot change directories: $!\n"; +my $file = basename($0, '.PL'); +if ($^O eq 'VMS') { + $file .= '.com'; +} + +# Create the generated script. +## no critic (InputOutput::RequireBriefOpen) +## no critic (InputOutput::RequireCheckedSyscalls) +open(my $out, '>', $file) or die "Cannot create $file: $!\n"; +print "Extracting $file (with variable substitutions)\n"; +## use critic + +# In this section, Perl variables will be expanded during extraction. You can +# use $Config{...} to use Configure variables. +print {$out} <<"PREAMBLE" or die "Cannot write to $file: $!\n"; +$Config{startperl} + eval 'exec $Config{perlpath} -S \$0 \${1+"\$@"}' + if \$running_under_some_shell; +PREAMBLE + +# In the following, Perl variables are not expanded during extraction. +print {$out} <<'SCRIPT_BODY' or die "Cannot write to $file: $!\n"; + +# Convert POD data to formatted *roff input. +# +# The driver script for Pod::Man. +# +# SPDX-License-Identifier: GPL-1.0-or-later OR Artistic-1.0-Perl + +use 5.006; +use strict; +use warnings; + +use Getopt::Long qw(GetOptions); +use Pod::Man (); +use Pod::Usage qw(pod2usage); + +use strict; + +# Clean up $0 for error reporting. +$0 =~ s%.*/%%; + +# Insert -- into @ARGV before any single dash argument to hide it from +# Getopt::Long; we want to interpret it as meaning stdin. +my $stdin; +@ARGV = map { $_ eq '-' && !$stdin++ ? ('--', $_) : $_ } @ARGV; + +# Parse our options, trying to retain backward compatibility with pod2man but +# allowing short forms as well. --lax is currently ignored. +my %options; +Getopt::Long::config ('bundling_override'); +GetOptions (\%options, 'center|c=s', 'date|d=s', 'errors=s', 'fixed=s', + 'fixedbold=s', 'fixeditalic=s', 'fixedbolditalic=s', 'help|h', + 'lax|l', 'lquote=s', 'name|n=s', 'nourls', 'official|o', + 'quotes|q=s', 'release|r=s', 'rquote=s', 'section|s=s', 'stderr', + 'verbose|v', 'utf8|u') + or exit 1; +pod2usage (0) if $options{help}; + +# Official sets --center, but don't override things explicitly set. +if ($options{official} && !defined $options{center}) { + $options{center} = 'Perl Programmers Reference Guide'; +} + +# Verbose is only our flag, not a Pod::Man flag. +my $verbose = $options{verbose}; +delete $options{verbose}; + +# This isn't a valid Pod::Man option and is only accepted for backward +# compatibility. +delete $options{lax}; + +# If neither stderr nor errors is set, default to errors = die. +if (!defined $options{stderr} && !defined $options{errors}) { + $options{errors} = 'die'; +} + +# Initialize and run the formatter, pulling a pair of input and output off at +# a time. For each file, we check whether the document was completely empty +# and, if so, will remove the created file and exit with a non-zero exit +# status. +my $parser = Pod::Man->new (%options); +my $status = 0; +my @files; +do { + @files = splice (@ARGV, 0, 2); + print " $files[1]\n" if $verbose; + $parser->parse_from_file (@files); + if ($parser->{CONTENTLESS}) { + $status = 1; + if (defined $files[0]) { + warn "$0: unable to format $files[0]\n"; + } else { + warn "$0: unable to format standard input\n"; + } + if (defined ($files[1]) and $files[1] ne '-') { + unlink $files[1] unless (-s $files[1]); + } + } +} while (@ARGV); +exit $status; + +__END__ + +=for stopwords +en em --stderr stderr --utf8 UTF-8 overdo markup MT-LEVEL Allbery Solaris URL +troff troff-specific formatters uppercased Christiansen --nourls UTC prepend +lquote rquote + +=head1 NAME + +pod2man - Convert POD data to formatted *roff input + +=head1 SYNOPSIS + +pod2man [B<--center>=I] [B<--date>=I] [B<--errors>=I