summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl
diff options
context:
space:
mode:
authorNorbert Preining <preining@logic.at>2008-01-07 13:06:47 +0000
committerNorbert Preining <preining@logic.at>2008-01-07 13:06:47 +0000
commitccf29645c02dcd2e530892cd3cad48f3b555cd3d (patch)
treecad04a5175629d1f5b40d3d5c86d61f649126481 /Master/tlpkg/tlperl
parentde02666bc74cb71685aa565c195759e9fd00631d (diff)
add all the pod stuff, hope now that it is enough
git-svn-id: svn://tug.org/texlive/trunk@6115 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/tlpkg/tlperl')
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Checker.pm1270
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Find.pm523
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Functions.pm376
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Html.pm2123
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/InputObjects.pm941
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/LaTeX.pm1876
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Man.pm1413
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/ParseLink.pm184
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/ParseUtils.pm852
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Parser.pm1799
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc.pm1762
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc/BaseTo.pm28
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc/GetOptsOO.pm106
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc/ToChecker.pm72
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc/ToMan.pm187
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc/ToNroff.pm100
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc/ToPod.pm90
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc/ToRtf.pm85
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc/ToText.pm91
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc/ToTk.pm129
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Perldoc/ToXml.pm63
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/PlainText.pm705
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Plainer.pm69
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Select.pm754
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Text.pm848
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Text/Color.pm145
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Text/Overstrike.pm208
-rw-r--r--Master/tlpkg/tlperl/lib/Pod/Text/Termcap.pm180
28 files changed, 16979 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl/lib/Pod/Checker.pm b/Master/tlpkg/tlperl/lib/Pod/Checker.pm
new file mode 100644
index 00000000000..49162da4a27
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Checker.pm
@@ -0,0 +1,1270 @@
+#############################################################################
+# Pod/Checker.pm -- check pod documents for syntax errors
+#
+# Copyright (C) 1994-2000 by Bradford Appleton. All rights reserved.
+# This file is part of "PodParser". PodParser is free software;
+# you can redistribute it and/or modify it under the same terms
+# as Perl itself.
+#############################################################################
+
+package Pod::Checker;
+
+use vars qw($VERSION);
+$VERSION = 1.43; ## Current version of this package
+require 5.005; ## requires this Perl version or later
+
+use Pod::ParseUtils; ## for hyperlinks and lists
+
+=head1 NAME
+
+Pod::Checker, podchecker() - check pod documents for syntax errors
+
+=head1 SYNOPSIS
+
+ use Pod::Checker;
+
+ $syntax_okay = podchecker($filepath, $outputpath, %options);
+
+ my $checker = new Pod::Checker %options;
+ $checker->parse_from_file($filepath, \*STDERR);
+
+=head1 OPTIONS/ARGUMENTS
+
+C<$filepath> is the input POD to read and C<$outputpath> is
+where to write POD syntax error messages. Either argument may be a scalar
+indicating a file-path, or else a reference to an open filehandle.
+If unspecified, the input-file it defaults to C<\*STDIN>, and
+the output-file defaults to C<\*STDERR>.
+
+=head2 podchecker()
+
+This function can take a hash of options:
+
+=over 4
+
+=item B<-warnings> =E<gt> I<val>
+
+Turn warnings on/off. I<val> is usually 1 for on, but higher values
+trigger additional warnings. See L<"Warnings">.
+
+=back
+
+=head1 DESCRIPTION
+
+B<podchecker> will perform syntax checking of Perl5 POD format documentation.
+
+Curious/ambitious users are welcome to propose additional features they wish
+to see in B<Pod::Checker> and B<podchecker> and verify that the checks are
+consistent with L<perlpod>.
+
+The following checks are currently performed:
+
+=over 4
+
+=item *
+
+Unknown '=xxxx' commands, unknown 'XE<lt>...E<gt>' interior-sequences,
+and unterminated interior sequences.
+
+=item *
+
+Check for proper balancing of C<=begin> and C<=end>. The contents of such
+a block are generally ignored, i.e. no syntax checks are performed.
+
+=item *
+
+Check for proper nesting and balancing of C<=over>, C<=item> and C<=back>.
+
+=item *
+
+Check for same nested interior-sequences (e.g.
+C<LE<lt>...LE<lt>...E<gt>...E<gt>>).
+
+=item *
+
+Check for malformed or nonexisting entities C<EE<lt>...E<gt>>.
+
+=item *
+
+Check for correct syntax of hyperlinks C<LE<lt>...E<gt>>. See L<perlpod>
+for details.
+
+=item *
+
+Check for unresolved document-internal links. This check may also reveal
+misspelled links that seem to be internal links but should be links
+to something else.
+
+=back
+
+=head1 DIAGNOSTICS
+
+=head2 Errors
+
+=over 4
+
+=item * empty =headn
+
+A heading (C<=head1> or C<=head2>) without any text? That ain't no
+heading!
+
+=item * =over on line I<N> without closing =back
+
+The C<=over> command does not have a corresponding C<=back> before the
+next heading (C<=head1> or C<=head2>) or the end of the file.
+
+=item * =item without previous =over
+
+=item * =back without previous =over
+
+An C<=item> or C<=back> command has been found outside a
+C<=over>/C<=back> block.
+
+=item * No argument for =begin
+
+A C<=begin> command was found that is not followed by the formatter
+specification.
+
+=item * =end without =begin
+
+A standalone C<=end> command was found.
+
+=item * Nested =begin's
+
+There were at least two consecutive C<=begin> commands without
+the corresponding C<=end>. Only one C<=begin> may be active at
+a time.
+
+=item * =for without formatter specification
+
+There is no specification of the formatter after the C<=for> command.
+
+=item * unresolved internal link I<NAME>
+
+The given link to I<NAME> does not have a matching node in the current
+POD. This also happend when a single word node name is not enclosed in
+C<"">.
+
+=item * Unknown command "I<CMD>"
+
+An invalid POD command has been found. Valid are C<=head1>, C<=head2>,
+C<=head3>, C<=head4>, C<=over>, C<=item>, C<=back>, C<=begin>, C<=end>,
+C<=for>, C<=pod>, C<=cut>
+
+=item * Unknown interior-sequence "I<SEQ>"
+
+An invalid markup command has been encountered. Valid are:
+C<BE<lt>E<gt>>, C<CE<lt>E<gt>>, C<EE<lt>E<gt>>, C<FE<lt>E<gt>>,
+C<IE<lt>E<gt>>, C<LE<lt>E<gt>>, C<SE<lt>E<gt>>, C<XE<lt>E<gt>>,
+C<ZE<lt>E<gt>>
+
+=item * nested commands I<CMD>E<lt>...I<CMD>E<lt>...E<gt>...E<gt>
+
+Two nested identical markup commands have been found. Generally this
+does not make sense.
+
+=item * garbled entity I<STRING>
+
+The I<STRING> found cannot be interpreted as a character entity.
+
+=item * Entity number out of range
+
+An entity specified by number (dec, hex, oct) is out of range (1-255).
+
+=item * malformed link LE<lt>E<gt>
+
+The link found cannot be parsed because it does not conform to the
+syntax described in L<perlpod>.
+
+=item * nonempty ZE<lt>E<gt>
+
+The C<ZE<lt>E<gt>> sequence is supposed to be empty.
+
+=item * empty XE<lt>E<gt>
+
+The index entry specified contains nothing but whitespace.
+
+=item * Spurious text after =pod / =cut
+
+The commands C<=pod> and C<=cut> do not take any arguments.
+
+=item * Spurious character(s) after =back
+
+The C<=back> command does not take any arguments.
+
+=back
+
+=head2 Warnings
+
+These may not necessarily cause trouble, but indicate mediocre style.
+
+=over 4
+
+=item * multiple occurrence of link target I<name>
+
+The POD file has some C<=item> and/or C<=head> commands that have
+the same text. Potential hyperlinks to such a text cannot be unique then.
+This warning is printed only with warning level greater than one.
+
+=item * line containing nothing but whitespace in paragraph
+
+There is some whitespace on a seemingly empty line. POD is very sensitive
+to such things, so this is flagged. B<vi> users switch on the B<list>
+option to avoid this problem.
+
+=begin _disabled_
+
+=item * file does not start with =head
+
+The file starts with a different POD directive than head.
+This is most probably something you do not want.
+
+=end _disabled_
+
+=item * previous =item has no contents
+
+There is a list C<=item> right above the flagged line that has no
+text contents. You probably want to delete empty items.
+
+=item * preceding non-item paragraph(s)
+
+A list introduced by C<=over> starts with a text or verbatim paragraph,
+but continues with C<=item>s. Move the non-item paragraph out of the
+C<=over>/C<=back> block.
+
+=item * =item type mismatch (I<one> vs. I<two>)
+
+A list started with e.g. a bulletted C<=item> and continued with a
+numbered one. This is obviously inconsistent. For most translators the
+type of the I<first> C<=item> determines the type of the list.
+
+=item * I<N> unescaped C<E<lt>E<gt>> in paragraph
+
+Angle brackets not written as C<E<lt>ltE<gt>> and C<E<lt>gtE<gt>>
+can potentially cause errors as they could be misinterpreted as
+markup commands. This is only printed when the -warnings level is
+greater than 1.
+
+=item * Unknown entity
+
+A character entity was found that does not belong to the standard
+ISO set or the POD specials C<verbar> and C<sol>.
+
+=item * No items in =over
+
+The list opened with C<=over> does not contain any items.
+
+=item * No argument for =item
+
+C<=item> without any parameters is deprecated. It should either be followed
+by C<*> to indicate an unordered list, by a number (optionally followed
+by a dot) to indicate an ordered (numbered) list or simple text for a
+definition list.
+
+=item * empty section in previous paragraph
+
+The previous section (introduced by a C<=head> command) does not contain
+any text. This usually indicates that something is missing. Note: A
+C<=head1> followed immediately by C<=head2> does not trigger this warning.
+
+=item * Verbatim paragraph in NAME section
+
+The NAME section (C<=head1 NAME>) should consist of a single paragraph
+with the script/module name, followed by a dash `-' and a very short
+description of what the thing is good for.
+
+=item * =headI<n> without preceding higher level
+
+For example if there is a C<=head2> in the POD file prior to a
+C<=head1>.
+
+=back
+
+=head2 Hyperlinks
+
+There are some warnings wrt. malformed hyperlinks.
+
+=over 4
+
+=item * ignoring leading/trailing whitespace in link
+
+There is whitespace at the beginning or the end of the contents of
+LE<lt>...E<gt>.
+
+=item * (section) in '$page' deprecated
+
+There is a section detected in the page name of LE<lt>...E<gt>, e.g.
+C<LE<lt>passwd(2)E<gt>>. POD hyperlinks may point to POD documents only.
+Please write C<CE<lt>passwd(2)E<gt>> instead. Some formatters are able
+to expand this to appropriate code. For links to (builtin) functions,
+please say C<LE<lt>perlfunc/mkdirE<gt>>, without ().
+
+=item * alternative text/node '%s' contains non-escaped | or /
+
+The characters C<|> and C</> are special in the LE<lt>...E<gt> context.
+Although the hyperlink parser does its best to determine which "/" is
+text and which is a delimiter in case of doubt, one ought to escape
+these literal characters like this:
+
+ / E<sol>
+ | E<verbar>
+
+=back
+
+=head1 RETURN VALUE
+
+B<podchecker> returns the number of POD syntax errors found or -1 if
+there were no POD commands at all found in the file.
+
+=head1 EXAMPLES
+
+See L</SYNOPSIS>
+
+=head1 INTERFACE
+
+While checking, this module collects document properties, e.g. the nodes
+for hyperlinks (C<=headX>, C<=item>) and index entries (C<XE<lt>E<gt>>).
+POD translators can use this feature to syntax-check and get the nodes in
+a first pass before actually starting to convert. This is expensive in terms
+of execution time, but allows for very robust conversions.
+
+Since PodParser-1.24 the B<Pod::Checker> module uses only the B<poderror>
+method to print errors and warnings. The summary output (e.g.
+"Pod syntax OK") has been dropped from the module and has been included in
+B<podchecker> (the script). This allows users of B<Pod::Checker> to
+control completely the output behaviour. Users of B<podchecker> (the script)
+get the well-known behaviour.
+
+=cut
+
+#############################################################################
+
+use strict;
+#use diagnostics;
+use Carp;
+use Exporter;
+use Pod::Parser;
+
+use vars qw(@ISA @EXPORT);
+@ISA = qw(Pod::Parser);
+@EXPORT = qw(&podchecker);
+
+use vars qw(%VALID_COMMANDS %VALID_SEQUENCES);
+
+my %VALID_COMMANDS = (
+ 'pod' => 1,
+ 'cut' => 1,
+ 'head1' => 1,
+ 'head2' => 1,
+ 'head3' => 1,
+ 'head4' => 1,
+ 'over' => 1,
+ 'back' => 1,
+ 'item' => 1,
+ 'for' => 1,
+ 'begin' => 1,
+ 'end' => 1,
+);
+
+my %VALID_SEQUENCES = (
+ 'I' => 1,
+ 'B' => 1,
+ 'S' => 1,
+ 'C' => 1,
+ 'L' => 1,
+ 'F' => 1,
+ 'X' => 1,
+ 'Z' => 1,
+ 'E' => 1,
+);
+
+# stolen from HTML::Entities
+my %ENTITIES = (
+ # Some normal chars that have special meaning in SGML context
+ amp => '&', # ampersand
+'gt' => '>', # greater than
+'lt' => '<', # less than
+ quot => '"', # double quote
+
+ # PUBLIC ISO 8879-1986//ENTITIES Added Latin 1//EN//HTML
+ AElig => 'Æ', # capital AE diphthong (ligature)
+ Aacute => 'Á', # capital A, acute accent
+ Acirc => 'Â', # capital A, circumflex accent
+ Agrave => 'À', # capital A, grave accent
+ Aring => 'Å', # capital A, ring
+ Atilde => 'Ã', # capital A, tilde
+ Auml => 'Ä', # capital A, dieresis or umlaut mark
+ Ccedil => 'Ç', # capital C, cedilla
+ ETH => 'Ð', # capital Eth, Icelandic
+ Eacute => 'É', # capital E, acute accent
+ Ecirc => 'Ê', # capital E, circumflex accent
+ Egrave => 'È', # capital E, grave accent
+ Euml => 'Ë', # capital E, dieresis or umlaut mark
+ Iacute => 'Í', # capital I, acute accent
+ Icirc => 'Î', # capital I, circumflex accent
+ Igrave => 'Ì', # capital I, grave accent
+ Iuml => 'Ï', # capital I, dieresis or umlaut mark
+ Ntilde => 'Ñ', # capital N, tilde
+ Oacute => 'Ó', # capital O, acute accent
+ Ocirc => 'Ô', # capital O, circumflex accent
+ Ograve => 'Ò', # capital O, grave accent
+ Oslash => 'Ø', # capital O, slash
+ Otilde => 'Õ', # capital O, tilde
+ Ouml => 'Ö', # capital O, dieresis or umlaut mark
+ THORN => 'Þ', # capital THORN, Icelandic
+ Uacute => 'Ú', # capital U, acute accent
+ Ucirc => 'Û', # capital U, circumflex accent
+ Ugrave => 'Ù', # capital U, grave accent
+ Uuml => 'Ü', # capital U, dieresis or umlaut mark
+ Yacute => 'Ý', # capital Y, acute accent
+ aacute => 'á', # small a, acute accent
+ acirc => 'â', # small a, circumflex accent
+ aelig => 'æ', # small ae diphthong (ligature)
+ agrave => 'à', # small a, grave accent
+ aring => 'å', # small a, ring
+ atilde => 'ã', # small a, tilde
+ auml => 'ä', # small a, dieresis or umlaut mark
+ ccedil => 'ç', # small c, cedilla
+ eacute => 'é', # small e, acute accent
+ ecirc => 'ê', # small e, circumflex accent
+ egrave => 'è', # small e, grave accent
+ eth => 'ð', # small eth, Icelandic
+ euml => 'ë', # small e, dieresis or umlaut mark
+ iacute => 'í', # small i, acute accent
+ icirc => 'î', # small i, circumflex accent
+ igrave => 'ì', # small i, grave accent
+ iuml => 'ï', # small i, dieresis or umlaut mark
+ ntilde => 'ñ', # small n, tilde
+ oacute => 'ó', # small o, acute accent
+ ocirc => 'ô', # small o, circumflex accent
+ ograve => 'ò', # small o, grave accent
+ oslash => 'ø', # small o, slash
+ otilde => 'õ', # small o, tilde
+ ouml => 'ö', # small o, dieresis or umlaut mark
+ szlig => 'ß', # small sharp s, German (sz ligature)
+ thorn => 'þ', # small thorn, Icelandic
+ uacute => 'ú', # small u, acute accent
+ ucirc => 'û', # small u, circumflex accent
+ ugrave => 'ù', # small u, grave accent
+ uuml => 'ü', # small u, dieresis or umlaut mark
+ yacute => 'ý', # small y, acute accent
+ yuml => 'ÿ', # small y, dieresis or umlaut mark
+
+ # Some extra Latin 1 chars that are listed in the HTML3.2 draft (21-May-96)
+ copy => '©', # copyright sign
+ reg => '®', # registered sign
+ nbsp => "\240", # non breaking space
+
+ # Additional ISO-8859/1 entities listed in rfc1866 (section 14)
+ iexcl => '¡',
+ cent => '¢',
+ pound => '£',
+ curren => '¤',
+ yen => '¥',
+ brvbar => '¦',
+ sect => '§',
+ uml => '¨',
+ ordf => 'ª',
+ laquo => '«',
+'not' => '¬', # not is a keyword in perl
+ shy => '­',
+ macr => '¯',
+ deg => '°',
+ plusmn => '±',
+ sup1 => '¹',
+ sup2 => '²',
+ sup3 => '³',
+ acute => '´',
+ micro => 'µ',
+ para => '¶',
+ middot => '·',
+ cedil => '¸',
+ ordm => 'º',
+ raquo => '»',
+ frac14 => '¼',
+ frac12 => '½',
+ frac34 => '¾',
+ iquest => '¿',
+'times' => '×', # times is a keyword in perl
+ divide => '÷',
+
+# some POD special entities
+ verbar => '|',
+ sol => '/'
+);
+
+##---------------------------------------------------------------------------
+
+##---------------------------------
+## Function definitions begin here
+##---------------------------------
+
+sub podchecker( $ ; $ % ) {
+ my ($infile, $outfile, %options) = @_;
+ local $_;
+
+ ## Set defaults
+ $infile ||= \*STDIN;
+ $outfile ||= \*STDERR;
+
+ ## Now create a pod checker
+ my $checker = new Pod::Checker(%options);
+
+ ## Now check the pod document for errors
+ $checker->parse_from_file($infile, $outfile);
+
+ ## Return the number of errors found
+ return $checker->num_errors();
+}
+
+##---------------------------------------------------------------------------
+
+##-------------------------------
+## Method definitions begin here
+##-------------------------------
+
+##################################
+
+=over 4
+
+=item C<Pod::Checker-E<gt>new( %options )>
+
+Return a reference to a new Pod::Checker object that inherits from
+Pod::Parser and is used for calling the required methods later. The
+following options are recognized:
+
+C<-warnings =E<gt> num>
+ Print warnings if C<num> is true. The higher the value of C<num>,
+the more warnings are printed. Currently there are only levels 1 and 2.
+
+C<-quiet =E<gt> num>
+ If C<num> is true, do not print any errors/warnings. This is useful
+when Pod::Checker is used to munge POD code into plain text from within
+POD formatters.
+
+=cut
+
+## sub new {
+## my $this = shift;
+## my $class = ref($this) || $this;
+## my %params = @_;
+## my $self = {%params};
+## bless $self, $class;
+## $self->initialize();
+## return $self;
+## }
+
+sub initialize {
+ my $self = shift;
+ ## Initialize number of errors, and setup an error function to
+ ## increment this number and then print to the designated output.
+ $self->{_NUM_ERRORS} = 0;
+ $self->{_NUM_WARNINGS} = 0;
+ $self->{-quiet} ||= 0;
+ # set the error handling subroutine
+ $self->errorsub($self->{-quiet} ? sub { 1; } : 'poderror');
+ $self->{_commands} = 0; # total number of POD commands encountered
+ $self->{_list_stack} = []; # stack for nested lists
+ $self->{_have_begin} = ''; # stores =begin
+ $self->{_links} = []; # stack for internal hyperlinks
+ $self->{_nodes} = []; # stack for =head/=item nodes
+ $self->{_index} = []; # text in X<>
+ # print warnings?
+ $self->{-warnings} = 1 unless(defined $self->{-warnings});
+ $self->{_current_head1} = ''; # the current =head1 block
+ $self->parseopts(-process_cut_cmd => 1, -warnings => $self->{-warnings});
+}
+
+##################################
+
+=item C<$checker-E<gt>poderror( @args )>
+
+=item C<$checker-E<gt>poderror( {%opts}, @args )>
+
+Internal method for printing errors and warnings. If no options are
+given, simply prints "@_". The following options are recognized and used
+to form the output:
+
+ -msg
+
+A message to print prior to C<@args>.
+
+ -line
+
+The line number the error occurred in.
+
+ -file
+
+The file (name) the error occurred in.
+
+ -severity
+
+The error level, should be 'WARNING' or 'ERROR'.
+
+=cut
+
+# Invoked as $self->poderror( @args ), or $self->poderror( {%opts}, @args )
+sub poderror {
+ my $self = shift;
+ my %opts = (ref $_[0]) ? %{shift()} : ();
+
+ ## Retrieve options
+ chomp( my $msg = ($opts{-msg} || "")."@_" );
+ my $line = (exists $opts{-line}) ? " at line $opts{-line}" : "";
+ my $file = (exists $opts{-file}) ? " in file $opts{-file}" : "";
+ unless (exists $opts{-severity}) {
+ ## See if can find severity in message prefix
+ $opts{-severity} = $1 if ( $msg =~ s/^\**\s*([A-Z]{3,}):\s+// );
+ }
+ my $severity = (exists $opts{-severity}) ? "*** $opts{-severity}: " : "";
+
+ ## Increment error count and print message "
+ ++($self->{_NUM_ERRORS})
+ if(!%opts || ($opts{-severity} && $opts{-severity} eq 'ERROR'));
+ ++($self->{_NUM_WARNINGS})
+ if(!%opts || ($opts{-severity} && $opts{-severity} eq 'WARNING'));
+ unless($self->{-quiet}) {
+ my $out_fh = $self->output_handle() || \*STDERR;
+ print $out_fh ($severity, $msg, $line, $file, "\n")
+ if($self->{-warnings} || !%opts || $opts{-severity} ne 'WARNING');
+ }
+}
+
+##################################
+
+=item C<$checker-E<gt>num_errors()>
+
+Set (if argument specified) and retrieve the number of errors found.
+
+=cut
+
+sub num_errors {
+ return (@_ > 1) ? ($_[0]->{_NUM_ERRORS} = $_[1]) : $_[0]->{_NUM_ERRORS};
+}
+
+##################################
+
+=item C<$checker-E<gt>num_warnings()>
+
+Set (if argument specified) and retrieve the number of warnings found.
+
+=cut
+
+sub num_warnings {
+ return (@_ > 1) ? ($_[0]->{_NUM_WARNINGS} = $_[1]) : $_[0]->{_NUM_WARNINGS};
+}
+
+##################################
+
+=item C<$checker-E<gt>name()>
+
+Set (if argument specified) and retrieve the canonical name of POD as
+found in the C<=head1 NAME> section.
+
+=cut
+
+sub name {
+ return (@_ > 1 && $_[1]) ?
+ ($_[0]->{-name} = $_[1]) : $_[0]->{-name};
+}
+
+##################################
+
+=item C<$checker-E<gt>node()>
+
+Add (if argument specified) and retrieve the nodes (as defined by C<=headX>
+and C<=item>) of the current POD. The nodes are returned in the order of
+their occurrence. They consist of plain text, each piece of whitespace is
+collapsed to a single blank.
+
+=cut
+
+sub node {
+ my ($self,$text) = @_;
+ if(defined $text) {
+ $text =~ s/\s+$//s; # strip trailing whitespace
+ $text =~ s/\s+/ /gs; # collapse whitespace
+ # add node, order important!
+ push(@{$self->{_nodes}}, $text);
+ # keep also a uniqueness counter
+ $self->{_unique_nodes}->{$text}++ if($text !~ /^\s*$/s);
+ return $text;
+ }
+ @{$self->{_nodes}};
+}
+
+##################################
+
+=item C<$checker-E<gt>idx()>
+
+Add (if argument specified) and retrieve the index entries (as defined by
+C<XE<lt>E<gt>>) of the current POD. They consist of plain text, each piece
+of whitespace is collapsed to a single blank.
+
+=cut
+
+# set/return index entries of current POD
+sub idx {
+ my ($self,$text) = @_;
+ if(defined $text) {
+ $text =~ s/\s+$//s; # strip trailing whitespace
+ $text =~ s/\s+/ /gs; # collapse whitespace
+ # add node, order important!
+ push(@{$self->{_index}}, $text);
+ # keep also a uniqueness counter
+ $self->{_unique_nodes}->{$text}++ if($text !~ /^\s*$/s);
+ return $text;
+ }
+ @{$self->{_index}};
+}
+
+##################################
+
+=item C<$checker-E<gt>hyperlink()>
+
+Add (if argument specified) and retrieve the hyperlinks (as defined by
+C<LE<lt>E<gt>>) of the current POD. They consist of a 2-item array: line
+number and C<Pod::Hyperlink> object.
+
+=back
+
+=cut
+
+# set/return hyperlinks of the current POD
+sub hyperlink {
+ my $self = shift;
+ if($_[0]) {
+ push(@{$self->{_links}}, $_[0]);
+ return $_[0];
+ }
+ @{$self->{_links}};
+}
+
+## overrides for Pod::Parser
+
+sub end_pod {
+ ## Do some final checks and
+ ## print the number of errors found
+ my $self = shift;
+ my $infile = $self->input_file();
+
+ if(@{$self->{_list_stack}}) {
+ my $list;
+ while(($list = $self->_close_list('EOF',$infile)) &&
+ $list->indent() ne 'auto') {
+ $self->poderror({ -line => 'EOF', -file => $infile,
+ -severity => 'ERROR', -msg => "=over on line " .
+ $list->start() . " without closing =back" }); #"
+ }
+ }
+
+ # check validity of document internal hyperlinks
+ # first build the node names from the paragraph text
+ my %nodes;
+ foreach($self->node()) {
+ $nodes{$_} = 1;
+ if(/^(\S+)\s+\S/) {
+ # we have more than one word. Use the first as a node, too.
+ # This is used heavily in perlfunc.pod
+ $nodes{$1} ||= 2; # derived node
+ }
+ }
+ foreach($self->idx()) {
+ $nodes{$_} = 3; # index node
+ }
+ foreach($self->hyperlink()) {
+ my ($line,$link) = @$_;
+ # _TODO_ what if there is a link to the page itself by the name,
+ # e.g. in Tk::Pod : L<Tk::Pod/"DESCRIPTION">
+ if($link->node() && !$link->page() && $link->type() ne 'hyperlink') {
+ my $node = $self->_check_ptree($self->parse_text($link->node(),
+ $line), $line, $infile, 'L');
+ if($node && !$nodes{$node}) {
+ $self->poderror({ -line => $line || '', -file => $infile,
+ -severity => 'ERROR',
+ -msg => "unresolved internal link '$node'"});
+ }
+ }
+ }
+
+ # check the internal nodes for uniqueness. This pertains to
+ # =headX, =item and X<...>
+ if($self->{-warnings} && $self->{-warnings}>1) {
+ foreach(grep($self->{_unique_nodes}->{$_} > 1,
+ keys %{$self->{_unique_nodes}})) {
+ $self->poderror({ -line => '-', -file => $infile,
+ -severity => 'WARNING',
+ -msg => "multiple occurrence of link target '$_'"});
+ }
+ }
+
+ # no POD found here
+ $self->num_errors(-1) if($self->{_commands} == 0);
+}
+
+# check a POD command directive
+sub command {
+ my ($self, $cmd, $paragraph, $line_num, $pod_para) = @_;
+ my ($file, $line) = $pod_para->file_line;
+ ## Check the command syntax
+ my $arg; # this will hold the command argument
+ if (! $VALID_COMMANDS{$cmd}) {
+ $self->poderror({ -line => $line, -file => $file, -severity => 'ERROR',
+ -msg => "Unknown command '$cmd'" });
+ }
+ else { # found a valid command
+ $self->{_commands}++; # delete this line if below is enabled again
+
+ ##### following check disabled due to strong request
+ #if(!$self->{_commands}++ && $cmd !~ /^head/) {
+ # $self->poderror({ -line => $line, -file => $file,
+ # -severity => 'WARNING',
+ # -msg => "file does not start with =head" });
+ #}
+
+ # check syntax of particular command
+ if($cmd eq 'over') {
+ # check for argument
+ $arg = $self->interpolate_and_check($paragraph, $line,$file);
+ my $indent = 4; # default
+ if($arg && $arg =~ /^\s*(\d+)\s*$/) {
+ $indent = $1;
+ }
+ # start a new list
+ $self->_open_list($indent,$line,$file);
+ }
+ elsif($cmd eq 'item') {
+ # are we in a list?
+ unless(@{$self->{_list_stack}}) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "=item without previous =over" });
+ # auto-open in case we encounter many more
+ $self->_open_list('auto',$line,$file);
+ }
+ my $list = $self->{_list_stack}->[0];
+ # check whether the previous item had some contents
+ if(defined $self->{_list_item_contents} &&
+ $self->{_list_item_contents} == 0) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "previous =item has no contents" });
+ }
+ if($list->{_has_par}) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "preceding non-item paragraph(s)" });
+ delete $list->{_has_par};
+ }
+ # check for argument
+ $arg = $self->interpolate_and_check($paragraph, $line, $file);
+ if($arg && $arg =~ /(\S+)/) {
+ $arg =~ s/[\s\n]+$//;
+ my $type;
+ if($arg =~ /^[*]\s*(\S*.*)/) {
+ $type = 'bullet';
+ $self->{_list_item_contents} = $1 ? 1 : 0;
+ $arg = $1;
+ }
+ elsif($arg =~ /^\d+\.?\s*(\S*)/) {
+ $type = 'number';
+ $self->{_list_item_contents} = $1 ? 1 : 0;
+ $arg = $1;
+ }
+ else {
+ $type = 'definition';
+ $self->{_list_item_contents} = 1;
+ }
+ my $first = $list->type();
+ if($first && $first ne $type) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "=item type mismatch ('$first' vs. '$type')"});
+ }
+ else { # first item
+ $list->type($type);
+ }
+ }
+ else {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "No argument for =item" });
+ $arg = ' '; # empty
+ $self->{_list_item_contents} = 0;
+ }
+ # add this item
+ $list->item($arg);
+ # remember this node
+ $self->node($arg);
+ }
+ elsif($cmd eq 'back') {
+ # check if we have an open list
+ unless(@{$self->{_list_stack}}) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "=back without previous =over" });
+ }
+ else {
+ # check for spurious characters
+ $arg = $self->interpolate_and_check($paragraph, $line,$file);
+ if($arg && $arg =~ /\S/) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "Spurious character(s) after =back" });
+ }
+ # close list
+ my $list = $self->_close_list($line,$file);
+ # check for empty lists
+ if(!$list->item() && $self->{-warnings}) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "No items in =over (at line " .
+ $list->start() . ") / =back list"}); #"
+ }
+ }
+ }
+ elsif($cmd =~ /^head(\d+)/) {
+ my $hnum = $1;
+ $self->{"_have_head_$hnum"}++; # count head types
+ if($hnum > 1 && !$self->{"_have_head_".($hnum -1)}) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "=head$hnum without preceding higher level"});
+ }
+ # check whether the previous =head section had some contents
+ if(defined $self->{_commands_in_head} &&
+ $self->{_commands_in_head} == 0 &&
+ defined $self->{_last_head} &&
+ $self->{_last_head} >= $hnum) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "empty section in previous paragraph"});
+ }
+ $self->{_commands_in_head} = -1;
+ $self->{_last_head} = $hnum;
+ # check if there is an open list
+ if(@{$self->{_list_stack}}) {
+ my $list;
+ while(($list = $self->_close_list($line,$file)) &&
+ $list->indent() ne 'auto') {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "=over on line ". $list->start() .
+ " without closing =back (at $cmd)" });
+ }
+ }
+ # remember this node
+ $arg = $self->interpolate_and_check($paragraph, $line,$file);
+ $arg =~ s/[\s\n]+$//s;
+ $self->node($arg);
+ unless(length($arg)) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "empty =$cmd"});
+ }
+ if($cmd eq 'head1') {
+ $self->{_current_head1} = $arg;
+ } else {
+ $self->{_current_head1} = '';
+ }
+ }
+ elsif($cmd eq 'begin') {
+ if($self->{_have_begin}) {
+ # already have a begin
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "Nested =begin's (first at line " .
+ $self->{_have_begin} . ")"});
+ }
+ else {
+ # check for argument
+ $arg = $self->interpolate_and_check($paragraph, $line,$file);
+ unless($arg && $arg =~ /(\S+)/) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "No argument for =begin"});
+ }
+ # remember the =begin
+ $self->{_have_begin} = "$line:$1";
+ }
+ }
+ elsif($cmd eq 'end') {
+ if($self->{_have_begin}) {
+ # close the existing =begin
+ $self->{_have_begin} = '';
+ # check for spurious characters
+ $arg = $self->interpolate_and_check($paragraph, $line,$file);
+ # the closing argument is optional
+ #if($arg && $arg =~ /\S/) {
+ # $self->poderror({ -line => $line, -file => $file,
+ # -severity => 'WARNING',
+ # -msg => "Spurious character(s) after =end" });
+ #}
+ }
+ else {
+ # don't have a matching =begin
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "=end without =begin" });
+ }
+ }
+ elsif($cmd eq 'for') {
+ unless($paragraph =~ /\s*(\S+)\s*/) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "=for without formatter specification" });
+ }
+ $arg = ''; # do not expand paragraph below
+ }
+ elsif($cmd =~ /^(pod|cut)$/) {
+ # check for argument
+ $arg = $self->interpolate_and_check($paragraph, $line,$file);
+ if($arg && $arg =~ /(\S+)/) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "Spurious text after =$cmd"});
+ }
+ }
+ $self->{_commands_in_head}++;
+ ## Check the interior sequences in the command-text
+ $self->interpolate_and_check($paragraph, $line,$file)
+ unless(defined $arg);
+ }
+}
+
+sub _open_list
+{
+ my ($self,$indent,$line,$file) = @_;
+ my $list = Pod::List->new(
+ -indent => $indent,
+ -start => $line,
+ -file => $file);
+ unshift(@{$self->{_list_stack}}, $list);
+ undef $self->{_list_item_contents};
+ $list;
+}
+
+sub _close_list
+{
+ my ($self,$line,$file) = @_;
+ my $list = shift(@{$self->{_list_stack}});
+ if(defined $self->{_list_item_contents} &&
+ $self->{_list_item_contents} == 0) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "previous =item has no contents" });
+ }
+ undef $self->{_list_item_contents};
+ $list;
+}
+
+# process a block of some text
+sub interpolate_and_check {
+ my ($self, $paragraph, $line, $file) = @_;
+ ## Check the interior sequences in the command-text
+ # and return the text
+ $self->_check_ptree(
+ $self->parse_text($paragraph,$line), $line, $file, '');
+}
+
+sub _check_ptree {
+ my ($self,$ptree,$line,$file,$nestlist) = @_;
+ local($_);
+ my $text = '';
+ # process each node in the parse tree
+ foreach(@$ptree) {
+ # regular text chunk
+ unless(ref) {
+ # count the unescaped angle brackets
+ # complain only when warning level is greater than 1
+ if($self->{-warnings} && $self->{-warnings}>1) {
+ my $count;
+ if($count = tr/<>/<>/) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "$count unescaped <> in paragraph" });
+ }
+ }
+ $text .= $_;
+ next;
+ }
+ # have an interior sequence
+ my $cmd = $_->cmd_name();
+ my $contents = $_->parse_tree();
+ ($file,$line) = $_->file_line();
+ # check for valid tag
+ if (! $VALID_SEQUENCES{$cmd}) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => qq(Unknown interior-sequence '$cmd')});
+ # expand it anyway
+ $text .= $self->_check_ptree($contents, $line, $file, "$nestlist$cmd");
+ next;
+ }
+ if($nestlist =~ /$cmd/) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "nested commands $cmd<...$cmd<...>...>"});
+ # _TODO_ should we add the contents anyway?
+ # expand it anyway, see below
+ }
+ if($cmd eq 'E') {
+ # preserve entities
+ if(@$contents > 1 || ref $$contents[0] || $$contents[0] !~ /^\w+$/) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "garbled entity " . $_->raw_text()});
+ next;
+ }
+ my $ent = $$contents[0];
+ my $val;
+ if($ent =~ /^0x[0-9a-f]+$/i) {
+ # hexadec entity
+ $val = hex($ent);
+ }
+ elsif($ent =~ /^0\d+$/) {
+ # octal
+ $val = oct($ent);
+ }
+ elsif($ent =~ /^\d+$/) {
+ # numeric entity
+ $val = $ent;
+ }
+ if(defined $val) {
+ if($val>0 && $val<256) {
+ $text .= chr($val);
+ }
+ else {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "Entity number out of range " . $_->raw_text()});
+ }
+ }
+ elsif($ENTITIES{$ent}) {
+ # known ISO entity
+ $text .= $ENTITIES{$ent};
+ }
+ else {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => "Unknown entity " . $_->raw_text()});
+ $text .= "E<$ent>";
+ }
+ }
+ elsif($cmd eq 'L') {
+ # try to parse the hyperlink
+ my $link = Pod::Hyperlink->new($contents->raw_text());
+ unless(defined $link) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "malformed link " . $_->raw_text() ." : $@"});
+ next;
+ }
+ $link->line($line); # remember line
+ if($self->{-warnings}) {
+ foreach my $w ($link->warning()) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => $w });
+ }
+ }
+ # check the link text
+ $text .= $self->_check_ptree($self->parse_text($link->text(),
+ $line), $line, $file, "$nestlist$cmd");
+ # remember link
+ $self->hyperlink([$line,$link]);
+ }
+ elsif($cmd =~ /[BCFIS]/) {
+ # add the guts
+ $text .= $self->_check_ptree($contents, $line, $file, "$nestlist$cmd");
+ }
+ elsif($cmd eq 'Z') {
+ if(length($contents->raw_text())) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "Nonempty Z<>"});
+ }
+ }
+ elsif($cmd eq 'X') {
+ my $idx = $self->_check_ptree($contents, $line, $file, "$nestlist$cmd");
+ if($idx =~ /^\s*$/s) {
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'ERROR',
+ -msg => "Empty X<>"});
+ }
+ else {
+ # remember this node
+ $self->idx($idx);
+ }
+ }
+ else {
+ # not reached
+ die "internal error";
+ }
+ }
+ $text;
+}
+
+# process a block of verbatim text
+sub verbatim {
+ ## Nothing particular to check
+ my ($self, $paragraph, $line_num, $pod_para) = @_;
+
+ $self->_preproc_par($paragraph);
+
+ if($self->{_current_head1} eq 'NAME') {
+ my ($file, $line) = $pod_para->file_line;
+ $self->poderror({ -line => $line, -file => $file,
+ -severity => 'WARNING',
+ -msg => 'Verbatim paragraph in NAME section' });
+ }
+}
+
+# process a block of regular text
+sub textblock {
+ my ($self, $paragraph, $line_num, $pod_para) = @_;
+ my ($file, $line) = $pod_para->file_line;
+
+ $self->_preproc_par($paragraph);
+
+ # skip this paragraph if in a =begin block
+ unless($self->{_have_begin}) {
+ my $block = $self->interpolate_and_check($paragraph, $line,$file);
+ if($self->{_current_head1} eq 'NAME') {
+ if($block =~ /^\s*(\S+?)\s*[,-]/) {
+ # this is the canonical name
+ $self->{-name} = $1 unless(defined $self->{-name});
+ }
+ }
+ }
+}
+
+sub _preproc_par
+{
+ my $self = shift;
+ $_[0] =~ s/[\s\n]+$//;
+ if($_[0]) {
+ $self->{_commands_in_head}++;
+ $self->{_list_item_contents}++ if(defined $self->{_list_item_contents});
+ if(@{$self->{_list_stack}} && !$self->{_list_stack}->[0]->item()) {
+ $self->{_list_stack}->[0]->{_has_par} = 1;
+ }
+ }
+}
+
+1;
+
+__END__
+
+=head1 AUTHOR
+
+Please report bugs using L<http://rt.cpan.org>.
+
+Brad Appleton E<lt>bradapp@enteract.comE<gt> (initial version),
+Marek Rouchal E<lt>marekr@cpan.orgE<gt>
+
+Based on code for B<Pod::Text::pod2text()> written by
+Tom Christiansen E<lt>tchrist@mox.perl.comE<gt>
+
+=cut
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Find.pm b/Master/tlpkg/tlperl/lib/Pod/Find.pm
new file mode 100644
index 00000000000..0b085b8c9e3
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Find.pm
@@ -0,0 +1,523 @@
+#############################################################################
+# Pod/Find.pm -- finds files containing POD documentation
+#
+# Author: Marek Rouchal <marekr@cpan.org>
+#
+# Copyright (C) 1999-2000 by Marek Rouchal (and borrowing code
+# from Nick Ing-Simmon's PodToHtml). All rights reserved.
+# This file is part of "PodParser". Pod::Find is free software;
+# you can redistribute it and/or modify it under the same terms
+# as Perl itself.
+#############################################################################
+
+package Pod::Find;
+
+use vars qw($VERSION);
+$VERSION = 1.34; ## Current version of this package
+require 5.005; ## requires this Perl version or later
+use Carp;
+
+#############################################################################
+
+=head1 NAME
+
+Pod::Find - find POD documents in directory trees
+
+=head1 SYNOPSIS
+
+ use Pod::Find qw(pod_find simplify_name);
+ my %pods = pod_find({ -verbose => 1, -inc => 1 });
+ foreach(keys %pods) {
+ print "found library POD `$pods{$_}' in $_\n";
+ }
+
+ print "podname=",simplify_name('a/b/c/mymodule.pod'),"\n";
+
+ $location = pod_where( { -inc => 1 }, "Pod::Find" );
+
+=head1 DESCRIPTION
+
+B<Pod::Find> provides a set of functions to locate POD files. Note that
+no function is exported by default to avoid pollution of your namespace,
+so be sure to specify them in the B<use> statement if you need them:
+
+ use Pod::Find qw(pod_find);
+
+From this version on the typical SCM (software configuration management)
+files/directories like RCS, CVS, SCCS, .svn are ignored.
+
+=cut
+
+use strict;
+#use diagnostics;
+use Exporter;
+use File::Spec;
+use File::Find;
+use Cwd;
+
+use vars qw(@ISA @EXPORT_OK $VERSION);
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(&pod_find &simplify_name &pod_where &contains_pod);
+
+# package global variables
+my $SIMPLIFY_RX;
+
+=head2 C<pod_find( { %opts } , @directories )>
+
+The function B<pod_find> searches for POD documents in a given set of
+files and/or directories. It returns a hash with the file names as keys
+and the POD name as value. The POD name is derived from the file name
+and its position in the directory tree.
+
+E.g. when searching in F<$HOME/perl5lib>, the file
+F<$HOME/perl5lib/MyModule.pm> would get the POD name I<MyModule>,
+whereas F<$HOME/perl5lib/Myclass/Subclass.pm> would be
+I<Myclass::Subclass>. The name information can be used for POD
+translators.
+
+Only text files containing at least one valid POD command are found.
+
+A warning is printed if more than one POD file with the same POD name
+is found, e.g. F<CPAN.pm> in different directories. This usually
+indicates duplicate occurrences of modules in the I<@INC> search path.
+
+B<OPTIONS> The first argument for B<pod_find> may be a hash reference
+with options. The rest are either directories that are searched
+recursively or files. The POD names of files are the plain basenames
+with any Perl-like extension (.pm, .pl, .pod) stripped.
+
+=over 4
+
+=item C<-verbose =E<gt> 1>
+
+Print progress information while scanning.
+
+=item C<-perl =E<gt> 1>
+
+Apply Perl-specific heuristics to find the correct PODs. This includes
+stripping Perl-like extensions, omitting subdirectories that are numeric
+but do I<not> match the current Perl interpreter's version id, suppressing
+F<site_perl> as a module hierarchy name etc.
+
+=item C<-script =E<gt> 1>
+
+Search for PODs in the current Perl interpreter's installation
+B<scriptdir>. This is taken from the local L<Config|Config> module.
+
+=item C<-inc =E<gt> 1>
+
+Search for PODs in the current Perl interpreter's I<@INC> paths. This
+automatically considers paths specified in the C<PERL5LIB> environment
+as this is prepended to I<@INC> by the Perl interpreter itself.
+
+=back
+
+=cut
+
+# return a hash of the POD files found
+# first argument may be a hashref (options),
+# rest is a list of directories to search recursively
+sub pod_find
+{
+ my %opts;
+ if(ref $_[0]) {
+ %opts = %{shift()};
+ }
+
+ $opts{-verbose} ||= 0;
+ $opts{-perl} ||= 0;
+
+ my (@search) = @_;
+
+ if($opts{-script}) {
+ require Config;
+ push(@search, $Config::Config{scriptdir})
+ if -d $Config::Config{scriptdir};
+ $opts{-perl} = 1;
+ }
+
+ if($opts{-inc}) {
+ if ($^O eq 'MacOS') {
+ # tolerate '.', './some_dir' and '(../)+some_dir' on Mac OS
+ my @new_INC = @INC;
+ for (@new_INC) {
+ if ( $_ eq '.' ) {
+ $_ = ':';
+ } elsif ( $_ =~ s|^((?:\.\./)+)|':' x (length($1)/3)|e ) {
+ $_ = ':'. $_;
+ } else {
+ $_ =~ s|^\./|:|;
+ }
+ }
+ push(@search, grep($_ ne File::Spec->curdir, @new_INC));
+ } else {
+ push(@search, grep($_ ne File::Spec->curdir, @INC));
+ }
+
+ $opts{-perl} = 1;
+ }
+
+ if($opts{-perl}) {
+ require Config;
+ # this code simplifies the POD name for Perl modules:
+ # * remove "site_perl"
+ # * remove e.g. "i586-linux" (from 'archname')
+ # * remove e.g. 5.00503
+ # * remove pod/ if followed by *.pod (e.g. in pod/perlfunc.pod)
+
+ # Mac OS:
+ # * remove ":?site_perl:"
+ # * remove :?pod: if followed by *.pod (e.g. in :pod:perlfunc.pod)
+
+ if ($^O eq 'MacOS') {
+ $SIMPLIFY_RX =
+ qq!^(?i:\:?site_perl\:|\:?pod\:(?=.*?\\.pod\\z))*!;
+ } else {
+ $SIMPLIFY_RX =
+ qq!^(?i:site(_perl)?/|\Q$Config::Config{archname}\E/|\\d+\\.\\d+([_.]?\\d+)?/|pod/(?=.*?\\.pod\\z))*!;
+ }
+ }
+
+ my %dirs_visited;
+ my %pods;
+ my %names;
+ my $pwd = cwd();
+
+ foreach my $try (@search) {
+ unless(File::Spec->file_name_is_absolute($try)) {
+ # make path absolute
+ $try = File::Spec->catfile($pwd,$try);
+ }
+ # simplify path
+ # on VMS canonpath will vmsify:[the.path], but File::Find::find
+ # wants /unixy/paths
+ $try = File::Spec->canonpath($try) if ($^O ne 'VMS');
+ $try = VMS::Filespec::unixify($try) if ($^O eq 'VMS');
+ my $name;
+ if(-f $try) {
+ if($name = _check_and_extract_name($try, $opts{-verbose})) {
+ _check_for_duplicates($try, $name, \%names, \%pods);
+ }
+ next;
+ }
+ my $root_rx = $^O eq 'MacOS' ? qq!^\Q$try\E! : qq!^\Q$try\E/!;
+ File::Find::find( sub {
+ my $item = $File::Find::name;
+ if(-d) {
+ if($item =~ m{/(?:RCS|CVS|SCCS|\.svn)$}) {
+ $File::Find::prune = 1;
+ return;
+ }
+ elsif($dirs_visited{$item}) {
+ warn "Directory '$item' already seen, skipping.\n"
+ if($opts{-verbose});
+ $File::Find::prune = 1;
+ return;
+ }
+ else {
+ $dirs_visited{$item} = 1;
+ }
+ if($opts{-perl} && /^(\d+\.[\d_]+)\z/s && eval "$1" != $]) {
+ $File::Find::prune = 1;
+ warn "Perl $] version mismatch on $_, skipping.\n"
+ if($opts{-verbose});
+ }
+ return;
+ }
+ if($name = _check_and_extract_name($item, $opts{-verbose}, $root_rx)) {
+ _check_for_duplicates($item, $name, \%names, \%pods);
+ }
+ }, $try); # end of File::Find::find
+ }
+ chdir $pwd;
+ %pods;
+}
+
+sub _check_for_duplicates {
+ my ($file, $name, $names_ref, $pods_ref) = @_;
+ if($$names_ref{$name}) {
+ warn "Duplicate POD found (shadowing?): $name ($file)\n";
+ warn " Already seen in ",
+ join(' ', grep($$pods_ref{$_} eq $name, keys %$pods_ref)),"\n";
+ }
+ else {
+ $$names_ref{$name} = 1;
+ }
+ $$pods_ref{$file} = $name;
+}
+
+sub _check_and_extract_name {
+ my ($file, $verbose, $root_rx) = @_;
+
+ # check extension or executable flag
+ # this involves testing the .bat extension on Win32!
+ unless(-f $file && -T $file && ($file =~ /\.(pod|pm|plx?)\z/i || -x $file )) {
+ return undef;
+ }
+
+ return undef unless contains_pod($file,$verbose);
+
+ # strip non-significant path components
+ # TODO what happens on e.g. Win32?
+ my $name = $file;
+ if(defined $root_rx) {
+ $name =~ s!$root_rx!!s;
+ $name =~ s!$SIMPLIFY_RX!!os if(defined $SIMPLIFY_RX);
+ }
+ else {
+ if ($^O eq 'MacOS') {
+ $name =~ s/^.*://s;
+ } else {
+ $name =~ s:^.*/::s;
+ }
+ }
+ _simplify($name);
+ $name =~ s!/+!::!g; #/
+ if ($^O eq 'MacOS') {
+ $name =~ s!:+!::!g; # : -> ::
+ } else {
+ $name =~ s!/+!::!g; # / -> ::
+ }
+ $name;
+}
+
+=head2 C<simplify_name( $str )>
+
+The function B<simplify_name> is equivalent to B<basename>, but also
+strips Perl-like extensions (.pm, .pl, .pod) and extensions like
+F<.bat>, F<.cmd> on Win32 and OS/2, or F<.com> on VMS, respectively.
+
+=cut
+
+# basic simplification of the POD name:
+# basename & strip extension
+sub simplify_name {
+ my ($str) = @_;
+ # remove all path components
+ if ($^O eq 'MacOS') {
+ $str =~ s/^.*://s;
+ } else {
+ $str =~ s:^.*/::s;
+ }
+ _simplify($str);
+ $str;
+}
+
+# internal sub only
+sub _simplify {
+ # strip Perl's own extensions
+ $_[0] =~ s/\.(pod|pm|plx?)\z//i;
+ # strip meaningless extensions on Win32 and OS/2
+ $_[0] =~ s/\.(bat|exe|cmd)\z//i if($^O =~ /mswin|os2/i);
+ # strip meaningless extensions on VMS
+ $_[0] =~ s/\.(com)\z//i if($^O eq 'VMS');
+}
+
+# contribution from Tim Jenness <t.jenness@jach.hawaii.edu>
+
+=head2 C<pod_where( { %opts }, $pod )>
+
+Returns the location of a pod document given a search directory
+and a module (e.g. C<File::Find>) or script (e.g. C<perldoc>) name.
+
+Options:
+
+=over 4
+
+=item C<-inc =E<gt> 1>
+
+Search @INC for the pod and also the C<scriptdir> defined in the
+L<Config|Config> module.
+
+=item C<-dirs =E<gt> [ $dir1, $dir2, ... ]>
+
+Reference to an array of search directories. These are searched in order
+before looking in C<@INC> (if B<-inc>). Current directory is used if
+none are specified.
+
+=item C<-verbose =E<gt> 1>
+
+List directories as they are searched
+
+=back
+
+Returns the full path of the first occurrence to the file.
+Package names (eg 'A::B') are automatically converted to directory
+names in the selected directory. (eg on unix 'A::B' is converted to
+'A/B'). Additionally, '.pm', '.pl' and '.pod' are appended to the
+search automatically if required.
+
+A subdirectory F<pod/> is also checked if it exists in any of the given
+search directories. This ensures that e.g. L<perlfunc|perlfunc> is
+found.
+
+It is assumed that if a module name is supplied, that that name
+matches the file name. Pods are not opened to check for the 'NAME'
+entry.
+
+A check is made to make sure that the file that is found does
+contain some pod documentation.
+
+=cut
+
+sub pod_where {
+
+ # default options
+ my %options = (
+ '-inc' => 0,
+ '-verbose' => 0,
+ '-dirs' => [ File::Spec->curdir ],
+ );
+
+ # Check for an options hash as first argument
+ if (defined $_[0] && ref($_[0]) eq 'HASH') {
+ my $opt = shift;
+
+ # Merge default options with supplied options
+ %options = (%options, %$opt);
+ }
+
+ # Check usage
+ carp 'Usage: pod_where({options}, $pod)' unless (scalar(@_));
+
+ # Read argument
+ my $pod = shift;
+
+ # Split on :: and then join the name together using File::Spec
+ my @parts = split (/::/, $pod);
+
+ # Get full directory list
+ my @search_dirs = @{ $options{'-dirs'} };
+
+ if ($options{'-inc'}) {
+
+ require Config;
+
+ # Add @INC
+ if ($^O eq 'MacOS' && $options{'-inc'}) {
+ # tolerate '.', './some_dir' and '(../)+some_dir' on Mac OS
+ my @new_INC = @INC;
+ for (@new_INC) {
+ if ( $_ eq '.' ) {
+ $_ = ':';
+ } elsif ( $_ =~ s|^((?:\.\./)+)|':' x (length($1)/3)|e ) {
+ $_ = ':'. $_;
+ } else {
+ $_ =~ s|^\./|:|;
+ }
+ }
+ push (@search_dirs, @new_INC);
+ } elsif ($options{'-inc'}) {
+ push (@search_dirs, @INC);
+ }
+
+ # Add location of pod documentation for perl man pages (eg perlfunc)
+ # This is a pod directory in the private install tree
+ #my $perlpoddir = File::Spec->catdir($Config::Config{'installprivlib'},
+ # 'pod');
+ #push (@search_dirs, $perlpoddir)
+ # if -d $perlpoddir;
+
+ # Add location of binaries such as pod2text
+ push (@search_dirs, $Config::Config{'scriptdir'})
+ if -d $Config::Config{'scriptdir'};
+ }
+
+ warn "Search path is: ".join(' ', @search_dirs)."\n"
+ if $options{'-verbose'};
+
+ # Loop over directories
+ Dir: foreach my $dir ( @search_dirs ) {
+
+ # Don't bother if can't find the directory
+ if (-d $dir) {
+ warn "Looking in directory $dir\n"
+ if $options{'-verbose'};
+
+ # Now concatenate this directory with the pod we are searching for
+ my $fullname = File::Spec->catfile($dir, @parts);
+ warn "Filename is now $fullname\n"
+ if $options{'-verbose'};
+
+ # Loop over possible extensions
+ foreach my $ext ('', '.pod', '.pm', '.pl') {
+ my $fullext = $fullname . $ext;
+ if (-f $fullext &&
+ contains_pod($fullext, $options{'-verbose'}) ) {
+ warn "FOUND: $fullext\n" if $options{'-verbose'};
+ return $fullext;
+ }
+ }
+ } else {
+ warn "Directory $dir does not exist\n"
+ if $options{'-verbose'};
+ next Dir;
+ }
+ # for some strange reason the path on MacOS/darwin/cygwin is
+ # 'pods' not 'pod'
+ # this could be the case also for other systems that
+ # have a case-tolerant file system, but File::Spec
+ # does not recognize 'darwin' yet. And cygwin also has "pods",
+ # but is not case tolerant. Oh well...
+ if((File::Spec->case_tolerant || $^O =~ /macos|darwin|cygwin/i)
+ && -d File::Spec->catdir($dir,'pods')) {
+ $dir = File::Spec->catdir($dir,'pods');
+ redo Dir;
+ }
+ if(-d File::Spec->catdir($dir,'pod')) {
+ $dir = File::Spec->catdir($dir,'pod');
+ redo Dir;
+ }
+ }
+ # No match;
+ return undef;
+}
+
+=head2 C<contains_pod( $file , $verbose )>
+
+Returns true if the supplied filename (not POD module) contains some pod
+information.
+
+=cut
+
+sub contains_pod {
+ my $file = shift;
+ my $verbose = 0;
+ $verbose = shift if @_;
+
+ # check for one line of POD
+ unless(open(POD,"<$file")) {
+ warn "Error: $file is unreadable: $!\n";
+ return undef;
+ }
+
+ local $/ = undef;
+ my $pod = <POD>;
+ close(POD) || die "Error closing $file: $!\n";
+ unless($pod =~ /^=(head\d|pod|over|item)\b/m) {
+ warn "No POD in $file, skipping.\n"
+ if($verbose);
+ return 0;
+ }
+
+ return 1;
+}
+
+=head1 AUTHOR
+
+Please report bugs using L<http://rt.cpan.org>.
+
+Marek Rouchal E<lt>marekr@cpan.orgE<gt>,
+heavily borrowing code from Nick Ing-Simmons' PodToHtml.
+
+Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt> provided
+C<pod_where> and C<contains_pod>.
+
+=head1 SEE ALSO
+
+L<Pod::Parser>, L<Pod::Checker>, L<perldoc>
+
+=cut
+
+1;
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Functions.pm b/Master/tlpkg/tlperl/lib/Pod/Functions.pm
new file mode 100644
index 00000000000..0e250cf0b50
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Functions.pm
@@ -0,0 +1,376 @@
+package Pod::Functions;
+use strict;
+
+=head1 NAME
+
+Pod::Functions - Group Perl's functions a la perlfunc.pod
+
+=head1 SYNOPSIS
+
+ use Pod::Functions;
+
+ my @misc_ops = @{ $Kinds{ 'Misc' } };
+ my $misc_dsc = $Type_Description{ 'Misc' };
+
+or
+
+ perl /path/to/lib/Pod/Functions.pm
+
+This will print a grouped list of Perl's functions, like the
+L<perlfunc/"Perl Functions by Category"> section.
+
+=head1 DESCRIPTION
+
+It exports the following variables:
+
+=over 4
+
+=item %Kinds
+
+This holds a hash-of-lists. Each list contains the functions in the category
+the key denotes.
+
+=item %Type
+
+In this hash each key represents a function and the value is the category.
+The category can be a comma separated list.
+
+=item %Flavor
+
+In this hash each key represents a function and the value is a short
+description of that function.
+
+=item %Type_Description
+
+In this hash each key represents a category of functions and the value is
+a short description of that category.
+
+=item @Type_Order
+
+This list of categories is used to produce the same order as the
+L<perlfunc/"Perl Functions by Category"> section.
+
+=back
+
+=head1 CHANGES
+
+1.02 20020813 <abe@ztreet.demon.nl>
+ de-typo in the SYNOPSIS section (thanks Mike Castle for noticing)
+
+1.01 20011229 <abe@ztreet.demon.nl>
+ fixed some bugs that slipped in after 5.6.1
+ added the pod
+ finished making it strict safe
+
+1.00 ??
+ first numbered version
+
+=cut
+
+our $VERSION = '1.03';
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+our @EXPORT = qw(%Kinds %Type %Flavor %Type_Description @Type_Order);
+
+our(%Kinds, %Type, %Flavor);
+
+our %Type_Description = (
+ 'ARRAY' => 'Functions for real @ARRAYs',
+ 'Binary' => 'Functions for fixed length data or records',
+ 'File' => 'Functions for filehandles, files, or directories',
+ 'Flow' => 'Keywords related to control flow of your perl program',
+ 'HASH' => 'Functions for real %HASHes',
+ 'I/O' => 'Input and output functions',
+ 'LIST' => 'Functions for list data',
+ 'Math' => 'Numeric functions',
+ 'Misc' => 'Miscellaneous functions',
+ 'Modules' => 'Keywords related to perl modules',
+ 'Network' => 'Fetching network info',
+ 'Objects' => 'Keywords related to classes and object-orientedness',
+ 'Process' => 'Functions for processes and process groups',
+ 'Regexp' => 'Regular expressions and pattern matching',
+ 'Socket' => 'Low-level socket functions',
+ 'String' => 'Functions for SCALARs or strings',
+ 'SysV' => 'System V interprocess communication functions',
+ 'Time' => 'Time-related functions',
+ 'User' => 'Fetching user and group info',
+ 'Namespace' => 'Keywords altering or affecting scoping of identifiers',
+);
+
+our @Type_Order = qw{
+ String
+ Regexp
+ Math
+ ARRAY
+ LIST
+ HASH
+ I/O
+ Binary
+ File
+ Flow
+ Namespace
+ Misc
+ Process
+ Modules
+ Objects
+ Socket
+ SysV
+ User
+ Network
+ Time
+};
+
+while (<DATA>) {
+ chomp;
+ s/#.*//;
+ next unless $_;
+ my($name, $type, $text) = split " ", $_, 3;
+ $Type{$name} = $type;
+ $Flavor{$name} = $text;
+ for my $t ( split /[,\s]+/, $type ) {
+ push @{$Kinds{$t}}, $name;
+ }
+}
+
+close DATA;
+
+my( $typedesc, $list );
+unless (caller) {
+ foreach my $type ( @Type_Order ) {
+ $list = join(", ", sort @{$Kinds{$type}});
+ $typedesc = $Type_Description{$type} . ":";
+ write;
+ }
+}
+
+format =
+
+^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ $typedesc
+~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ $typedesc
+ ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ $list
+.
+
+1;
+
+__DATA__
+-X File a file test (-r, -x, etc)
+abs Math absolute value function
+accept Socket accept an incoming socket connect
+alarm Process schedule a SIGALRM
+atan2 Math arctangent of Y/X in the range -PI to PI
+bind Socket binds an address to a socket
+binmode I/O prepare binary files for I/O
+bless Objects create an object
+caller Flow,Namespace get context of the current subroutine call
+chdir File change your current working directory
+chmod File changes the permissions on a list of files
+chomp String remove a trailing record separator from a string
+chop String remove the last character from a string
+chown File change the owership on a list of files
+chr String get character this number represents
+chroot File make directory new root for path lookups
+close I/O close file (or pipe or socket) handle
+closedir I/O close directory handle
+connect Socket connect to a remote socket
+continue Flow optional trailing block in a while or foreach
+cos Math cosine function
+crypt String one-way passwd-style encryption
+dbmclose Objects,I/O breaks binding on a tied dbm file
+dbmopen Objects,I/O create binding on a tied dbm file
+defined Misc test whether a value, variable, or function is defined
+delete HASH deletes a value from a hash
+die I/O,Flow raise an exception or bail out
+do Flow,Modules turn a BLOCK into a TERM
+dump Misc,Flow create an immediate core dump
+each HASH retrieve the next key/value pair from a hash
+endgrent User be done using group file
+endhostent User be done using hosts file
+endnetent User be done using networks file
+endprotoent Network be done using protocols file
+endpwent User be done using passwd file
+endservent Network be done using services file
+eof I/O test a filehandle for its end
+eval Flow,Misc catch exceptions or compile and run code
+exec Process abandon this program to run another
+exists HASH test whether a hash key is present
+exit Flow terminate this program
+exp Math raise I<e> to a power
+fcntl File file control system call
+fileno I/O return file descriptor from filehandle
+flock I/O lock an entire file with an advisory lock
+fork Process create a new process just like this one
+format I/O declare a picture format with use by the write() function
+formline Misc internal function used for formats
+getc I/O get the next character from the filehandle
+getgrent User get next group record
+getgrgid User get group record given group user ID
+getgrnam User get group record given group name
+gethostbyaddr Network get host record given its address
+gethostbyname Network get host record given name
+gethostent Network get next hosts record
+getlogin User return who logged in at this tty
+getnetbyaddr Network get network record given its address
+getnetbyname Network get networks record given name
+getnetent Network get next networks record
+getpeername Socket find the other end of a socket connection
+getpgrp Process get process group
+getppid Process get parent process ID
+getpriority Process get current nice value
+getprotobyname Network get protocol record given name
+getprotobynumber Network get protocol record numeric protocol
+getprotoent Network get next protocols record
+getpwent User get next passwd record
+getpwnam User get passwd record given user login name
+getpwuid User get passwd record given user ID
+getservbyname Network get services record given its name
+getservbyport Network get services record given numeric port
+getservent Network get next services record
+getsockname Socket retrieve the sockaddr for a given socket
+getsockopt Socket get socket options on a given socket
+glob File expand filenames using wildcards
+gmtime Time convert UNIX time into record or string using Greenwich time
+goto Flow create spaghetti code
+grep LIST locate elements in a list test true against a given criterion
+hex Math,String convert a string to a hexadecimal number
+import Modules,Namespace patch a module's namespace into your own
+index String find a substring within a string
+int Math get the integer portion of a number
+ioctl File system-dependent device control system call
+join LIST join a list into a string using a separator
+keys HASH retrieve list of indices from a hash
+kill Process send a signal to a process or process group
+last Flow exit a block prematurely
+lc String return lower-case version of a string
+lcfirst String return a string with just the next letter in lower case
+length String return the number of bytes in a string
+link File create a hard link in the filesytem
+listen Socket register your socket as a server
+local Misc,Namespace create a temporary value for a global variable (dynamic scoping)
+localtime Time convert UNIX time into record or string using local time
+lock Threads get a thread lock on a variable, subroutine, or method
+log Math retrieve the natural logarithm for a number
+lstat File stat a symbolic link
+m// Regexp match a string with a regular expression pattern
+map LIST apply a change to a list to get back a new list with the changes
+mkdir File create a directory
+msgctl SysV SysV IPC message control operations
+msgget SysV get SysV IPC message queue
+msgrcv SysV receive a SysV IPC message from a message queue
+msgsnd SysV send a SysV IPC message to a message queue
+my Misc,Namespace declare and assign a local variable (lexical scoping)
+next Flow iterate a block prematurely
+no Modules unimport some module symbols or semantics at compile time
+package Modules,Objects,Namespace declare a separate global namespace
+prototype Flow,Misc get the prototype (if any) of a subroutine
+oct String,Math convert a string to an octal number
+open File open a file, pipe, or descriptor
+opendir File open a directory
+ord String find a character's numeric representation
+our Misc,Namespace declare and assign a package variable (lexical scoping)
+pack Binary,String convert a list into a binary representation
+pipe Process open a pair of connected filehandles
+pop ARRAY remove the last element from an array and return it
+pos Regexp find or set the offset for the last/next m//g search
+print I/O output a list to a filehandle
+printf I/O output a formatted list to a filehandle
+push ARRAY append one or more elements to an array
+q/STRING/ String singly quote a string
+qq/STRING/ String doubly quote a string
+quotemeta Regexp quote regular expression magic characters
+qw/STRING/ LIST quote a list of words
+qx/STRING/ Process backquote quote a string
+qr/STRING/ Regexp Compile pattern
+rand Math retrieve the next pseudorandom number
+read I/O,Binary fixed-length buffered input from a filehandle
+readdir I/O get a directory from a directory handle
+readline I/O fetch a record from a file
+readlink File determine where a symbolic link is pointing
+readpipe Process execute a system command and collect standard output
+recv Socket receive a message over a Socket
+redo Flow start this loop iteration over again
+ref Objects find out the type of thing being referenced
+rename File change a filename
+require Modules load in external functions from a library at runtime
+reset Misc clear all variables of a given name
+return Flow get out of a function early
+reverse String,LIST flip a string or a list
+rewinddir I/O reset directory handle
+rindex String right-to-left substring search
+rmdir File remove a directory
+s/// Regexp replace a pattern with a string
+scalar Misc force a scalar context
+seek I/O reposition file pointer for random-access I/O
+seekdir I/O reposition directory pointer
+select I/O reset default output or do I/O multiplexing
+semctl SysV SysV semaphore control operations
+semget SysV get set of SysV semaphores
+semop SysV SysV semaphore operations
+send Socket send a message over a socket
+setgrent User prepare group file for use
+sethostent Network prepare hosts file for use
+setnetent Network prepare networks file for use
+setpgrp Process set the process group of a process
+setpriority Process set a process's nice value
+setprotoent Network prepare protocols file for use
+setpwent User prepare passwd file for use
+setservent Network prepare services file for use
+setsockopt Socket set some socket options
+shift ARRAY remove the first element of an array, and return it
+shmctl SysV SysV shared memory operations
+shmget SysV get SysV shared memory segment identifier
+shmread SysV read SysV shared memory
+shmwrite SysV write SysV shared memory
+shutdown Socket close down just half of a socket connection
+sin Math return the sine of a number
+sleep Process block for some number of seconds
+socket Socket create a socket
+socketpair Socket create a pair of sockets
+sort LIST sort a list of values
+splice ARRAY add or remove elements anywhere in an array
+split Regexp split up a string using a regexp delimiter
+sprintf String formatted print into a string
+sqrt Math square root function
+srand Math seed the random number generator
+stat File get a file's status information
+study Regexp optimize input data for repeated searches
+sub Flow declare a subroutine, possibly anonymously
+substr String get or alter a portion of a stirng
+symlink File create a symbolic link to a file
+syscall I/O,Binary execute an arbitrary system call
+sysopen File open a file, pipe, or descriptor
+sysread I/O,Binary fixed-length unbuffered input from a filehandle
+sysseek I/O,Binary position I/O pointer on handle used with sysread and syswrite
+system Process run a separate program
+syswrite I/O,Binary fixed-length unbuffered output to a filehandle
+tell I/O get current seekpointer on a filehandle
+telldir I/O get current seekpointer on a directory handle
+tie Objects bind a variable to an object class
+tied Objects get a reference to the object underlying a tied variable
+time Time return number of seconds since 1970
+times Process,Time return elapsed time for self and child processes
+tr/// String transliterate a string
+truncate I/O shorten a file
+uc String return upper-case version of a string
+ucfirst String return a string with just the next letter in upper case
+umask File set file creation mode mask
+undef Misc remove a variable or function definition
+unlink File remove one link to a file
+unpack Binary,LIST convert binary structure into normal perl variables
+unshift ARRAY prepend more elements to the beginning of a list
+untie Objects break a tie binding to a variable
+use Modules,Namespace load a module and import its namespace
+use Objects load in a module at compile time
+utime File set a file's last access and modify times
+values HASH return a list of the values in a hash
+vec Binary test or set particular bits in a string
+wait Process wait for any child process to die
+waitpid Process wait for a particular child process to die
+wantarray Misc,Flow get void vs scalar vs list context of current subroutine call
+warn I/O print debugging info
+write I/O print a picture record
+y/// String transliterate a string
diff --git a/Master/tlpkg/tlperl/lib/Pod/Html.pm b/Master/tlpkg/tlperl/lib/Pod/Html.pm
new file mode 100644
index 00000000000..4b9752bc6fc
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Html.pm
@@ -0,0 +1,2123 @@
+package Pod::Html;
+use strict;
+require Exporter;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+$VERSION = 1.0504;
+@ISA = qw(Exporter);
+@EXPORT = qw(pod2html htmlify);
+@EXPORT_OK = qw(anchorify);
+
+use Carp;
+use Config;
+use Cwd;
+use File::Spec;
+use File::Spec::Unix;
+use Getopt::Long;
+
+use locale; # make \w work right in non-ASCII lands
+
+=head1 NAME
+
+Pod::Html - module to convert pod files to HTML
+
+=head1 SYNOPSIS
+
+ use Pod::Html;
+ pod2html([options]);
+
+=head1 DESCRIPTION
+
+Converts files from pod format (see L<perlpod>) to HTML format. It
+can automatically generate indexes and cross-references, and it keeps
+a cache of things it knows how to cross-reference.
+
+=head1 ARGUMENTS
+
+Pod::Html takes the following arguments:
+
+=over 4
+
+=item backlink
+
+ --backlink="Back to Top"
+
+Adds "Back to Top" links in front of every C<head1> heading (except for
+the first). By default, no backlinks are generated.
+
+=item cachedir
+
+ --cachedir=name
+
+Creates the item and directory caches in the given directory.
+
+=item css
+
+ --css=stylesheet
+
+Specify the URL of a cascading style sheet. Also disables all HTML/CSS
+C<style> attributes that are output by default (to avoid conflicts).
+
+=item flush
+
+ --flush
+
+Flushes the item and directory caches.
+
+=item header
+
+ --header
+ --noheader
+
+Creates header and footer blocks containing the text of the C<NAME>
+section. By default, no headers are generated.
+
+=item help
+
+ --help
+
+Displays the usage message.
+
+=item hiddendirs
+
+ --hiddendirs
+ --nohiddendirs
+
+Include hidden directories in the search for POD's in podpath if recurse
+is set.
+The default is not to traverse any directory whose name begins with C<.>.
+See L</"podpath"> and L</"recurse">.
+
+[This option is for backward compatibility only.
+It's hard to imagine that one would usefully create a module with a
+name component beginning with C<.>.]
+
+=item htmldir
+
+ --htmldir=name
+
+Sets the directory in which the resulting HTML file is placed. This
+is used to generate relative links to other files. Not passing this
+causes all links to be absolute, since this is the value that tells
+Pod::Html the root of the documentation tree.
+
+=item htmlroot
+
+ --htmlroot=name
+
+Sets the base URL for the HTML files. When cross-references are made,
+the HTML root is prepended to the URL.
+
+=item index
+
+ --index
+ --noindex
+
+Generate an index at the top of the HTML file. This is the default
+behaviour.
+
+=item infile
+
+ --infile=name
+
+Specify the pod file to convert. Input is taken from STDIN if no
+infile is specified.
+
+=item libpods
+
+ --libpods=name:...:name
+
+List of page names (eg, "perlfunc") which contain linkable C<=item>s.
+
+=item netscape
+
+ --netscape
+ --nonetscape
+
+B<Deprecated>, has no effect. For backwards compatibility only.
+
+=item outfile
+
+ --outfile=name
+
+Specify the HTML file to create. Output goes to STDOUT if no outfile
+is specified.
+
+=item podpath
+
+ --podpath=name:...:name
+
+Specify which subdirectories of the podroot contain pod files whose
+HTML converted forms can be linked to in cross references.
+
+=item podroot
+
+ --podroot=name
+
+Specify the base directory for finding library pods.
+
+=item quiet
+
+ --quiet
+ --noquiet
+
+Don't display I<mostly harmless> warning messages. These messages
+will be displayed by default. But this is not the same as C<verbose>
+mode.
+
+=item recurse
+
+ --recurse
+ --norecurse
+
+Recurse into subdirectories specified in podpath (default behaviour).
+
+=item title
+
+ --title=title
+
+Specify the title of the resulting HTML file.
+
+=item verbose
+
+ --verbose
+ --noverbose
+
+Display progress messages. By default, they won't be displayed.
+
+=back
+
+=head1 EXAMPLE
+
+ pod2html("pod2html",
+ "--podpath=lib:ext:pod:vms",
+ "--podroot=/usr/src/perl",
+ "--htmlroot=/perl/nmanual",
+ "--libpods=perlfunc:perlguts:perlvar:perlrun:perlop",
+ "--recurse",
+ "--infile=foo.pod",
+ "--outfile=/perl/nmanual/foo.html");
+
+=head1 ENVIRONMENT
+
+Uses C<$Config{pod2html}> to setup default options.
+
+=head1 AUTHOR
+
+Tom Christiansen, E<lt>tchrist@perl.comE<gt>.
+
+=head1 SEE ALSO
+
+L<perlpod>
+
+=head1 COPYRIGHT
+
+This program is distributed under the Artistic License.
+
+=cut
+
+
+my($Cachedir);
+my($Dircache, $Itemcache);
+my @Begin_Stack;
+my @Libpods;
+my($Htmlroot, $Htmldir, $Htmlfile, $Htmlfileurl);
+my($Podfile, @Podpath, $Podroot);
+my $Css;
+
+my $Recurse;
+my $Quiet;
+my $HiddenDirs;
+my $Verbose;
+my $Doindex;
+
+my $Backlink;
+my($Listlevel, @Listtype);
+my $ListNewTerm;
+use vars qw($Ignore); # need to localize it later.
+
+my(%Items_Named, @Items_Seen);
+my($Title, $Header);
+
+my $Top;
+my $Paragraph;
+
+my %Sections;
+
+# Caches
+my %Pages = (); # associative array used to find the location
+ # of pages referenced by L<> links.
+my %Items = (); # associative array used to find the location
+ # of =item directives referenced by C<> links
+
+my %Local_Items;
+my $Is83;
+my $PTQuote;
+
+my $Curdir = File::Spec->curdir;
+
+init_globals();
+
+sub init_globals {
+ $Cachedir = "."; # The directory to which item and directory
+ # caches will be written.
+
+ $Dircache = "pod2htmd.tmp";
+ $Itemcache = "pod2htmi.tmp";
+
+ @Begin_Stack = (); # begin/end stack
+
+ @Libpods = (); # files to search for links from C<> directives
+ $Htmlroot = "/"; # http-server base directory from which all
+ # relative paths in $podpath stem.
+ $Htmldir = ""; # The directory to which the html pages
+ # will (eventually) be written.
+ $Htmlfile = ""; # write to stdout by default
+ $Htmlfileurl = ""; # The url that other files would use to
+ # refer to this file. This is only used
+ # to make relative urls that point to
+ # other files.
+
+ $Podfile = ""; # read from stdin by default
+ @Podpath = (); # list of directories containing library pods.
+ $Podroot = $Curdir; # filesystem base directory from which all
+ # relative paths in $podpath stem.
+ $Css = ''; # Cascading style sheet
+ $Recurse = 1; # recurse on subdirectories in $podpath.
+ $Quiet = 0; # not quiet by default
+ $Verbose = 0; # not verbose by default
+ $Doindex = 1; # non-zero if we should generate an index
+ $Backlink = ''; # text for "back to top" links
+ $Listlevel = 0; # current list depth
+ @Listtype = (); # list types for open lists
+ $ListNewTerm = 0; # indicates new term in definition list; used
+ # to correctly open/close <dd> tags
+ $Ignore = 1; # whether or not to format text. we don't
+ # format text until we hit our first pod
+ # directive.
+
+ @Items_Seen = (); # for multiples of the same item in perlfunc
+ %Items_Named = ();
+ $Header = 0; # produce block header/footer
+ $Title = ''; # title to give the pod(s)
+ $Top = 1; # true if we are at the top of the doc. used
+ # to prevent the first <hr /> directive.
+ $Paragraph = ''; # which paragraph we're processing (used
+ # for error messages)
+ $PTQuote = 0; # status of double-quote conversion
+ %Sections = (); # sections within this page
+
+ %Local_Items = ();
+ $Is83 = $^O eq 'dos'; # Is it an 8.3 filesystem?
+}
+
+#
+# clean_data: global clean-up of pod data
+#
+sub clean_data($){
+ my( $dataref ) = @_;
+ for my $i ( 0..$#{$dataref} ) {
+ ${$dataref}[$i] =~ s/\s+\Z//;
+
+ # have a look for all-space lines
+ if( ${$dataref}[$i] =~ /^\s+$/m and $dataref->[$i] !~ /^\s/ ){
+ my @chunks = split( /^\s+$/m, ${$dataref}[$i] );
+ splice( @$dataref, $i, 1, @chunks );
+ }
+ }
+}
+
+
+sub pod2html {
+ local(@ARGV) = @_;
+ local($/);
+ local $_;
+
+ init_globals();
+
+ $Is83 = 0 if (defined (&Dos::UseLFN) && Dos::UseLFN());
+
+ # cache of %Pages and %Items from last time we ran pod2html
+
+ #undef $opt_help if defined $opt_help;
+
+ # parse the command-line parameters
+ parse_command_line();
+
+ # escape the backlink argument (same goes for title but is done later...)
+ $Backlink = html_escape($Backlink) if defined $Backlink;
+
+ # set some variables to their default values if necessary
+ local *POD;
+ unless (@ARGV && $ARGV[0]) {
+ $Podfile = "-" unless $Podfile; # stdin
+ open(POD, "<$Podfile")
+ || die "$0: cannot open $Podfile file for input: $!\n";
+ } else {
+ $Podfile = $ARGV[0]; # XXX: might be more filenames
+ *POD = *ARGV;
+ }
+ $Htmlfile = "-" unless $Htmlfile; # stdout
+ $Htmlroot = "" if $Htmlroot eq "/"; # so we don't get a //
+ $Htmldir =~ s#/\z## ; # so we don't get a //
+ if ( $Htmlroot eq ''
+ && defined( $Htmldir )
+ && $Htmldir ne ''
+ && substr( $Htmlfile, 0, length( $Htmldir ) ) eq $Htmldir
+ )
+ {
+ # Set the 'base' url for this file, so that we can use it
+ # as the location from which to calculate relative links
+ # to other files. If this is '', then absolute links will
+ # be used throughout.
+ $Htmlfileurl= "$Htmldir/" . substr( $Htmlfile, length( $Htmldir ) + 1);
+ }
+
+ # read the pod a paragraph at a time
+ warn "Scanning for sections in input file(s)\n" if $Verbose;
+ $/ = "";
+ my @poddata = <POD>;
+ close(POD);
+
+ # be eol agnostic
+ for (@poddata) {
+ if (/\r/) {
+ if (/\r\n/) {
+ @poddata = map { s/\r\n/\n/g;
+ /\n\n/ ?
+ map { "$_\n\n" } split /\n\n/ :
+ $_ } @poddata;
+ } else {
+ @poddata = map { s/\r/\n/g;
+ /\n\n/ ?
+ map { "$_\n\n" } split /\n\n/ :
+ $_ } @poddata;
+ }
+ last;
+ }
+ }
+
+ clean_data( \@poddata );
+
+ # scan the pod for =head[1-6] directives and build an index
+ my $index = scan_headings(\%Sections, @poddata);
+
+ unless($index) {
+ warn "No headings in $Podfile\n" if $Verbose;
+ }
+
+ # open the output file
+ open(HTML, ">$Htmlfile")
+ || die "$0: cannot open $Htmlfile file for output: $!\n";
+
+ # put a title in the HTML file if one wasn't specified
+ if ($Title eq '') {
+ TITLE_SEARCH: {
+ for (my $i = 0; $i < @poddata; $i++) {
+ if ($poddata[$i] =~ /^=head1\s*NAME\b/m) {
+ for my $para ( @poddata[$i, $i+1] ) {
+ last TITLE_SEARCH
+ if ($Title) = $para =~ /(\S+\s+-+.*\S)/s;
+ }
+ }
+
+ }
+ }
+ }
+ if (!$Title and $Podfile =~ /\.pod\z/) {
+ # probably a split pod so take first =head[12] as title
+ for (my $i = 0; $i < @poddata; $i++) {
+ last if ($Title) = $poddata[$i] =~ /^=head[12]\s*(.*)/;
+ }
+ warn "adopted '$Title' as title for $Podfile\n"
+ if $Verbose and $Title;
+ }
+ if ($Title) {
+ $Title =~ s/\s*\(.*\)//;
+ } else {
+ warn "$0: no title for $Podfile.\n" unless $Quiet;
+ $Podfile =~ /^(.*)(\.[^.\/]+)?\z/s;
+ $Title = ($Podfile eq "-" ? 'No Title' : $1);
+ warn "using $Title" if $Verbose;
+ }
+ $Title = html_escape($Title);
+
+ my $csslink = '';
+ my $bodystyle = ' style="background-color: white"';
+ my $tdstyle = ' style="background-color: #cccccc"';
+
+ if ($Css) {
+ $csslink = qq(\n<link rel="stylesheet" href="$Css" type="text/css" />);
+ $csslink =~ s,\\,/,g;
+ $csslink =~ s,(/.):,$1|,;
+ $bodystyle = '';
+ $tdstyle = '';
+ }
+
+ my $block = $Header ? <<END_OF_BLOCK : '';
+<table border="0" width="100%" cellspacing="0" cellpadding="3">
+<tr><td class="block"$tdstyle valign="middle">
+<big><strong><span class="block">&nbsp;$Title</span></strong></big>
+</td></tr>
+</table>
+END_OF_BLOCK
+
+ print HTML <<END_OF_HEAD;
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>$Title</title>$csslink
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+<link rev="made" href="mailto:$Config{perladmin}" />
+</head>
+
+<body$bodystyle>
+$block
+END_OF_HEAD
+
+ # load/reload/validate/cache %Pages and %Items
+ get_cache($Dircache, $Itemcache, \@Podpath, $Podroot, $Recurse);
+
+ # scan the pod for =item directives
+ scan_items( \%Local_Items, "", @poddata);
+
+ # put an index at the top of the file. note, if $Doindex is 0 we
+ # still generate an index, but surround it with an html comment.
+ # that way some other program can extract it if desired.
+ $index =~ s/--+/-/g;
+ print HTML "<p><a name=\"__index__\"></a></p>\n";
+ print HTML "<!-- INDEX BEGIN -->\n";
+ print HTML "<!--\n" unless $Doindex;
+ print HTML $index;
+ print HTML "-->\n" unless $Doindex;
+ print HTML "<!-- INDEX END -->\n\n";
+ print HTML "<hr />\n" if $Doindex and $index;
+
+ # now convert this file
+ my $after_item; # set to true after an =item
+ warn "Converting input file $Podfile\n" if $Verbose;
+ foreach my $i (0..$#poddata){
+ $PTQuote = 0; # status of quote conversion
+
+ $_ = $poddata[$i];
+ $Paragraph = $i+1;
+ if (/^(=.*)/s) { # is it a pod directive?
+ $Ignore = 0;
+ $after_item = 0;
+ $_ = $1;
+ if (/^=begin\s+(\S+)\s*(.*)/si) {# =begin
+ process_begin($1, $2);
+ } elsif (/^=end\s+(\S+)\s*(.*)/si) {# =end
+ process_end($1, $2);
+ } elsif (/^=cut/) { # =cut
+ process_cut();
+ } elsif (/^=pod/) { # =pod
+ process_pod();
+ } else {
+ next if @Begin_Stack && $Begin_Stack[-1] ne 'html';
+
+ if (/^=(head[1-6])\s+(.*\S)/s) { # =head[1-6] heading
+ process_head( $1, $2, $Doindex && $index );
+ } elsif (/^=item\s*(.*\S)?/sm) { # =item text
+ process_item( $1 );
+ $after_item = 1;
+ } elsif (/^=over\s*(.*)/) { # =over N
+ process_over();
+ } elsif (/^=back/) { # =back
+ process_back();
+ } elsif (/^=for\s+(\S+)\s*(.*)/si) {# =for
+ process_for($1,$2);
+ } else {
+ /^=(\S*)\s*/;
+ warn "$0: $Podfile: unknown pod directive '$1' in "
+ . "paragraph $Paragraph. ignoring.\n" unless $Quiet;
+ }
+ }
+ $Top = 0;
+ }
+ else {
+ next if $Ignore;
+ next if @Begin_Stack && $Begin_Stack[-1] ne 'html';
+ print HTML and next if @Begin_Stack && $Begin_Stack[-1] eq 'html';
+ my $text = $_;
+
+ # Open tag for definition list as we have something to put in it
+ if( $ListNewTerm ){
+ print HTML "<dd>\n";
+ $ListNewTerm = 0;
+ }
+
+ if( $text =~ /\A\s+/ ){
+ process_pre( \$text );
+ print HTML "<pre>\n$text</pre>\n";
+
+ } else {
+ process_text( \$text );
+
+ # experimental: check for a paragraph where all lines
+ # have some ...\t...\t...\n pattern
+ if( $text =~ /\t/ ){
+ my @lines = split( "\n", $text );
+ if( @lines > 1 ){
+ my $all = 2;
+ foreach my $line ( @lines ){
+ if( $line =~ /\S/ && $line !~ /\t/ ){
+ $all--;
+ last if $all == 0;
+ }
+ }
+ if( $all > 0 ){
+ $text =~ s/\t+/<td>/g;
+ $text =~ s/^/<tr><td>/gm;
+ $text = '<table cellspacing="0" cellpadding="0">' .
+ $text . '</table>';
+ }
+ }
+ }
+ ## end of experimental
+
+ print HTML "<p>$text</p>\n";
+ }
+ $after_item = 0;
+ }
+ }
+
+ # finish off any pending directives
+ finish_list();
+
+ # link to page index
+ print HTML "<p><a href=\"#__index__\"><small>$Backlink</small></a></p>\n"
+ if $Doindex and $index and $Backlink;
+
+ print HTML <<END_OF_TAIL;
+$block
+</body>
+
+</html>
+END_OF_TAIL
+
+ # close the html file
+ close(HTML);
+
+ warn "Finished\n" if $Verbose;
+}
+
+##############################################################################
+
+sub usage {
+ my $podfile = shift;
+ warn "$0: $podfile: @_\n" if @_;
+ die <<END_OF_USAGE;
+Usage: $0 --help --htmlroot=<name> --infile=<name> --outfile=<name>
+ --podpath=<name>:...:<name> --podroot=<name>
+ --libpods=<name>:...:<name> --recurse --verbose --index
+ --netscape --norecurse --noindex --cachedir=<name>
+
+ --backlink - set text for "back to top" links (default: none).
+ --cachedir - directory for the item and directory cache files.
+ --css - stylesheet URL
+ --flush - flushes the item and directory caches.
+ --[no]header - produce block header/footer (default is no headers).
+ --help - prints this message.
+ --hiddendirs - search hidden directories in podpath
+ --htmldir - directory for resulting HTML files.
+ --htmlroot - http-server base directory from which all relative paths
+ in podpath stem (default is /).
+ --[no]index - generate an index at the top of the resulting html
+ (default behaviour).
+ --infile - filename for the pod to convert (input taken from stdin
+ by default).
+ --libpods - colon-separated list of pages to search for =item pod
+ directives in as targets of C<> and implicit links (empty
+ by default). note, these are not filenames, but rather
+ page names like those that appear in L<> links.
+ --outfile - filename for the resulting html file (output sent to
+ stdout by default).
+ --podpath - colon-separated list of directories containing library
+ pods (empty by default).
+ --podroot - filesystem base directory from which all relative paths
+ in podpath stem (default is .).
+ --[no]quiet - suppress some benign warning messages (default is off).
+ --[no]recurse - recurse on those subdirectories listed in podpath
+ (default behaviour).
+ --title - title that will appear in resulting html file.
+ --[no]verbose - self-explanatory (off by default).
+ --[no]netscape - deprecated, has no effect. for backwards compatibility only.
+
+END_OF_USAGE
+
+}
+
+sub parse_command_line {
+ my ($opt_backlink,$opt_cachedir,$opt_css,$opt_flush,$opt_header,$opt_help,
+ $opt_htmldir,$opt_htmlroot,$opt_index,$opt_infile,$opt_libpods,
+ $opt_netscape,$opt_outfile,$opt_podpath,$opt_podroot,$opt_quiet,
+ $opt_recurse,$opt_title,$opt_verbose,$opt_hiddendirs);
+
+ unshift @ARGV, split ' ', $Config{pod2html} if $Config{pod2html};
+ my $result = GetOptions(
+ 'backlink=s' => \$opt_backlink,
+ 'cachedir=s' => \$opt_cachedir,
+ 'css=s' => \$opt_css,
+ 'flush' => \$opt_flush,
+ 'header!' => \$opt_header,
+ 'help' => \$opt_help,
+ 'hiddendirs!'=> \$opt_hiddendirs,
+ 'htmldir=s' => \$opt_htmldir,
+ 'htmlroot=s' => \$opt_htmlroot,
+ 'index!' => \$opt_index,
+ 'infile=s' => \$opt_infile,
+ 'libpods=s' => \$opt_libpods,
+ 'netscape!' => \$opt_netscape,
+ 'outfile=s' => \$opt_outfile,
+ 'podpath=s' => \$opt_podpath,
+ 'podroot=s' => \$opt_podroot,
+ 'quiet!' => \$opt_quiet,
+ 'recurse!' => \$opt_recurse,
+ 'title=s' => \$opt_title,
+ 'verbose!' => \$opt_verbose,
+ );
+ usage("-", "invalid parameters") if not $result;
+
+ usage("-") if defined $opt_help; # see if the user asked for help
+ $opt_help = ""; # just to make -w shut-up.
+
+ @Podpath = split(":", $opt_podpath) if defined $opt_podpath;
+ @Libpods = split(":", $opt_libpods) if defined $opt_libpods;
+
+ $Backlink = $opt_backlink if defined $opt_backlink;
+ $Cachedir = $opt_cachedir if defined $opt_cachedir;
+ $Css = $opt_css if defined $opt_css;
+ $Header = $opt_header if defined $opt_header;
+ $Htmldir = $opt_htmldir if defined $opt_htmldir;
+ $Htmlroot = $opt_htmlroot if defined $opt_htmlroot;
+ $Doindex = $opt_index if defined $opt_index;
+ $Podfile = $opt_infile if defined $opt_infile;
+ $HiddenDirs = $opt_hiddendirs if defined $opt_hiddendirs;
+ $Htmlfile = $opt_outfile if defined $opt_outfile;
+ $Podroot = $opt_podroot if defined $opt_podroot;
+ $Quiet = $opt_quiet if defined $opt_quiet;
+ $Recurse = $opt_recurse if defined $opt_recurse;
+ $Title = $opt_title if defined $opt_title;
+ $Verbose = $opt_verbose if defined $opt_verbose;
+
+ warn "Flushing item and directory caches\n"
+ if $opt_verbose && defined $opt_flush;
+ $Dircache = "$Cachedir/pod2htmd.tmp";
+ $Itemcache = "$Cachedir/pod2htmi.tmp";
+ if (defined $opt_flush) {
+ 1 while unlink($Dircache, $Itemcache);
+ }
+}
+
+
+my $Saved_Cache_Key;
+
+sub get_cache {
+ my($dircache, $itemcache, $podpath, $podroot, $recurse) = @_;
+ my @cache_key_args = @_;
+
+ # A first-level cache:
+ # Don't bother reading the cache files if they still apply
+ # and haven't changed since we last read them.
+
+ my $this_cache_key = cache_key(@cache_key_args);
+
+ return if $Saved_Cache_Key and $this_cache_key eq $Saved_Cache_Key;
+
+ # load the cache of %Pages and %Items if possible. $tests will be
+ # non-zero if successful.
+ my $tests = 0;
+ if (-f $dircache && -f $itemcache) {
+ warn "scanning for item cache\n" if $Verbose;
+ $tests = load_cache($dircache, $itemcache, $podpath, $podroot);
+ }
+
+ # if we didn't succeed in loading the cache then we must (re)build
+ # %Pages and %Items.
+ if (!$tests) {
+ warn "scanning directories in pod-path\n" if $Verbose;
+ scan_podpath($podroot, $recurse, 0);
+ }
+ $Saved_Cache_Key = cache_key(@cache_key_args);
+}
+
+sub cache_key {
+ my($dircache, $itemcache, $podpath, $podroot, $recurse) = @_;
+ return join('!', $dircache, $itemcache, $recurse,
+ @$podpath, $podroot, stat($dircache), stat($itemcache));
+}
+
+#
+# load_cache - tries to find if the caches stored in $dircache and $itemcache
+# are valid caches of %Pages and %Items. if they are valid then it loads
+# them and returns a non-zero value.
+#
+sub load_cache {
+ my($dircache, $itemcache, $podpath, $podroot) = @_;
+ my($tests);
+ local $_;
+
+ $tests = 0;
+
+ open(CACHE, "<$itemcache") ||
+ die "$0: error opening $itemcache for reading: $!\n";
+ $/ = "\n";
+
+ # is it the same podpath?
+ $_ = <CACHE>;
+ chomp($_);
+ $tests++ if (join(":", @$podpath) eq $_);
+
+ # is it the same podroot?
+ $_ = <CACHE>;
+ chomp($_);
+ $tests++ if ($podroot eq $_);
+
+ # load the cache if its good
+ if ($tests != 2) {
+ close(CACHE);
+ return 0;
+ }
+
+ warn "loading item cache\n" if $Verbose;
+ while (<CACHE>) {
+ /(.*?) (.*)$/;
+ $Items{$1} = $2;
+ }
+ close(CACHE);
+
+ warn "scanning for directory cache\n" if $Verbose;
+ open(CACHE, "<$dircache") ||
+ die "$0: error opening $dircache for reading: $!\n";
+ $/ = "\n";
+ $tests = 0;
+
+ # is it the same podpath?
+ $_ = <CACHE>;
+ chomp($_);
+ $tests++ if (join(":", @$podpath) eq $_);
+
+ # is it the same podroot?
+ $_ = <CACHE>;
+ chomp($_);
+ $tests++ if ($podroot eq $_);
+
+ # load the cache if its good
+ if ($tests != 2) {
+ close(CACHE);
+ return 0;
+ }
+
+ warn "loading directory cache\n" if $Verbose;
+ while (<CACHE>) {
+ /(.*?) (.*)$/;
+ $Pages{$1} = $2;
+ }
+
+ close(CACHE);
+
+ return 1;
+}
+
+#
+# scan_podpath - scans the directories specified in @podpath for directories,
+# .pod files, and .pm files. it also scans the pod files specified in
+# @Libpods for =item directives.
+#
+sub scan_podpath {
+ my($podroot, $recurse, $append) = @_;
+ my($pwd, $dir);
+ my($libpod, $dirname, $pod, @files, @poddata);
+
+ unless($append) {
+ %Items = ();
+ %Pages = ();
+ }
+
+ # scan each directory listed in @Podpath
+ $pwd = getcwd();
+ chdir($podroot)
+ || die "$0: error changing to directory $podroot: $!\n";
+ foreach $dir (@Podpath) {
+ scan_dir($dir, $recurse);
+ }
+
+ # scan the pods listed in @Libpods for =item directives
+ foreach $libpod (@Libpods) {
+ # if the page isn't defined then we won't know where to find it
+ # on the system.
+ next unless defined $Pages{$libpod} && $Pages{$libpod};
+
+ # if there is a directory then use the .pod and .pm files within it.
+ # NOTE: Only finds the first so-named directory in the tree.
+# if ($Pages{$libpod} =~ /([^:]*[^(\.pod|\.pm)]):/) {
+ if ($Pages{$libpod} =~ /([^:]*(?<!\.pod)(?<!\.pm)):/) {
+ # find all the .pod and .pm files within the directory
+ $dirname = $1;
+ opendir(DIR, $dirname) ||
+ die "$0: error opening directory $dirname: $!\n";
+ @files = grep(/(\.pod|\.pm)\z/ && ! -d $_, readdir(DIR));
+ closedir(DIR);
+
+ # scan each .pod and .pm file for =item directives
+ foreach $pod (@files) {
+ open(POD, "<$dirname/$pod") ||
+ die "$0: error opening $dirname/$pod for input: $!\n";
+ @poddata = <POD>;
+ close(POD);
+ clean_data( \@poddata );
+
+ scan_items( \%Items, "$dirname/$pod", @poddata);
+ }
+
+ # use the names of files as =item directives too.
+### Don't think this should be done this way - confuses issues.(WL)
+### foreach $pod (@files) {
+### $pod =~ /^(.*)(\.pod|\.pm)$/;
+### $Items{$1} = "$dirname/$1.html" if $1;
+### }
+ } elsif ($Pages{$libpod} =~ /([^:]*\.pod):/ ||
+ $Pages{$libpod} =~ /([^:]*\.pm):/) {
+ # scan the .pod or .pm file for =item directives
+ $pod = $1;
+ open(POD, "<$pod") ||
+ die "$0: error opening $pod for input: $!\n";
+ @poddata = <POD>;
+ close(POD);
+ clean_data( \@poddata );
+
+ scan_items( \%Items, "$pod", @poddata);
+ } else {
+ warn "$0: shouldn't be here (line ".__LINE__."\n" unless $Quiet;
+ }
+ }
+ @poddata = (); # clean-up a bit
+
+ chdir($pwd)
+ || die "$0: error changing to directory $pwd: $!\n";
+
+ # cache the item list for later use
+ warn "caching items for later use\n" if $Verbose;
+ open(CACHE, ">$Itemcache") ||
+ die "$0: error open $Itemcache for writing: $!\n";
+
+ print CACHE join(":", @Podpath) . "\n$podroot\n";
+ foreach my $key (keys %Items) {
+ print CACHE "$key $Items{$key}\n";
+ }
+
+ close(CACHE);
+
+ # cache the directory list for later use
+ warn "caching directories for later use\n" if $Verbose;
+ open(CACHE, ">$Dircache") ||
+ die "$0: error open $Dircache for writing: $!\n";
+
+ print CACHE join(":", @Podpath) . "\n$podroot\n";
+ foreach my $key (keys %Pages) {
+ print CACHE "$key $Pages{$key}\n";
+ }
+
+ close(CACHE);
+}
+
+#
+# scan_dir - scans the directory specified in $dir for subdirectories, .pod
+# files, and .pm files. notes those that it finds. this information will
+# be used later in order to figure out where the pages specified in L<>
+# links are on the filesystem.
+#
+sub scan_dir {
+ my($dir, $recurse) = @_;
+ my($t, @subdirs, @pods, $pod, $dirname, @dirs);
+ local $_;
+
+ @subdirs = ();
+ @pods = ();
+
+ opendir(DIR, $dir) ||
+ die "$0: error opening directory $dir: $!\n";
+ while (defined($_ = readdir(DIR))) {
+ if (-d "$dir/$_" && $_ ne "." && $_ ne ".."
+ && ($HiddenDirs || !/^\./)
+ ) { # directory
+ $Pages{$_} = "" unless defined $Pages{$_};
+ $Pages{$_} .= "$dir/$_:";
+ push(@subdirs, $_);
+ } elsif (/\.pod\z/) { # .pod
+ s/\.pod\z//;
+ $Pages{$_} = "" unless defined $Pages{$_};
+ $Pages{$_} .= "$dir/$_.pod:";
+ push(@pods, "$dir/$_.pod");
+ } elsif (/\.html\z/) { # .html
+ s/\.html\z//;
+ $Pages{$_} = "" unless defined $Pages{$_};
+ $Pages{$_} .= "$dir/$_.pod:";
+ } elsif (/\.pm\z/) { # .pm
+ s/\.pm\z//;
+ $Pages{$_} = "" unless defined $Pages{$_};
+ $Pages{$_} .= "$dir/$_.pm:";
+ push(@pods, "$dir/$_.pm");
+ } elsif (-T "$dir/$_") { # script(?)
+ local *F;
+ if (open(F, "$dir/$_")) {
+ my $line;
+ while (defined($line = <F>)) {
+ if ($line =~ /^=(?:pod|head1)/) {
+ $Pages{$_} = "" unless defined $Pages{$_};
+ $Pages{$_} .= "$dir/$_.pod:";
+ last;
+ }
+ }
+ close(F);
+ }
+ }
+ }
+ closedir(DIR);
+
+ # recurse on the subdirectories if necessary
+ if ($recurse) {
+ foreach my $subdir (@subdirs) {
+ scan_dir("$dir/$subdir", $recurse);
+ }
+ }
+}
+
+#
+# scan_headings - scan a pod file for head[1-6] tags, note the tags, and
+# build an index.
+#
+sub scan_headings {
+ my($sections, @data) = @_;
+ my($tag, $which_head, $otitle, $listdepth, $index);
+
+ local $Ignore = 0;
+
+ $listdepth = 0;
+ $index = "";
+
+ # scan for =head directives, note their name, and build an index
+ # pointing to each of them.
+ foreach my $line (@data) {
+ if ($line =~ /^=(head)([1-6])\s+(.*)/) {
+ ($tag, $which_head, $otitle) = ($1,$2,$3);
+
+ my $title = depod( $otitle );
+ my $name = anchorify( $title );
+ $$sections{$name} = 1;
+ $title = process_text( \$otitle );
+
+ while ($which_head != $listdepth) {
+ if ($which_head > $listdepth) {
+ $index .= "\n" . ("\t" x $listdepth) . "<ul>\n";
+ $listdepth++;
+ } elsif ($which_head < $listdepth) {
+ $listdepth--;
+ $index .= "\n" . ("\t" x $listdepth) . "</ul>\n";
+ }
+ }
+
+ $index .= "\n" . ("\t" x $listdepth) . "<li>" .
+ "<a href=\"#" . $name . "\">" .
+ $title . "</a></li>";
+ }
+ }
+
+ # finish off the lists
+ while ($listdepth--) {
+ $index .= "\n" . ("\t" x $listdepth) . "</ul>\n";
+ }
+
+ # get rid of bogus lists
+ $index =~ s,\t*<ul>\s*</ul>\n,,g;
+
+ return $index;
+}
+
+#
+# scan_items - scans the pod specified by $pod for =item directives. we
+# will use this information later on in resolving C<> links.
+#
+sub scan_items {
+ my( $itemref, $pod, @poddata ) = @_;
+ my($i, $item);
+ local $_;
+
+ $pod =~ s/\.pod\z//;
+ $pod .= ".html" if $pod;
+
+ foreach $i (0..$#poddata) {
+ my $txt = depod( $poddata[$i] );
+
+ # figure out what kind of item it is.
+ # Build string for referencing this item.
+ if ( $txt =~ /\A=item\s+\*\s*(.*)\Z/s ) { # bulleted list
+ next unless $1;
+ $item = $1;
+ } elsif( $txt =~ /\A=item\s+(?>\d+\.?)\s*(.*)\Z/s ) { # numbered list
+ $item = $1;
+ } elsif( $txt =~ /\A=item\s+(.*)\Z/s ) { # definition list
+ $item = $1;
+ } else {
+ next;
+ }
+ my $fid = fragment_id( $item );
+ $$itemref{$fid} = "$pod" if $fid;
+ }
+}
+
+#
+# process_head - convert a pod head[1-6] tag and convert it to HTML format.
+#
+sub process_head {
+ my($tag, $heading, $hasindex) = @_;
+
+ # figure out the level of the =head
+ $tag =~ /head([1-6])/;
+ my $level = $1;
+
+ finish_list();
+
+ print HTML "<p>\n";
+ if( $level == 1 && ! $Top ){
+ print HTML "<a href=\"#__index__\"><small>$Backlink</small></a>\n"
+ if $hasindex and $Backlink;
+ print HTML "</p>\n<hr />\n"
+ } else {
+ print HTML "</p>\n";
+ }
+
+ my $name = anchorify( depod( $heading ) );
+ my $convert = process_text( \$heading );
+ print HTML "<h$level><a name=\"$name\">$convert</a></h$level>\n";
+}
+
+
+#
+# emit_item_tag - print an =item's text
+# Note: The global $EmittedItem is used for inhibiting self-references.
+#
+my $EmittedItem;
+
+sub emit_item_tag($$$){
+ my( $otext, $text, $compact ) = @_;
+ my $item = fragment_id( $text );
+
+ $EmittedItem = $item;
+ ### print STDERR "emit_item_tag=$item ($text)\n";
+
+ print HTML '<strong>';
+ if ($Items_Named{$item}++) {
+ print HTML process_text( \$otext );
+ } else {
+ my $name = 'item_' . $item;
+ $name = anchorify($name);
+ print HTML qq{<a name="$name">}, process_text( \$otext ), '</a>';
+ }
+ print HTML "</strong>";
+ undef( $EmittedItem );
+}
+
+sub new_listitem {
+ my( $tag ) = @_;
+ # Open tag for definition list as we have something to put in it
+ if( ($tag ne 'dl') && ($ListNewTerm) ){
+ print HTML "<dd>\n";
+ $ListNewTerm = 0;
+ }
+
+ if( $Items_Seen[$Listlevel]++ == 0 ){
+ # start of new list
+ push( @Listtype, "$tag" );
+ print HTML "<$tag>\n";
+ } else {
+ # if this is not the first item, close the previous one
+ if ( $tag eq 'dl' ){
+ print HTML "</dd>\n" unless $ListNewTerm;
+ } else {
+ print HTML "</li>\n";
+ }
+ }
+ my $opentag = $tag eq 'dl' ? 'dt' : 'li';
+ print HTML "<$opentag>";
+}
+
+#
+# process_item - convert a pod item tag and convert it to HTML format.
+#
+sub process_item {
+ my( $otext ) = @_;
+
+ # lots of documents start a list without doing an =over. this is
+ # bad! but, the proper thing to do seems to be to just assume
+ # they did do an =over. so warn them once and then continue.
+ if( $Listlevel == 0 ){
+ warn "$0: $Podfile: unexpected =item directive in paragraph $Paragraph. ignoring.\n" unless $Quiet;
+ process_over();
+ }
+
+ # remove formatting instructions from the text
+ my $text = depod( $otext );
+
+ # all the list variants:
+ if( $text =~ /\A\*/ ){ # bullet
+ new_listitem( 'ul' );
+ if ($text =~ /\A\*\s+(.+)\Z/s ) { # with additional text
+ my $tag = $1;
+ $otext =~ s/\A\*\s+//;
+ emit_item_tag( $otext, $tag, 1 );
+ print HTML "\n";
+ }
+
+ } elsif( $text =~ /\A\d+/ ){ # numbered list
+ new_listitem( 'ol' );
+ if ($text =~ /\A(?>\d+\.?)\s*(.+)\Z/s ) { # with additional text
+ my $tag = $1;
+ $otext =~ s/\A\d+\.?\s*//;
+ emit_item_tag( $otext, $tag, 1 );
+ print HTML "\n";
+ }
+
+ } else { # definition list
+ # new_listitem takes care of opening the <dt> tag
+ new_listitem( 'dl' );
+ if( $text =~ /\A(.+)\Z/s ){ # should have text
+ emit_item_tag( $otext, $text, 1 );
+ } else {
+ warn "$0: $Podfile: no term text provided for definition list in paragraph $Paragraph. ignoring.\n" unless $Quiet;
+ }
+ # write the definition term and close <dt> tag
+ print HTML "</dt>\n";
+ # trigger opening a <dd> tag for the actual definition; will not
+ # happen if next paragraph is also a definition term (=item)
+ $ListNewTerm = 1;
+ }
+ print HTML "\n";
+}
+
+#
+# process_over - process a pod over tag and start a corresponding HTML list.
+#
+sub process_over {
+ # start a new list
+ $Listlevel++;
+ push( @Items_Seen, 0 );
+}
+
+#
+# process_back - process a pod back tag and convert it to HTML format.
+#
+sub process_back {
+ if( $Listlevel == 0 ){
+ warn "$0: $Podfile: unexpected =back directive in paragraph $Paragraph. ignoring.\n" unless $Quiet;
+ return;
+ }
+
+ # close off the list. note, I check to see if $Listtype[$Listlevel] is
+ # defined because an =item directive may have never appeared and thus
+ # $Listtype[$Listlevel] may have never been initialized.
+ $Listlevel--;
+ if( defined $Listtype[$Listlevel] ){
+ if ( $Listtype[$Listlevel] eq 'dl' ){
+ print HTML "</dd>\n" unless $ListNewTerm;
+ } else {
+ print HTML "</li>\n";
+ }
+ print HTML "</$Listtype[$Listlevel]>\n";
+ pop( @Listtype );
+ $ListNewTerm = 0;
+ }
+
+ # clean up item count
+ pop( @Items_Seen );
+}
+
+#
+# process_cut - process a pod cut tag, thus start ignoring pod directives.
+#
+sub process_cut {
+ $Ignore = 1;
+}
+
+#
+# process_pod - process a pod tag, thus stop ignoring pod directives
+# until we see a corresponding cut.
+#
+sub process_pod {
+ # no need to set $Ignore to 0 cause the main loop did it
+}
+
+#
+# process_for - process a =for pod tag. if it's for html, spit
+# it out verbatim, if illustration, center it, otherwise ignore it.
+#
+sub process_for {
+ my($whom, $text) = @_;
+ if ( $whom =~ /^(pod2)?html$/i) {
+ print HTML $text;
+ } elsif ($whom =~ /^illustration$/i) {
+ 1 while chomp $text;
+ for my $ext (qw[.png .gif .jpeg .jpg .tga .pcl .bmp]) {
+ $text .= $ext, last if -r "$text$ext";
+ }
+ print HTML qq{<p align="center"><img src="$text" alt="$text illustration" /></p>};
+ }
+}
+
+#
+# process_begin - process a =begin pod tag. this pushes
+# whom we're beginning on the begin stack. if there's a
+# begin stack, we only print if it us.
+#
+sub process_begin {
+ my($whom, $text) = @_;
+ $whom = lc($whom);
+ push (@Begin_Stack, $whom);
+ if ( $whom =~ /^(pod2)?html$/) {
+ print HTML $text if $text;
+ }
+}
+
+#
+# process_end - process a =end pod tag. pop the
+# begin stack. die if we're mismatched.
+#
+sub process_end {
+ my($whom, $text) = @_;
+ $whom = lc($whom);
+ if ($Begin_Stack[-1] ne $whom ) {
+ die "Unmatched begin/end at chunk $Paragraph\n"
+ }
+ pop( @Begin_Stack );
+}
+
+#
+# process_pre - indented paragraph, made into <pre></pre>
+#
+sub process_pre {
+ my( $text ) = @_;
+ my( $rest );
+ return if $Ignore;
+
+ $rest = $$text;
+
+ # insert spaces in place of tabs
+ $rest =~ s#(.+)#
+ my $line = $1;
+ 1 while $line =~ s/(\t+)/' ' x ((length($1) * 8) - $-[0] % 8)/e;
+ $line;
+ #eg;
+
+ # convert some special chars to HTML escapes
+ $rest = html_escape($rest);
+
+ # try and create links for all occurrences of perl.* within
+ # the preformatted text.
+ $rest =~ s{
+ (\s*)(perl\w+)
+ }{
+ if ( defined $Pages{$2} ){ # is a link
+ qq($1<a href="$Htmlroot/$Pages{$2}">$2</a>);
+ } elsif (defined $Pages{dosify($2)}) { # is a link
+ qq($1<a href="$Htmlroot/$Pages{dosify($2)}">$2</a>);
+ } else {
+ "$1$2";
+ }
+ }xeg;
+ $rest =~ s{
+ (<a\ href="?) ([^>:]*:)? ([^>:]*) \.pod: ([^>:]*:)?
+ }{
+ my $url ;
+ if ( $Htmlfileurl ne '' ){
+ # Here, we take advantage of the knowledge
+ # that $Htmlfileurl ne '' implies $Htmlroot eq ''.
+ # Since $Htmlroot eq '', we need to prepend $Htmldir
+ # on the fron of the link to get the absolute path
+ # of the link's target. We check for a leading '/'
+ # to avoid corrupting links that are #, file:, etc.
+ my $old_url = $3 ;
+ $old_url = "$Htmldir$old_url" if $old_url =~ m{^\/};
+ $url = relativize_url( "$old_url.html", $Htmlfileurl );
+ } else {
+ $url = "$3.html" ;
+ }
+ "$1$url" ;
+ }xeg;
+
+ # Look for embedded URLs and make them into links. We don't
+ # relativize them since they are best left as the author intended.
+
+ my $urls = '(' . join ('|', qw{
+ http
+ telnet
+ mailto
+ news
+ gopher
+ file
+ wais
+ ftp
+ } )
+ . ')';
+
+ my $ltrs = '\w';
+ my $gunk = '/#~:.?+=&%@!\-';
+ my $punc = '.:!?\-;';
+ my $any = "${ltrs}${gunk}${punc}";
+
+ $rest =~ s{
+ \b # start at word boundary
+ ( # begin $1 {
+ $urls : # need resource and a colon
+ (?!:) # Ignore File::, among others.
+ [$any] +? # followed by one or more of any valid
+ # character, but be conservative and
+ # take only what you need to....
+ ) # end $1 }
+ (?=
+ &quot; &gt; # maybe pre-quoted '<a href="...">'
+ | # or:
+ [$punc]* # 0 or more punctuation
+ (?: # followed
+ [^$any] # by a non-url char
+ | # or
+ $ # end of the string
+ ) #
+ | # or else
+ $ # then end of the string
+ )
+ }{<a href="$1">$1</a>}igox;
+
+ # text should be as it is (verbatim)
+ $$text = $rest;
+}
+
+
+#
+# pure text processing
+#
+# pure_text/inIS_text: differ with respect to automatic C<> recognition.
+# we don't want this to happen within IS
+#
+sub pure_text($){
+ my $text = shift();
+ process_puretext( $text, \$PTQuote, 1 );
+}
+
+sub inIS_text($){
+ my $text = shift();
+ process_puretext( $text, \$PTQuote, 0 );
+}
+
+#
+# process_puretext - process pure text (without pod-escapes) converting
+# double-quotes and handling implicit C<> links.
+#
+sub process_puretext {
+ my($text, $quote, $notinIS) = @_;
+
+ ## Guessing at func() or [\$\@%&]*var references in plain text is destined
+ ## to produce some strange looking ref's. uncomment to disable:
+ ## $notinIS = 0;
+
+ my(@words, $lead, $trail);
+
+ # convert double-quotes to single-quotes
+ if( $$quote && $text =~ s/"/''/s ){
+ $$quote = 0;
+ }
+ while ($text =~ s/"([^"]*)"/``$1''/sg) {};
+ $$quote = 1 if $text =~ s/"/``/s;
+
+ # keep track of leading and trailing white-space
+ $lead = ($text =~ s/\A(\s+)//s ? $1 : "");
+ $trail = ($text =~ s/(\s+)\Z//s ? $1 : "");
+
+ # split at space/non-space boundaries
+ @words = split( /(?<=\s)(?=\S)|(?<=\S)(?=\s)/, $text );
+
+ # process each word individually
+ foreach my $word (@words) {
+ # skip space runs
+ next if $word =~ /^\s*$/;
+ # see if we can infer a link
+ if( $notinIS && $word =~ /^(\w+)\((.*)\)$/ ) {
+ # has parenthesis so should have been a C<> ref
+ ## try for a pagename (perlXXX(1))?
+ my( $func, $args ) = ( $1, $2 );
+ if( $args =~ /^\d+$/ ){
+ my $url = page_sect( $word, '' );
+ if( defined $url ){
+ $word = "<a href=\"$url\">the $word manpage</a>";
+ next;
+ }
+ }
+ ## try function name for a link, append tt'ed argument list
+ $word = emit_C( $func, '', "($args)");
+
+#### disabled. either all (including $\W, $\w+{.*} etc.) or nothing.
+## } elsif( $notinIS && $word =~ /^[\$\@%&*]+\w+$/) {
+## # perl variables, should be a C<> ref
+## $word = emit_C( $word );
+
+ } elsif ($word =~ m,^\w+://\w,) {
+ # looks like a URL
+ # Don't relativize it: leave it as the author intended
+ $word = qq(<a href="$word">$word</a>);
+ } elsif ($word =~ /[\w.-]+\@[\w-]+\.\w/) {
+ # looks like an e-mail address
+ my ($w1, $w2, $w3) = ("", $word, "");
+ ($w1, $w2, $w3) = ("(", $1, ")$2") if $word =~ /^\((.*?)\)(,?)/;
+ ($w1, $w2, $w3) = ("&lt;", $1, "&gt;$2") if $word =~ /^<(.*?)>(,?)/;
+ $word = qq($w1<a href="mailto:$w2">$w2</a>$w3);
+ } else {
+ $word = html_escape($word) if $word =~ /["&<>]/;
+ }
+ }
+
+ # put everything back together
+ return $lead . join( '', @words ) . $trail;
+}
+
+
+#
+# process_text - handles plaintext that appears in the input pod file.
+# there may be pod commands embedded within the text so those must be
+# converted to html commands.
+#
+
+sub process_text1($$;$$);
+sub pattern ($) { $_[0] ? '[^\S\n]+'.('>' x ($_[0] + 1)) : '>' }
+sub closing ($) { local($_) = shift; (defined && s/\s+$//) ? length : 0 }
+
+sub process_text {
+ return if $Ignore;
+ my( $tref ) = @_;
+ my $res = process_text1( 0, $tref );
+ $$tref = $res;
+}
+
+sub process_text1($$;$$){
+ my( $lev, $rstr, $func, $closing ) = @_;
+ my $res = '';
+
+ unless (defined $func) {
+ $func = '';
+ $lev++;
+ }
+
+ if( $func eq 'B' ){
+ # B<text> - boldface
+ $res = '<strong>' . process_text1( $lev, $rstr ) . '</strong>';
+
+ } elsif( $func eq 'C' ){
+ # C<code> - can be a ref or <code></code>
+ # need to extract text
+ my $par = go_ahead( $rstr, 'C', $closing );
+
+ ## clean-up of the link target
+ my $text = depod( $par );
+
+ ### my $x = $par =~ /[BI]</ ? 'yes' : 'no' ;
+ ### print STDERR "-->call emit_C($par) lev=$lev, par with BI=$x\n";
+
+ $res = emit_C( $text, $lev > 1 || ($par =~ /[BI]</) );
+
+ } elsif( $func eq 'E' ){
+ # E<x> - convert to character
+ $$rstr =~ s/^([^>]*)>//;
+ my $escape = $1;
+ $escape =~ s/^(\d+|X[\dA-F]+)$/#$1/i;
+ $res = "&$escape;";
+
+ } elsif( $func eq 'F' ){
+ # F<filename> - italizice
+ $res = '<em>' . process_text1( $lev, $rstr ) . '</em>';
+
+ } elsif( $func eq 'I' ){
+ # I<text> - italizice
+ $res = '<em>' . process_text1( $lev, $rstr ) . '</em>';
+
+ } elsif( $func eq 'L' ){
+ # L<link> - link
+ ## L<text|cross-ref> => produce text, use cross-ref for linking
+ ## L<cross-ref> => make text from cross-ref
+ ## need to extract text
+ my $par = go_ahead( $rstr, 'L', $closing );
+
+ # some L<>'s that shouldn't be:
+ # a) full-blown URL's are emitted as-is
+ if( $par =~ m{^\w+://}s ){
+ return make_URL_href( $par );
+ }
+ # b) C<...> is stripped and treated as C<>
+ if( $par =~ /^C<(.*)>$/ ){
+ my $text = depod( $1 );
+ return emit_C( $text, $lev > 1 || ($par =~ /[BI]</) );
+ }
+
+ # analyze the contents
+ $par =~ s/\n/ /g; # undo word-wrapped tags
+ my $opar = $par;
+ my $linktext;
+ if( $par =~ s{^([^|]+)\|}{} ){
+ $linktext = $1;
+ }
+
+ # make sure sections start with a /
+ $par =~ s{^"}{/"};
+
+ my( $page, $section, $ident );
+
+ # check for link patterns
+ if( $par =~ m{^([^/]+?)/(?!")(.*?)$} ){ # name/ident
+ # we've got a name/ident (no quotes)
+ ( $page, $ident ) = ( $1, $2 );
+ ### print STDERR "--> L<$par> to page $page, ident $ident\n";
+
+ } elsif( $par =~ m{^(.*?)/"?(.*?)"?$} ){ # [name]/"section"
+ # even though this should be a "section", we go for ident first
+ ( $page, $ident ) = ( $1, $2 );
+ ### print STDERR "--> L<$par> to page $page, section $section\n";
+
+ } elsif( $par =~ /\s/ ){ # this must be a section with missing quotes
+ ( $page, $section ) = ( '', $par );
+ ### print STDERR "--> L<$par> to void page, section $section\n";
+
+ } else {
+ ( $page, $section ) = ( $par, '' );
+ ### print STDERR "--> L<$par> to page $par, void section\n";
+ }
+
+ # now, either $section or $ident is defined. the convoluted logic
+ # below tries to resolve L<> according to what the user specified.
+ # failing this, we try to find the next best thing...
+ my( $url, $ltext, $fid );
+
+ RESOLVE: {
+ if( defined $ident ){
+ ## try to resolve $ident as an item
+ ( $url, $fid ) = coderef( $page, $ident );
+ if( $url ){
+ if( ! defined( $linktext ) ){
+ $linktext = $ident;
+ $linktext .= " in " if $ident && $page;
+ $linktext .= "the $page manpage" if $page;
+ }
+ ### print STDERR "got coderef url=$url\n";
+ last RESOLVE;
+ }
+ ## no luck: go for a section (auto-quoting!)
+ $section = $ident;
+ }
+ ## now go for a section
+ my $htmlsection = htmlify( $section );
+ $url = page_sect( $page, $htmlsection );
+ if( $url ){
+ if( ! defined( $linktext ) ){
+ $linktext = $section;
+ $linktext .= " in " if $section && $page;
+ $linktext .= "the $page manpage" if $page;
+ }
+ ### print STDERR "got page/section url=$url\n";
+ last RESOLVE;
+ }
+ ## no luck: go for an ident
+ if( $section ){
+ $ident = $section;
+ } else {
+ $ident = $page;
+ $page = undef();
+ }
+ ( $url, $fid ) = coderef( $page, $ident );
+ if( $url ){
+ if( ! defined( $linktext ) ){
+ $linktext = $ident;
+ $linktext .= " in " if $ident && $page;
+ $linktext .= "the $page manpage" if $page;
+ }
+ ### print STDERR "got section=>coderef url=$url\n";
+ last RESOLVE;
+ }
+
+ # warning; show some text.
+ $linktext = $opar unless defined $linktext;
+ warn "$0: $Podfile: cannot resolve L<$opar> in paragraph $Paragraph.\n" unless $Quiet;
+ }
+
+ # now we have a URL or just plain code
+ $$rstr = $linktext . '>' . $$rstr;
+ if( defined( $url ) ){
+ $res = "<a href=\"$url\">" . process_text1( $lev, $rstr ) . '</a>';
+ } else {
+ $res = '<em>' . process_text1( $lev, $rstr ) . '</em>';
+ }
+
+ } elsif( $func eq 'S' ){
+ # S<text> - non-breaking spaces
+ $res = process_text1( $lev, $rstr );
+ $res =~ s/ /&nbsp;/g;
+
+ } elsif( $func eq 'X' ){
+ # X<> - ignore
+ $$rstr =~ s/^[^>]*>//;
+
+ } elsif( $func eq 'Z' ){
+ # Z<> - empty
+ warn "$0: $Podfile: invalid X<> in paragraph $Paragraph.\n"
+ unless $$rstr =~ s/^>// or $Quiet;
+
+ } else {
+ my $term = pattern $closing;
+ while( $$rstr =~ s/\A(.*?)(([BCEFILSXZ])<(<+[^\S\n]+)?|$term)//s ){
+ # all others: either recurse into new function or
+ # terminate at closing angle bracket(s)
+ my $pt = $1;
+ $pt .= $2 if !$3 && $lev == 1;
+ $res .= $lev == 1 ? pure_text( $pt ) : inIS_text( $pt );
+ return $res if !$3 && $lev > 1;
+ if( $3 ){
+ $res .= process_text1( $lev, $rstr, $3, closing $4 );
+ }
+ }
+ if( $lev == 1 ){
+ $res .= pure_text( $$rstr );
+ } else {
+ warn "$0: $Podfile: undelimited $func<> in paragraph $Paragraph.\n" unless $Quiet;
+ }
+ }
+ return $res;
+}
+
+#
+# go_ahead: extract text of an IS (can be nested)
+#
+sub go_ahead($$$){
+ my( $rstr, $func, $closing ) = @_;
+ my $res = '';
+ my @closing = ($closing);
+ while( $$rstr =~
+ s/\A(.*?)(([BCEFILSXZ])<(<+[^\S\n]+)?|@{[pattern $closing[0]]})//s ){
+ $res .= $1;
+ unless( $3 ){
+ shift @closing;
+ return $res unless @closing;
+ } else {
+ unshift @closing, closing $4;
+ }
+ $res .= $2;
+ }
+ warn "$0: $Podfile: undelimited $func<> in paragraph $Paragraph.\n" unless $Quiet;
+ return $res;
+}
+
+#
+# emit_C - output result of C<text>
+# $text is the depod-ed text
+#
+sub emit_C($;$$){
+ my( $text, $nocode, $args ) = @_;
+ $args = '' unless defined $args;
+ my $res;
+ my( $url, $fid ) = coderef( undef(), $text );
+
+ # need HTML-safe text
+ my $linktext = html_escape( "$text$args" );
+
+ if( defined( $url ) &&
+ (!defined( $EmittedItem ) || $EmittedItem ne $fid ) ){
+ $res = "<a href=\"$url\"><code>$linktext</code></a>";
+ } elsif( 0 && $nocode ){
+ $res = $linktext;
+ } else {
+ $res = "<code>$linktext</code>";
+ }
+ return $res;
+}
+
+#
+# html_escape: make text safe for HTML
+#
+sub html_escape {
+ my $rest = $_[0];
+ $rest =~ s/&/&amp;/g;
+ $rest =~ s/</&lt;/g;
+ $rest =~ s/>/&gt;/g;
+ $rest =~ s/"/&quot;/g;
+ # &apos; is only in XHTML, not HTML4. Be conservative
+ #$rest =~ s/'/&apos;/g;
+ return $rest;
+}
+
+
+#
+# dosify - convert filenames to 8.3
+#
+sub dosify {
+ my($str) = @_;
+ return lc($str) if $^O eq 'VMS'; # VMS just needs casing
+ if ($Is83) {
+ $str = lc $str;
+ $str =~ s/(\.\w+)/substr ($1,0,4)/ge;
+ $str =~ s/(\w+)/substr ($1,0,8)/ge;
+ }
+ return $str;
+}
+
+#
+# page_sect - make a URL from the text of a L<>
+#
+sub page_sect($$) {
+ my( $page, $section ) = @_;
+ my( $linktext, $page83, $link); # work strings
+
+ # check if we know that this is a section in this page
+ if (!defined $Pages{$page} && defined $Sections{$page}) {
+ $section = $page;
+ $page = "";
+ ### print STDERR "reset page='', section=$section\n";
+ }
+
+ $page83=dosify($page);
+ $page=$page83 if (defined $Pages{$page83});
+ if ($page eq "") {
+ $link = "#" . anchorify( $section );
+ } elsif ( $page =~ /::/ ) {
+ $page =~ s,::,/,g;
+ # Search page cache for an entry keyed under the html page name,
+ # then look to see what directory that page might be in. NOTE:
+ # this will only find one page. A better solution might be to produce
+ # an intermediate page that is an index to all such pages.
+ my $page_name = $page ;
+ $page_name =~ s,^.*/,,s ;
+ if ( defined( $Pages{ $page_name } ) &&
+ $Pages{ $page_name } =~ /([^:]*$page)\.(?:pod|pm):/
+ ) {
+ $page = $1 ;
+ }
+ else {
+ # NOTE: This branch assumes that all A::B pages are located in
+ # $Htmlroot/A/B.html . This is often incorrect, since they are
+ # often in $Htmlroot/lib/A/B.html or such like. Perhaps we could
+ # analyze the contents of %Pages and figure out where any
+ # cousins of A::B are, then assume that. So, if A::B isn't found,
+ # but A::C is found in lib/A/C.pm, then A::B is assumed to be in
+ # lib/A/B.pm. This is also limited, but it's an improvement.
+ # Maybe a hints file so that the links point to the correct places
+ # nonetheless?
+
+ }
+ $link = "$Htmlroot/$page.html";
+ $link .= "#" . anchorify( $section ) if ($section);
+ } elsif (!defined $Pages{$page}) {
+ $link = "";
+ } else {
+ $section = anchorify( $section ) if $section ne "";
+ ### print STDERR "...section=$section\n";
+
+ # if there is a directory by the name of the page, then assume that an
+ # appropriate section will exist in the subdirectory
+# if ($section ne "" && $Pages{$page} =~ /([^:]*[^(\.pod|\.pm)]):/) {
+ if ($section ne "" && $Pages{$page} =~ /([^:]*(?<!\.pod)(?<!\.pm)):/) {
+ $link = "$Htmlroot/$1/$section.html";
+ ### print STDERR "...link=$link\n";
+
+ # since there is no directory by the name of the page, the section will
+ # have to exist within a .html of the same name. thus, make sure there
+ # is a .pod or .pm that might become that .html
+ } else {
+ $section = "#$section" if $section;
+ ### print STDERR "...section=$section\n";
+
+ # check if there is a .pod with the page name
+ if ($Pages{$page} =~ /([^:]*)\.pod:/) {
+ $link = "$Htmlroot/$1.html$section";
+ } elsif ($Pages{$page} =~ /([^:]*)\.pm:/) {
+ $link = "$Htmlroot/$1.html$section";
+ } else {
+ $link = "";
+ }
+ }
+ }
+
+ if ($link) {
+ # Here, we take advantage of the knowledge that $Htmlfileurl ne ''
+ # implies $Htmlroot eq ''. This means that the link in question
+ # needs a prefix of $Htmldir if it begins with '/'. The test for
+ # the initial '/' is done to avoid '#'-only links, and to allow
+ # for other kinds of links, like file:, ftp:, etc.
+ my $url ;
+ if ( $Htmlfileurl ne '' ) {
+ $link = "$Htmldir$link" if $link =~ m{^/}s;
+ $url = relativize_url( $link, $Htmlfileurl );
+# print( " b: [$link,$Htmlfileurl,$url]\n" );
+ }
+ else {
+ $url = $link ;
+ }
+ return $url;
+
+ } else {
+ return undef();
+ }
+}
+
+#
+# relativize_url - convert an absolute URL to one relative to a base URL.
+# Assumes both end in a filename.
+#
+sub relativize_url {
+ my ($dest,$source) = @_ ;
+
+ my ($dest_volume,$dest_directory,$dest_file) =
+ File::Spec::Unix->splitpath( $dest ) ;
+ $dest = File::Spec::Unix->catpath( $dest_volume, $dest_directory, '' ) ;
+
+ my ($source_volume,$source_directory,$source_file) =
+ File::Spec::Unix->splitpath( $source ) ;
+ $source = File::Spec::Unix->catpath( $source_volume, $source_directory, '' ) ;
+
+ my $rel_path = '' ;
+ if ( $dest ne '' ) {
+ $rel_path = File::Spec::Unix->abs2rel( $dest, $source ) ;
+ }
+
+ if ( $rel_path ne '' &&
+ substr( $rel_path, -1 ) ne '/' &&
+ substr( $dest_file, 0, 1 ) ne '#'
+ ) {
+ $rel_path .= "/$dest_file" ;
+ }
+ else {
+ $rel_path .= "$dest_file" ;
+ }
+
+ return $rel_path ;
+}
+
+
+#
+# coderef - make URL from the text of a C<>
+#
+sub coderef($$){
+ my( $page, $item ) = @_;
+ my( $url );
+
+ my $fid = fragment_id( $item );
+ if( defined( $page ) && $page ne "" ){
+ # we have been given a $page...
+ $page =~ s{::}{/}g;
+
+ # Do we take it? Item could be a section!
+ my $base = $Items{$fid} || "";
+ $base =~ s{[^/]*/}{};
+ if( $base ne "$page.html" ){
+ ### print STDERR "coderef( $page, $item ): items{$fid} = $Items{$fid} = $base => discard page!\n";
+ $page = undef();
+ }
+
+ } else {
+ # no page - local items precede cached items
+ if( defined( $fid ) ){
+ if( exists $Local_Items{$fid} ){
+ $page = $Local_Items{$fid};
+ } else {
+ $page = $Items{$fid};
+ }
+ }
+ }
+
+ # if there was a pod file that we found earlier with an appropriate
+ # =item directive, then create a link to that page.
+ if( defined $page ){
+ if( $page ){
+ if( exists $Pages{$page} and $Pages{$page} =~ /([^:.]*)\.[^:]*:/){
+ $page = $1 . '.html';
+ }
+ my $link = "$Htmlroot/$page#item_" . anchorify($fid);
+
+ # Here, we take advantage of the knowledge that $Htmlfileurl
+ # ne '' implies $Htmlroot eq ''.
+ if ( $Htmlfileurl ne '' ) {
+ $link = "$Htmldir$link" ;
+ $url = relativize_url( $link, $Htmlfileurl ) ;
+ } else {
+ $url = $link ;
+ }
+ } else {
+ $url = "#item_" . anchorify($fid);
+ }
+
+ confess "url has space: $url" if $url =~ /"[^"]*\s[^"]*"/;
+ }
+ return( $url, $fid );
+}
+
+
+
+#
+# Adapted from Nick Ing-Simmons' PodToHtml package.
+sub relative_url {
+ my $source_file = shift ;
+ my $destination_file = shift;
+
+ my $source = URI::file->new_abs($source_file);
+ my $uo = URI::file->new($destination_file,$source)->abs;
+ return $uo->rel->as_string;
+}
+
+
+#
+# finish_list - finish off any pending HTML lists. this should be called
+# after the entire pod file has been read and converted.
+#
+sub finish_list {
+ if( $Listlevel ){
+ warn "$0: $Podfile: unterminated list(s) at =head in paragraph $Paragraph. ignoring.\n" unless $Quiet;
+ while( $Listlevel ){
+ process_back();
+ }
+ }
+}
+
+#
+# htmlify - converts a pod section specification to a suitable section
+# specification for HTML. Note that we keep spaces and special characters
+# except ", ? (Netscape problem) and the hyphen (writer's problem...).
+#
+sub htmlify {
+ my( $heading) = @_;
+ $heading =~ s/(\s+)/ /g;
+ $heading =~ s/\s+\Z//;
+ $heading =~ s/\A\s+//;
+ # The hyphen is a disgrace to the English language.
+ $heading =~ s/[-"?]//g;
+ $heading = lc( $heading );
+ return $heading;
+}
+
+#
+# similar to htmlify, but turns non-alphanumerics into underscores
+#
+sub anchorify {
+ my ($anchor) = @_;
+ $anchor = htmlify($anchor);
+ $anchor =~ s/\W/_/g;
+ return $anchor;
+}
+
+#
+# depod - convert text by eliminating all interior sequences
+# Note: can be called with copy or modify semantics
+#
+my %E2c;
+$E2c{lt} = '<';
+$E2c{gt} = '>';
+$E2c{sol} = '/';
+$E2c{verbar} = '|';
+$E2c{amp} = '&'; # in Tk's pods
+
+sub depod1($;$$);
+
+sub depod($){
+ my $string;
+ if( ref( $_[0] ) ){
+ $string = ${$_[0]};
+ ${$_[0]} = depod1( \$string );
+ } else {
+ $string = $_[0];
+ depod1( \$string );
+ }
+}
+
+sub depod1($;$$){
+ my( $rstr, $func, $closing ) = @_;
+ my $res = '';
+ return $res unless defined $$rstr;
+ if( ! defined( $func ) ){
+ # skip to next begin of an interior sequence
+ while( $$rstr =~ s/\A(.*?)([BCEFILSXZ])<(<+[^\S\n]+)?// ){
+ # recurse into its text
+ $res .= $1 . depod1( $rstr, $2, closing $3);
+ }
+ $res .= $$rstr;
+ } elsif( $func eq 'E' ){
+ # E<x> - convert to character
+ $$rstr =~ s/^([^>]*)>//;
+ $res .= $E2c{$1} || "";
+ } elsif( $func eq 'X' ){
+ # X<> - ignore
+ $$rstr =~ s/^[^>]*>//;
+ } elsif( $func eq 'Z' ){
+ # Z<> - empty
+ $$rstr =~ s/^>//;
+ } else {
+ # all others: either recurse into new function or
+ # terminate at closing angle bracket
+ my $term = pattern $closing;
+ while( $$rstr =~ s/\A(.*?)(([BCEFILSXZ])<(<+[^\S\n]+)?|$term)// ){
+ $res .= $1;
+ last unless $3;
+ $res .= depod1( $rstr, $3, closing $4 );
+ }
+ ## If we're here and $2 ne '>': undelimited interior sequence.
+ ## Ignored, as this is called without proper indication of where we are.
+ ## Rely on process_text to produce diagnostics.
+ }
+ return $res;
+}
+
+#
+# fragment_id - construct a fragment identifier from:
+# a) =item text
+# b) contents of C<...>
+#
+my @HC;
+sub fragment_id {
+ my $text = shift();
+ $text =~ s/\s+\Z//s;
+ if( $text ){
+ # a method or function?
+ return $1 if $text =~ /(\w+)\s*\(/;
+ return $1 if $text =~ /->\s*(\w+)\s*\(?/;
+
+ # a variable name?
+ return $1 if $text =~ /^([\$\@%*]\S+)/;
+
+ # some pattern matching operator?
+ return $1 if $text =~ m|^(\w+/).*/\w*$|;
+
+ # fancy stuff... like "do { }"
+ return $1 if $text =~ m|^(\w+)\s*{.*}$|;
+
+ # honour the perlfunc manpage: func [PAR[,[ ]PAR]...]
+ # and some funnies with ... Module ...
+ return $1 if $text =~ m{^([a-z\d_]+)(\s+[A-Z\d,/& ]+)?$};
+ return $1 if $text =~ m{^([a-z\d]+)\s+Module(\s+[A-Z\d,/& ]+)?$};
+
+ # text? normalize!
+ $text =~ s/\s+/_/sg;
+ $text =~ s{(\W)}{
+ defined( $HC[ord($1)] ) ? $HC[ord($1)]
+ : ( $HC[ord($1)] = sprintf( "%%%02X", ord($1) ) ) }gxe;
+ $text = substr( $text, 0, 50 );
+ } else {
+ return undef();
+ }
+}
+
+#
+# make_URL_href - generate HTML href from URL
+# Special treatment for CGI queries.
+#
+sub make_URL_href($){
+ my( $url ) = @_;
+ if( $url !~
+ s{^(http:[-\w/#~:.+=&%@!]+)(\?.*)$}{<a href="$1$2">$1</a>}i ){
+ $url = "<a href=\"$url\">$url</a>";
+ }
+ return $url;
+}
+
+1;
diff --git a/Master/tlpkg/tlperl/lib/Pod/InputObjects.pm b/Master/tlpkg/tlperl/lib/Pod/InputObjects.pm
new file mode 100644
index 00000000000..fa5f61f9a70
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/InputObjects.pm
@@ -0,0 +1,941 @@
+#############################################################################
+# Pod/InputObjects.pm -- package which defines objects for input streams
+# and paragraphs and commands when parsing POD docs.
+#
+# Copyright (C) 1996-2000 by Bradford Appleton. All rights reserved.
+# This file is part of "PodParser". PodParser is free software;
+# you can redistribute it and/or modify it under the same terms
+# as Perl itself.
+#############################################################################
+
+package Pod::InputObjects;
+
+use vars qw($VERSION);
+$VERSION = 1.30; ## Current version of this package
+require 5.005; ## requires this Perl version or later
+
+#############################################################################
+
+=head1 NAME
+
+Pod::InputObjects - objects representing POD input paragraphs, commands, etc.
+
+=head1 SYNOPSIS
+
+ use Pod::InputObjects;
+
+=head1 REQUIRES
+
+perl5.004, Carp
+
+=head1 EXPORTS
+
+Nothing.
+
+=head1 DESCRIPTION
+
+This module defines some basic input objects used by B<Pod::Parser> when
+reading and parsing POD text from an input source. The following objects
+are defined:
+
+=over 4
+
+=begin __PRIVATE__
+
+=item package B<Pod::InputSource>
+
+An object corresponding to a source of POD input text. It is mostly a
+wrapper around a filehandle or C<IO::Handle>-type object (or anything
+that implements the C<getline()> method) which keeps track of some
+additional information relevant to the parsing of PODs.
+
+=end __PRIVATE__
+
+=item package B<Pod::Paragraph>
+
+An object corresponding to a paragraph of POD input text. It may be a
+plain paragraph, a verbatim paragraph, or a command paragraph (see
+L<perlpod>).
+
+=item package B<Pod::InteriorSequence>
+
+An object corresponding to an interior sequence command from the POD
+input text (see L<perlpod>).
+
+=item package B<Pod::ParseTree>
+
+An object corresponding to a tree of parsed POD text. Each "node" in
+a parse-tree (or I<ptree>) is either a text-string or a reference to
+a B<Pod::InteriorSequence> object. The nodes appear in the parse-tree
+in the order in which they were parsed from left-to-right.
+
+=back
+
+Each of these input objects are described in further detail in the
+sections which follow.
+
+=cut
+
+#############################################################################
+
+use strict;
+#use diagnostics;
+#use Carp;
+
+#############################################################################
+
+package Pod::InputSource;
+
+##---------------------------------------------------------------------------
+
+=begin __PRIVATE__
+
+=head1 B<Pod::InputSource>
+
+This object corresponds to an input source or stream of POD
+documentation. When parsing PODs, it is necessary to associate and store
+certain context information with each input source. All of this
+information is kept together with the stream itself in one of these
+C<Pod::InputSource> objects. Each such object is merely a wrapper around
+an C<IO::Handle> object of some kind (or at least something that
+implements the C<getline()> method). They have the following
+methods/attributes:
+
+=end __PRIVATE__
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=begin __PRIVATE__
+
+=head2 B<new()>
+
+ my $pod_input1 = Pod::InputSource->new(-handle => $filehandle);
+ my $pod_input2 = new Pod::InputSource(-handle => $filehandle,
+ -name => $name);
+ my $pod_input3 = new Pod::InputSource(-handle => \*STDIN);
+ my $pod_input4 = Pod::InputSource->new(-handle => \*STDIN,
+ -name => "(STDIN)");
+
+This is a class method that constructs a C<Pod::InputSource> object and
+returns a reference to the new input source object. It takes one or more
+keyword arguments in the form of a hash. The keyword C<-handle> is
+required and designates the corresponding input handle. The keyword
+C<-name> is optional and specifies the name associated with the input
+handle (typically a file name).
+
+=end __PRIVATE__
+
+=cut
+
+sub new {
+ ## Determine if we were called via an object-ref or a classname
+ my $this = shift;
+ my $class = ref($this) || $this;
+
+ ## Any remaining arguments are treated as initial values for the
+ ## hash that is used to represent this object. Note that we default
+ ## certain values by specifying them *before* the arguments passed.
+ ## If they are in the argument list, they will override the defaults.
+ my $self = { -name => '(unknown)',
+ -handle => undef,
+ -was_cutting => 0,
+ @_ };
+
+ ## Bless ourselves into the desired class and perform any initialization
+ bless $self, $class;
+ return $self;
+}
+
+##---------------------------------------------------------------------------
+
+=begin __PRIVATE__
+
+=head2 B<name()>
+
+ my $filename = $pod_input->name();
+ $pod_input->name($new_filename_to_use);
+
+This method gets/sets the name of the input source (usually a filename).
+If no argument is given, it returns a string containing the name of
+the input source; otherwise it sets the name of the input source to the
+contents of the given argument.
+
+=end __PRIVATE__
+
+=cut
+
+sub name {
+ (@_ > 1) and $_[0]->{'-name'} = $_[1];
+ return $_[0]->{'-name'};
+}
+
+## allow 'filename' as an alias for 'name'
+*filename = \&name;
+
+##---------------------------------------------------------------------------
+
+=begin __PRIVATE__
+
+=head2 B<handle()>
+
+ my $handle = $pod_input->handle();
+
+Returns a reference to the handle object from which input is read (the
+one used to contructed this input source object).
+
+=end __PRIVATE__
+
+=cut
+
+sub handle {
+ return $_[0]->{'-handle'};
+}
+
+##---------------------------------------------------------------------------
+
+=begin __PRIVATE__
+
+=head2 B<was_cutting()>
+
+ print "Yes.\n" if ($pod_input->was_cutting());
+
+The value of the C<cutting> state (that the B<cutting()> method would
+have returned) immediately before any input was read from this input
+stream. After all input from this stream has been read, the C<cutting>
+state is restored to this value.
+
+=end __PRIVATE__
+
+=cut
+
+sub was_cutting {
+ (@_ > 1) and $_[0]->{-was_cutting} = $_[1];
+ return $_[0]->{-was_cutting};
+}
+
+##---------------------------------------------------------------------------
+
+#############################################################################
+
+package Pod::Paragraph;
+
+##---------------------------------------------------------------------------
+
+=head1 B<Pod::Paragraph>
+
+An object representing a paragraph of POD input text.
+It has the following methods/attributes:
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=head2 Pod::Paragraph-E<gt>B<new()>
+
+ my $pod_para1 = Pod::Paragraph->new(-text => $text);
+ my $pod_para2 = Pod::Paragraph->new(-name => $cmd,
+ -text => $text);
+ my $pod_para3 = new Pod::Paragraph(-text => $text);
+ my $pod_para4 = new Pod::Paragraph(-name => $cmd,
+ -text => $text);
+ my $pod_para5 = Pod::Paragraph->new(-name => $cmd,
+ -text => $text,
+ -file => $filename,
+ -line => $line_number);
+
+This is a class method that constructs a C<Pod::Paragraph> object and
+returns a reference to the new paragraph object. It may be given one or
+two keyword arguments. The C<-text> keyword indicates the corresponding
+text of the POD paragraph. The C<-name> keyword indicates the name of
+the corresponding POD command, such as C<head1> or C<item> (it should
+I<not> contain the C<=> prefix); this is needed only if the POD
+paragraph corresponds to a command paragraph. The C<-file> and C<-line>
+keywords indicate the filename and line number corresponding to the
+beginning of the paragraph
+
+=cut
+
+sub new {
+ ## Determine if we were called via an object-ref or a classname
+ my $this = shift;
+ my $class = ref($this) || $this;
+
+ ## Any remaining arguments are treated as initial values for the
+ ## hash that is used to represent this object. Note that we default
+ ## certain values by specifying them *before* the arguments passed.
+ ## If they are in the argument list, they will override the defaults.
+ my $self = {
+ -name => undef,
+ -text => (@_ == 1) ? shift : undef,
+ -file => '<unknown-file>',
+ -line => 0,
+ -prefix => '=',
+ -separator => ' ',
+ -ptree => [],
+ @_
+ };
+
+ ## Bless ourselves into the desired class and perform any initialization
+ bless $self, $class;
+ return $self;
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_para-E<gt>B<cmd_name()>
+
+ my $para_cmd = $pod_para->cmd_name();
+
+If this paragraph is a command paragraph, then this method will return
+the name of the command (I<without> any leading C<=> prefix).
+
+=cut
+
+sub cmd_name {
+ (@_ > 1) and $_[0]->{'-name'} = $_[1];
+ return $_[0]->{'-name'};
+}
+
+## let name() be an alias for cmd_name()
+*name = \&cmd_name;
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_para-E<gt>B<text()>
+
+ my $para_text = $pod_para->text();
+
+This method will return the corresponding text of the paragraph.
+
+=cut
+
+sub text {
+ (@_ > 1) and $_[0]->{'-text'} = $_[1];
+ return $_[0]->{'-text'};
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_para-E<gt>B<raw_text()>
+
+ my $raw_pod_para = $pod_para->raw_text();
+
+This method will return the I<raw> text of the POD paragraph, exactly
+as it appeared in the input.
+
+=cut
+
+sub raw_text {
+ return $_[0]->{'-text'} unless (defined $_[0]->{'-name'});
+ return $_[0]->{'-prefix'} . $_[0]->{'-name'} .
+ $_[0]->{'-separator'} . $_[0]->{'-text'};
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_para-E<gt>B<cmd_prefix()>
+
+ my $prefix = $pod_para->cmd_prefix();
+
+If this paragraph is a command paragraph, then this method will return
+the prefix used to denote the command (which should be the string "="
+or "==").
+
+=cut
+
+sub cmd_prefix {
+ return $_[0]->{'-prefix'};
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_para-E<gt>B<cmd_separator()>
+
+ my $separator = $pod_para->cmd_separator();
+
+If this paragraph is a command paragraph, then this method will return
+the text used to separate the command name from the rest of the
+paragraph (if any).
+
+=cut
+
+sub cmd_separator {
+ return $_[0]->{'-separator'};
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_para-E<gt>B<parse_tree()>
+
+ my $ptree = $pod_parser->parse_text( $pod_para->text() );
+ $pod_para->parse_tree( $ptree );
+ $ptree = $pod_para->parse_tree();
+
+This method will get/set the corresponding parse-tree of the paragraph's text.
+
+=cut
+
+sub parse_tree {
+ (@_ > 1) and $_[0]->{'-ptree'} = $_[1];
+ return $_[0]->{'-ptree'};
+}
+
+## let ptree() be an alias for parse_tree()
+*ptree = \&parse_tree;
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_para-E<gt>B<file_line()>
+
+ my ($filename, $line_number) = $pod_para->file_line();
+ my $position = $pod_para->file_line();
+
+Returns the current filename and line number for the paragraph
+object. If called in a list context, it returns a list of two
+elements: first the filename, then the line number. If called in
+a scalar context, it returns a string containing the filename, followed
+by a colon (':'), followed by the line number.
+
+=cut
+
+sub file_line {
+ my @loc = ($_[0]->{'-file'} || '<unknown-file>',
+ $_[0]->{'-line'} || 0);
+ return (wantarray) ? @loc : join(':', @loc);
+}
+
+##---------------------------------------------------------------------------
+
+#############################################################################
+
+package Pod::InteriorSequence;
+
+##---------------------------------------------------------------------------
+
+=head1 B<Pod::InteriorSequence>
+
+An object representing a POD interior sequence command.
+It has the following methods/attributes:
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=head2 Pod::InteriorSequence-E<gt>B<new()>
+
+ my $pod_seq1 = Pod::InteriorSequence->new(-name => $cmd
+ -ldelim => $delimiter);
+ my $pod_seq2 = new Pod::InteriorSequence(-name => $cmd,
+ -ldelim => $delimiter);
+ my $pod_seq3 = new Pod::InteriorSequence(-name => $cmd,
+ -ldelim => $delimiter,
+ -file => $filename,
+ -line => $line_number);
+
+ my $pod_seq4 = new Pod::InteriorSequence(-name => $cmd, $ptree);
+ my $pod_seq5 = new Pod::InteriorSequence($cmd, $ptree);
+
+This is a class method that constructs a C<Pod::InteriorSequence> object
+and returns a reference to the new interior sequence object. It should
+be given two keyword arguments. The C<-ldelim> keyword indicates the
+corresponding left-delimiter of the interior sequence (e.g. 'E<lt>').
+The C<-name> keyword indicates the name of the corresponding interior
+sequence command, such as C<I> or C<B> or C<C>. The C<-file> and
+C<-line> keywords indicate the filename and line number corresponding
+to the beginning of the interior sequence. If the C<$ptree> argument is
+given, it must be the last argument, and it must be either string, or
+else an array-ref suitable for passing to B<Pod::ParseTree::new> (or
+it may be a reference to a Pod::ParseTree object).
+
+=cut
+
+sub new {
+ ## Determine if we were called via an object-ref or a classname
+ my $this = shift;
+ my $class = ref($this) || $this;
+
+ ## See if first argument has no keyword
+ if (((@_ <= 2) or (@_ % 2)) and $_[0] !~ /^-\w/) {
+ ## Yup - need an implicit '-name' before first parameter
+ unshift @_, '-name';
+ }
+
+ ## See if odd number of args
+ if ((@_ % 2) != 0) {
+ ## Yup - need an implicit '-ptree' before the last parameter
+ splice @_, $#_, 0, '-ptree';
+ }
+
+ ## Any remaining arguments are treated as initial values for the
+ ## hash that is used to represent this object. Note that we default
+ ## certain values by specifying them *before* the arguments passed.
+ ## If they are in the argument list, they will override the defaults.
+ my $self = {
+ -name => (@_ == 1) ? $_[0] : undef,
+ -file => '<unknown-file>',
+ -line => 0,
+ -ldelim => '<',
+ -rdelim => '>',
+ @_
+ };
+
+ ## Initialize contents if they havent been already
+ my $ptree = $self->{'-ptree'} || new Pod::ParseTree();
+ if ( ref $ptree =~ /^(ARRAY)?$/ ) {
+ ## We have an array-ref, or a normal scalar. Pass it as an
+ ## an argument to the ptree-constructor
+ $ptree = new Pod::ParseTree($1 ? [$ptree] : $ptree);
+ }
+ $self->{'-ptree'} = $ptree;
+
+ ## Bless ourselves into the desired class and perform any initialization
+ bless $self, $class;
+ return $self;
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_seq-E<gt>B<cmd_name()>
+
+ my $seq_cmd = $pod_seq->cmd_name();
+
+The name of the interior sequence command.
+
+=cut
+
+sub cmd_name {
+ (@_ > 1) and $_[0]->{'-name'} = $_[1];
+ return $_[0]->{'-name'};
+}
+
+## let name() be an alias for cmd_name()
+*name = \&cmd_name;
+
+##---------------------------------------------------------------------------
+
+## Private subroutine to set the parent pointer of all the given
+## children that are interior-sequences to be $self
+
+sub _set_child2parent_links {
+ my ($self, @children) = @_;
+ ## Make sure any sequences know who their parent is
+ for (@children) {
+ next unless (length and ref and ref ne 'SCALAR');
+ if (UNIVERSAL::isa($_, 'Pod::InteriorSequence') or
+ UNIVERSAL::can($_, 'nested'))
+ {
+ $_->nested($self);
+ }
+ }
+}
+
+## Private subroutine to unset child->parent links
+
+sub _unset_child2parent_links {
+ my $self = shift;
+ $self->{'-parent_sequence'} = undef;
+ my $ptree = $self->{'-ptree'};
+ for (@$ptree) {
+ next unless (length and ref and ref ne 'SCALAR');
+ $_->_unset_child2parent_links()
+ if UNIVERSAL::isa($_, 'Pod::InteriorSequence');
+ }
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_seq-E<gt>B<prepend()>
+
+ $pod_seq->prepend($text);
+ $pod_seq1->prepend($pod_seq2);
+
+Prepends the given string or parse-tree or sequence object to the parse-tree
+of this interior sequence.
+
+=cut
+
+sub prepend {
+ my $self = shift;
+ $self->{'-ptree'}->prepend(@_);
+ _set_child2parent_links($self, @_);
+ return $self;
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_seq-E<gt>B<append()>
+
+ $pod_seq->append($text);
+ $pod_seq1->append($pod_seq2);
+
+Appends the given string or parse-tree or sequence object to the parse-tree
+of this interior sequence.
+
+=cut
+
+sub append {
+ my $self = shift;
+ $self->{'-ptree'}->append(@_);
+ _set_child2parent_links($self, @_);
+ return $self;
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_seq-E<gt>B<nested()>
+
+ $outer_seq = $pod_seq->nested || print "not nested";
+
+If this interior sequence is nested inside of another interior
+sequence, then the outer/parent sequence that contains it is
+returned. Otherwise C<undef> is returned.
+
+=cut
+
+sub nested {
+ my $self = shift;
+ (@_ == 1) and $self->{'-parent_sequence'} = shift;
+ return $self->{'-parent_sequence'} || undef;
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_seq-E<gt>B<raw_text()>
+
+ my $seq_raw_text = $pod_seq->raw_text();
+
+This method will return the I<raw> text of the POD interior sequence,
+exactly as it appeared in the input.
+
+=cut
+
+sub raw_text {
+ my $self = shift;
+ my $text = $self->{'-name'} . $self->{'-ldelim'};
+ for ( $self->{'-ptree'}->children ) {
+ $text .= (ref $_) ? $_->raw_text : $_;
+ }
+ $text .= $self->{'-rdelim'};
+ return $text;
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_seq-E<gt>B<left_delimiter()>
+
+ my $ldelim = $pod_seq->left_delimiter();
+
+The leftmost delimiter beginning the argument text to the interior
+sequence (should be "<").
+
+=cut
+
+sub left_delimiter {
+ (@_ > 1) and $_[0]->{'-ldelim'} = $_[1];
+ return $_[0]->{'-ldelim'};
+}
+
+## let ldelim() be an alias for left_delimiter()
+*ldelim = \&left_delimiter;
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_seq-E<gt>B<right_delimiter()>
+
+The rightmost delimiter beginning the argument text to the interior
+sequence (should be ">").
+
+=cut
+
+sub right_delimiter {
+ (@_ > 1) and $_[0]->{'-rdelim'} = $_[1];
+ return $_[0]->{'-rdelim'};
+}
+
+## let rdelim() be an alias for right_delimiter()
+*rdelim = \&right_delimiter;
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_seq-E<gt>B<parse_tree()>
+
+ my $ptree = $pod_parser->parse_text($paragraph_text);
+ $pod_seq->parse_tree( $ptree );
+ $ptree = $pod_seq->parse_tree();
+
+This method will get/set the corresponding parse-tree of the interior
+sequence's text.
+
+=cut
+
+sub parse_tree {
+ (@_ > 1) and $_[0]->{'-ptree'} = $_[1];
+ return $_[0]->{'-ptree'};
+}
+
+## let ptree() be an alias for parse_tree()
+*ptree = \&parse_tree;
+
+##---------------------------------------------------------------------------
+
+=head2 $pod_seq-E<gt>B<file_line()>
+
+ my ($filename, $line_number) = $pod_seq->file_line();
+ my $position = $pod_seq->file_line();
+
+Returns the current filename and line number for the interior sequence
+object. If called in a list context, it returns a list of two
+elements: first the filename, then the line number. If called in
+a scalar context, it returns a string containing the filename, followed
+by a colon (':'), followed by the line number.
+
+=cut
+
+sub file_line {
+ my @loc = ($_[0]->{'-file'} || '<unknown-file>',
+ $_[0]->{'-line'} || 0);
+ return (wantarray) ? @loc : join(':', @loc);
+}
+
+##---------------------------------------------------------------------------
+
+=head2 Pod::InteriorSequence::B<DESTROY()>
+
+This method performs any necessary cleanup for the interior-sequence.
+If you override this method then it is B<imperative> that you invoke
+the parent method from within your own method, otherwise
+I<interior-sequence storage will not be reclaimed upon destruction!>
+
+=cut
+
+sub DESTROY {
+ ## We need to get rid of all child->parent pointers throughout the
+ ## tree so their reference counts will go to zero and they can be
+ ## garbage-collected
+ _unset_child2parent_links(@_);
+}
+
+##---------------------------------------------------------------------------
+
+#############################################################################
+
+package Pod::ParseTree;
+
+##---------------------------------------------------------------------------
+
+=head1 B<Pod::ParseTree>
+
+This object corresponds to a tree of parsed POD text. As POD text is
+scanned from left to right, it is parsed into an ordered list of
+text-strings and B<Pod::InteriorSequence> objects (in order of
+appearance). A B<Pod::ParseTree> object corresponds to this list of
+strings and sequences. Each interior sequence in the parse-tree may
+itself contain a parse-tree (since interior sequences may be nested).
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=head2 Pod::ParseTree-E<gt>B<new()>
+
+ my $ptree1 = Pod::ParseTree->new;
+ my $ptree2 = new Pod::ParseTree;
+ my $ptree4 = Pod::ParseTree->new($array_ref);
+ my $ptree3 = new Pod::ParseTree($array_ref);
+
+This is a class method that constructs a C<Pod::Parse_tree> object and
+returns a reference to the new parse-tree. If a single-argument is given,
+it must be a reference to an array, and is used to initialize the root
+(top) of the parse tree.
+
+=cut
+
+sub new {
+ ## Determine if we were called via an object-ref or a classname
+ my $this = shift;
+ my $class = ref($this) || $this;
+
+ my $self = (@_ == 1 and ref $_[0]) ? $_[0] : [];
+
+ ## Bless ourselves into the desired class and perform any initialization
+ bless $self, $class;
+ return $self;
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $ptree-E<gt>B<top()>
+
+ my $top_node = $ptree->top();
+ $ptree->top( $top_node );
+ $ptree->top( @children );
+
+This method gets/sets the top node of the parse-tree. If no arguments are
+given, it returns the topmost node in the tree (the root), which is also
+a B<Pod::ParseTree>. If it is given a single argument that is a reference,
+then the reference is assumed to a parse-tree and becomes the new top node.
+Otherwise, if arguments are given, they are treated as the new list of
+children for the top node.
+
+=cut
+
+sub top {
+ my $self = shift;
+ if (@_ > 0) {
+ @{ $self } = (@_ == 1 and ref $_[0]) ? ${ @_ } : @_;
+ }
+ return $self;
+}
+
+## let parse_tree() & ptree() be aliases for the 'top' method
+*parse_tree = *ptree = \&top;
+
+##---------------------------------------------------------------------------
+
+=head2 $ptree-E<gt>B<children()>
+
+This method gets/sets the children of the top node in the parse-tree.
+If no arguments are given, it returns the list (array) of children
+(each of which should be either a string or a B<Pod::InteriorSequence>.
+Otherwise, if arguments are given, they are treated as the new list of
+children for the top node.
+
+=cut
+
+sub children {
+ my $self = shift;
+ if (@_ > 0) {
+ @{ $self } = (@_ == 1 and ref $_[0]) ? ${ @_ } : @_;
+ }
+ return @{ $self };
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $ptree-E<gt>B<prepend()>
+
+This method prepends the given text or parse-tree to the current parse-tree.
+If the first item on the parse-tree is text and the argument is also text,
+then the text is prepended to the first item (not added as a separate string).
+Otherwise the argument is added as a new string or parse-tree I<before>
+the current one.
+
+=cut
+
+use vars qw(@ptree); ## an alias used for performance reasons
+
+sub prepend {
+ my $self = shift;
+ local *ptree = $self;
+ for (@_) {
+ next unless length;
+ if (@ptree and !(ref $ptree[0]) and !(ref $_)) {
+ $ptree[0] = $_ . $ptree[0];
+ }
+ else {
+ unshift @ptree, $_;
+ }
+ }
+}
+
+##---------------------------------------------------------------------------
+
+=head2 $ptree-E<gt>B<append()>
+
+This method appends the given text or parse-tree to the current parse-tree.
+If the last item on the parse-tree is text and the argument is also text,
+then the text is appended to the last item (not added as a separate string).
+Otherwise the argument is added as a new string or parse-tree I<after>
+the current one.
+
+=cut
+
+sub append {
+ my $self = shift;
+ local *ptree = $self;
+ my $can_append = @ptree && !(ref $ptree[-1]);
+ for (@_) {
+ if (ref) {
+ push @ptree, $_;
+ }
+ elsif(!length) {
+ next;
+ }
+ elsif ($can_append) {
+ $ptree[-1] .= $_;
+ }
+ else {
+ push @ptree, $_;
+ }
+ }
+}
+
+=head2 $ptree-E<gt>B<raw_text()>
+
+ my $ptree_raw_text = $ptree->raw_text();
+
+This method will return the I<raw> text of the POD parse-tree
+exactly as it appeared in the input.
+
+=cut
+
+sub raw_text {
+ my $self = shift;
+ my $text = "";
+ for ( @$self ) {
+ $text .= (ref $_) ? $_->raw_text : $_;
+ }
+ return $text;
+}
+
+##---------------------------------------------------------------------------
+
+## Private routines to set/unset child->parent links
+
+sub _unset_child2parent_links {
+ my $self = shift;
+ local *ptree = $self;
+ for (@ptree) {
+ next unless (defined and length and ref and ref ne 'SCALAR');
+ $_->_unset_child2parent_links()
+ if UNIVERSAL::isa($_, 'Pod::InteriorSequence');
+ }
+}
+
+sub _set_child2parent_links {
+ ## nothing to do, Pod::ParseTrees cant have parent pointers
+}
+
+=head2 Pod::ParseTree::B<DESTROY()>
+
+This method performs any necessary cleanup for the parse-tree.
+If you override this method then it is B<imperative>
+that you invoke the parent method from within your own method,
+otherwise I<parse-tree storage will not be reclaimed upon destruction!>
+
+=cut
+
+sub DESTROY {
+ ## We need to get rid of all child->parent pointers throughout the
+ ## tree so their reference counts will go to zero and they can be
+ ## garbage-collected
+ _unset_child2parent_links(@_);
+}
+
+#############################################################################
+
+=head1 SEE ALSO
+
+See L<Pod::Parser>, L<Pod::Select>
+
+=head1 AUTHOR
+
+Please report bugs using L<http://rt.cpan.org>.
+
+Brad Appleton E<lt>bradapp@enteract.comE<gt>
+
+=cut
+
+1;
diff --git a/Master/tlpkg/tlperl/lib/Pod/LaTeX.pm b/Master/tlpkg/tlperl/lib/Pod/LaTeX.pm
new file mode 100644
index 00000000000..9d3a905258f
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/LaTeX.pm
@@ -0,0 +1,1876 @@
+package Pod::LaTeX;
+
+=head1 NAME
+
+Pod::LaTeX - Convert Pod data to formatted Latex
+
+=head1 SYNOPSIS
+
+ use Pod::LaTeX;
+ my $parser = Pod::LaTeX->new ( );
+
+ $parser->parse_from_filehandle;
+
+ $parser->parse_from_file ('file.pod', 'file.tex');
+
+=head1 DESCRIPTION
+
+C<Pod::LaTeX> is a module to convert documentation in the Pod format
+into Latex. The L<B<pod2latex>|pod2latex> X<pod2latex> command uses
+this module for translation.
+
+C<Pod::LaTeX> is a derived class from L<Pod::Select|Pod::Select>.
+
+=cut
+
+
+use strict;
+require Pod::ParseUtils;
+use base qw/ Pod::Select /;
+
+# use Data::Dumper; # for debugging
+use Carp;
+
+use vars qw/ $VERSION %HTML_Escapes @LatexSections /;
+
+$VERSION = '0.58';
+
+# Definitions of =headN -> latex mapping
+@LatexSections = (qw/
+ chapter
+ section
+ subsection
+ subsubsection
+ paragraph
+ subparagraph
+ /);
+
+# Standard escape sequences converted to Latex.
+# The Unicode name of each character is given in the comments.
+# Complete LaTeX set added by Peter Acklam.
+
+%HTML_Escapes = (
+ 'sol' => '\textfractionsolidus{}', # xxx - or should it be just '/'
+ 'verbar' => '|',
+
+ # The stuff below is based on the information available at
+ # http://www.w3.org/TR/html401/sgml/entities.html
+
+ # All characters in the range 0xA0-0xFF of the ISO 8859-1 character set.
+ # Several of these characters require the `textcomp' LaTeX package.
+ 'nbsp' => q|~|, # 0xA0 - no-break space = non-breaking space
+ 'iexcl' => q|\textexclamdown{}|, # 0xA1 - inverted exclamation mark
+ 'cent' => q|\textcent{}|, # 0xA2 - cent sign
+ 'pound' => q|\textsterling{}|, # 0xA3 - pound sign
+ 'curren' => q|\textcurrency{}|, # 0xA4 - currency sign
+ 'yen' => q|\textyen{}|, # 0xA5 - yen sign = yuan sign
+ 'brvbar' => q|\textbrokenbar{}|, # 0xA6 - broken bar = broken vertical bar
+ 'sect' => q|\textsection{}|, # 0xA7 - section sign
+ 'uml' => q|\textasciidieresis{}|, # 0xA8 - diaeresis = spacing diaeresis
+ 'copy' => q|\textcopyright{}|, # 0xA9 - copyright sign
+ 'ordf' => q|\textordfeminine{}|, # 0xAA - feminine ordinal indicator
+ 'laquo' => q|\guillemotleft{}|, # 0xAB - left-pointing double angle quotation mark = left pointing guillemet
+ 'not' => q|\textlnot{}|, # 0xAC - not sign
+ 'shy' => q|\-|, # 0xAD - soft hyphen = discretionary hyphen
+ 'reg' => q|\textregistered{}|, # 0xAE - registered sign = registered trade mark sign
+ 'macr' => q|\textasciimacron{}|, # 0xAF - macron = spacing macron = overline = APL overbar
+ 'deg' => q|\textdegree{}|, # 0xB0 - degree sign
+ 'plusmn' => q|\textpm{}|, # 0xB1 - plus-minus sign = plus-or-minus sign
+ 'sup2' => q|\texttwosuperior{}|, # 0xB2 - superscript two = superscript digit two = squared
+ 'sup3' => q|\textthreesuperior{}|, # 0xB3 - superscript three = superscript digit three = cubed
+ 'acute' => q|\textasciiacute{}|, # 0xB4 - acute accent = spacing acute
+ 'micro' => q|\textmu{}|, # 0xB5 - micro sign
+ 'para' => q|\textparagraph{}|, # 0xB6 - pilcrow sign = paragraph sign
+ 'middot' => q|\textperiodcentered{}|, # 0xB7 - middle dot = Georgian comma = Greek middle dot
+ 'cedil' => q|\c{}|, # 0xB8 - cedilla = spacing cedilla
+ 'sup1' => q|\textonesuperior{}|, # 0xB9 - superscript one = superscript digit one
+ 'ordm' => q|\textordmasculine{}|, # 0xBA - masculine ordinal indicator
+ 'raquo' => q|\guillemotright{}|, # 0xBB - right-pointing double angle quotation mark = right pointing guillemet
+ 'frac14' => q|\textonequarter{}|, # 0xBC - vulgar fraction one quarter = fraction one quarter
+ 'frac12' => q|\textonehalf{}|, # 0xBD - vulgar fraction one half = fraction one half
+ 'frac34' => q|\textthreequarters{}|, # 0xBE - vulgar fraction three quarters = fraction three quarters
+ 'iquest' => q|\textquestiondown{}|, # 0xBF - inverted question mark = turned question mark
+ 'Agrave' => q|\`A|, # 0xC0 - latin capital letter A with grave = latin capital letter A grave
+ 'Aacute' => q|\'A|, # 0xC1 - latin capital letter A with acute
+ 'Acirc' => q|\^A|, # 0xC2 - latin capital letter A with circumflex
+ 'Atilde' => q|\~A|, # 0xC3 - latin capital letter A with tilde
+ 'Auml' => q|\"A|, # 0xC4 - latin capital letter A with diaeresis
+ 'Aring' => q|\AA{}|, # 0xC5 - latin capital letter A with ring above = latin capital letter A ring
+ 'AElig' => q|\AE{}|, # 0xC6 - latin capital letter AE = latin capital ligature AE
+ 'Ccedil' => q|\c{C}|, # 0xC7 - latin capital letter C with cedilla
+ 'Egrave' => q|\`E|, # 0xC8 - latin capital letter E with grave
+ 'Eacute' => q|\'E|, # 0xC9 - latin capital letter E with acute
+ 'Ecirc' => q|\^E|, # 0xCA - latin capital letter E with circumflex
+ 'Euml' => q|\"E|, # 0xCB - latin capital letter E with diaeresis
+ 'Igrave' => q|\`I|, # 0xCC - latin capital letter I with grave
+ 'Iacute' => q|\'I|, # 0xCD - latin capital letter I with acute
+ 'Icirc' => q|\^I|, # 0xCE - latin capital letter I with circumflex
+ 'Iuml' => q|\"I|, # 0xCF - latin capital letter I with diaeresis
+ 'ETH' => q|\DH{}|, # 0xD0 - latin capital letter ETH
+ 'Ntilde' => q|\~N|, # 0xD1 - latin capital letter N with tilde
+ 'Ograve' => q|\`O|, # 0xD2 - latin capital letter O with grave
+ 'Oacute' => q|\'O|, # 0xD3 - latin capital letter O with acute
+ 'Ocirc' => q|\^O|, # 0xD4 - latin capital letter O with circumflex
+ 'Otilde' => q|\~O|, # 0xD5 - latin capital letter O with tilde
+ 'Ouml' => q|\"O|, # 0xD6 - latin capital letter O with diaeresis
+ 'times' => q|\texttimes{}|, # 0xD7 - multiplication sign
+ 'Oslash' => q|\O{}|, # 0xD8 - latin capital letter O with stroke = latin capital letter O slash
+ 'Ugrave' => q|\`U|, # 0xD9 - latin capital letter U with grave
+ 'Uacute' => q|\'U|, # 0xDA - latin capital letter U with acute
+ 'Ucirc' => q|\^U|, # 0xDB - latin capital letter U with circumflex
+ 'Uuml' => q|\"U|, # 0xDC - latin capital letter U with diaeresis
+ 'Yacute' => q|\'Y|, # 0xDD - latin capital letter Y with acute
+ 'THORN' => q|\TH{}|, # 0xDE - latin capital letter THORN
+ 'szlig' => q|\ss{}|, # 0xDF - latin small letter sharp s = ess-zed
+ 'agrave' => q|\`a|, # 0xE0 - latin small letter a with grave = latin small letter a grave
+ 'aacute' => q|\'a|, # 0xE1 - latin small letter a with acute
+ 'acirc' => q|\^a|, # 0xE2 - latin small letter a with circumflex
+ 'atilde' => q|\~a|, # 0xE3 - latin small letter a with tilde
+ 'auml' => q|\"a|, # 0xE4 - latin small letter a with diaeresis
+ 'aring' => q|\aa{}|, # 0xE5 - latin small letter a with ring above = latin small letter a ring
+ 'aelig' => q|\ae{}|, # 0xE6 - latin small letter ae = latin small ligature ae
+ 'ccedil' => q|\c{c}|, # 0xE7 - latin small letter c with cedilla
+ 'egrave' => q|\`e|, # 0xE8 - latin small letter e with grave
+ 'eacute' => q|\'e|, # 0xE9 - latin small letter e with acute
+ 'ecirc' => q|\^e|, # 0xEA - latin small letter e with circumflex
+ 'euml' => q|\"e|, # 0xEB - latin small letter e with diaeresis
+ 'igrave' => q|\`i|, # 0xEC - latin small letter i with grave
+ 'iacute' => q|\'i|, # 0xED - latin small letter i with acute
+ 'icirc' => q|\^i|, # 0xEE - latin small letter i with circumflex
+ 'iuml' => q|\"i|, # 0xEF - latin small letter i with diaeresis
+ 'eth' => q|\dh{}|, # 0xF0 - latin small letter eth
+ 'ntilde' => q|\~n|, # 0xF1 - latin small letter n with tilde
+ 'ograve' => q|\`o|, # 0xF2 - latin small letter o with grave
+ 'oacute' => q|\'o|, # 0xF3 - latin small letter o with acute
+ 'ocirc' => q|\^o|, # 0xF4 - latin small letter o with circumflex
+ 'otilde' => q|\~o|, # 0xF5 - latin small letter o with tilde
+ 'ouml' => q|\"o|, # 0xF6 - latin small letter o with diaeresis
+ 'divide' => q|\textdiv{}|, # 0xF7 - division sign
+ 'oslash' => q|\o{}|, # 0xF8 - latin small letter o with stroke, = latin small letter o slash
+ 'ugrave' => q|\`u|, # 0xF9 - latin small letter u with grave
+ 'uacute' => q|\'u|, # 0xFA - latin small letter u with acute
+ 'ucirc' => q|\^u|, # 0xFB - latin small letter u with circumflex
+ 'uuml' => q|\"u|, # 0xFC - latin small letter u with diaeresis
+ 'yacute' => q|\'y|, # 0xFD - latin small letter y with acute
+ 'thorn' => q|\th{}|, # 0xFE - latin small letter thorn
+ 'yuml' => q|\"y|, # 0xFF - latin small letter y with diaeresis
+
+ # Latin Extended-B
+ 'fnof' => q|\textflorin{}|, # latin small f with hook = function = florin
+
+ # Greek
+ 'Alpha' => q|$\mathrm{A}$|, # greek capital letter alpha
+ 'Beta' => q|$\mathrm{B}$|, # greek capital letter beta
+ 'Gamma' => q|$\Gamma$|, # greek capital letter gamma
+ 'Delta' => q|$\Delta$|, # greek capital letter delta
+ 'Epsilon' => q|$\mathrm{E}$|, # greek capital letter epsilon
+ 'Zeta' => q|$\mathrm{Z}$|, # greek capital letter zeta
+ 'Eta' => q|$\mathrm{H}$|, # greek capital letter eta
+ 'Theta' => q|$\Theta$|, # greek capital letter theta
+ 'Iota' => q|$\mathrm{I}$|, # greek capital letter iota
+ 'Kappa' => q|$\mathrm{K}$|, # greek capital letter kappa
+ 'Lambda' => q|$\Lambda$|, # greek capital letter lambda
+ 'Mu' => q|$\mathrm{M}$|, # greek capital letter mu
+ 'Nu' => q|$\mathrm{N}$|, # greek capital letter nu
+ 'Xi' => q|$\Xi$|, # greek capital letter xi
+ 'Omicron' => q|$\mathrm{O}$|, # greek capital letter omicron
+ 'Pi' => q|$\Pi$|, # greek capital letter pi
+ 'Rho' => q|$\mathrm{R}$|, # greek capital letter rho
+ 'Sigma' => q|$\Sigma$|, # greek capital letter sigma
+ 'Tau' => q|$\mathrm{T}$|, # greek capital letter tau
+ 'Upsilon' => q|$\Upsilon$|, # greek capital letter upsilon
+ 'Phi' => q|$\Phi$|, # greek capital letter phi
+ 'Chi' => q|$\mathrm{X}$|, # greek capital letter chi
+ 'Psi' => q|$\Psi$|, # greek capital letter psi
+ 'Omega' => q|$\Omega$|, # greek capital letter omega
+
+ 'alpha' => q|$\alpha$|, # greek small letter alpha
+ 'beta' => q|$\beta$|, # greek small letter beta
+ 'gamma' => q|$\gamma$|, # greek small letter gamma
+ 'delta' => q|$\delta$|, # greek small letter delta
+ 'epsilon' => q|$\epsilon$|, # greek small letter epsilon
+ 'zeta' => q|$\zeta$|, # greek small letter zeta
+ 'eta' => q|$\eta$|, # greek small letter eta
+ 'theta' => q|$\theta$|, # greek small letter theta
+ 'iota' => q|$\iota$|, # greek small letter iota
+ 'kappa' => q|$\kappa$|, # greek small letter kappa
+ 'lambda' => q|$\lambda$|, # greek small letter lambda
+ 'mu' => q|$\mu$|, # greek small letter mu
+ 'nu' => q|$\nu$|, # greek small letter nu
+ 'xi' => q|$\xi$|, # greek small letter xi
+ 'omicron' => q|$o$|, # greek small letter omicron
+ 'pi' => q|$\pi$|, # greek small letter pi
+ 'rho' => q|$\rho$|, # greek small letter rho
+# 'sigmaf' => q||, # greek small letter final sigma
+ 'sigma' => q|$\sigma$|, # greek small letter sigma
+ 'tau' => q|$\tau$|, # greek small letter tau
+ 'upsilon' => q|$\upsilon$|, # greek small letter upsilon
+ 'phi' => q|$\phi$|, # greek small letter phi
+ 'chi' => q|$\chi$|, # greek small letter chi
+ 'psi' => q|$\psi$|, # greek small letter psi
+ 'omega' => q|$\omega$|, # greek small letter omega
+# 'thetasym' => q||, # greek small letter theta symbol
+# 'upsih' => q||, # greek upsilon with hook symbol
+# 'piv' => q||, # greek pi symbol
+
+ # General Punctuation
+ 'bull' => q|\textbullet{}|, # bullet = black small circle
+ # bullet is NOT the same as bullet operator
+ 'hellip' => q|\textellipsis{}|, # horizontal ellipsis = three dot leader
+ 'prime' => q|\textquotesingle{}|, # prime = minutes = feet
+ 'Prime' => q|\textquotedbl{}|, # double prime = seconds = inches
+ 'oline' => q|\textasciimacron{}|, # overline = spacing overscore
+ 'frasl' => q|\textfractionsolidus{}|, # fraction slash
+
+ # Letterlike Symbols
+ 'weierp' => q|$\wp$|, # script capital P = power set = Weierstrass p
+ 'image' => q|$\Re$|, # blackletter capital I = imaginary part
+ 'real' => q|$\Im$|, # blackletter capital R = real part symbol
+ 'trade' => q|\texttrademark{}|, # trade mark sign
+# 'alefsym' => q||, # alef symbol = first transfinite cardinal
+ # alef symbol is NOT the same as hebrew letter alef, although the same
+ # glyph could be used to depict both characters
+
+ # Arrows
+ 'larr' => q|\textleftarrow{}|, # leftwards arrow
+ 'uarr' => q|\textuparrow{}|, # upwards arrow
+ 'rarr' => q|\textrightarrow{}|, # rightwards arrow
+ 'darr' => q|\textdownarrow{}|, # downwards arrow
+ 'harr' => q|$\leftrightarrow$|, # left right arrow
+# 'crarr' => q||, # downwards arrow with corner leftwards = carriage return
+ 'lArr' => q|$\Leftarrow$|, # leftwards double arrow
+ # ISO 10646 does not say that lArr is the same as the 'is implied by'
+ # arrow but also does not have any other character for that function. So
+ # lArr can be used for 'is implied by' as ISOtech suggests
+ 'uArr' => q|$\Uparrow$|, # upwards double arrow
+ 'rArr' => q|$\Rightarrow$|, # rightwards double arrow
+ # ISO 10646 does not say this is the 'implies' character but does not
+ # have another character with this function so ? rArr can be used for
+ # 'implies' as ISOtech suggests
+ 'dArr' => q|$\Downarrow$|, # downwards double arrow
+ 'hArr' => q|$\Leftrightarrow$|, # left right double arrow
+
+ # Mathematical Operators.
+ # Some of these require the `amssymb' package.
+ 'forall' => q|$\forall$|, # for all
+ 'part' => q|$\partial$|, # partial differential
+ 'exist' => q|$\exists$|, # there exists
+ 'empty' => q|$\emptyset$|, # empty set = null set = diameter
+ 'nabla' => q|$\nabla$|, # nabla = backward difference
+ 'isin' => q|$\in$|, # element of
+ 'notin' => q|$\notin$|, # not an element of
+ 'ni' => q|$\ni$|, # contains as member
+ 'prod' => q|$\prod$|, # n-ary product = product sign
+ # prod is NOT the same character as 'greek capital letter pi' though the
+ # same glyph might be used for both
+ 'sum' => q|$\sum$|, # n-ary sumation
+ # sum is NOT the same character as 'greek capital letter sigma' though
+ # the same glyph might be used for both
+ 'minus' => q|$-$|, # minus sign
+ 'lowast' => q|$\ast$|, # asterisk operator
+ 'radic' => q|$\surd$|, # square root = radical sign
+ 'prop' => q|$\propto$|, # proportional to
+ 'infin' => q|$\infty$|, # infinity
+ 'ang' => q|$\angle$|, # angle
+ 'and' => q|$\wedge$|, # logical and = wedge
+ 'or' => q|$\vee$|, # logical or = vee
+ 'cap' => q|$\cap$|, # intersection = cap
+ 'cup' => q|$\cup$|, # union = cup
+ 'int' => q|$\int$|, # integral
+ 'there4' => q|$\therefore$|, # therefore
+ 'sim' => q|$\sim$|, # tilde operator = varies with = similar to
+ # tilde operator is NOT the same character as the tilde
+ 'cong' => q|$\cong$|, # approximately equal to
+ 'asymp' => q|$\asymp$|, # almost equal to = asymptotic to
+ 'ne' => q|$\neq$|, # not equal to
+ 'equiv' => q|$\equiv$|, # identical to
+ 'le' => q|$\leq$|, # less-than or equal to
+ 'ge' => q|$\geq$|, # greater-than or equal to
+ 'sub' => q|$\subset$|, # subset of
+ 'sup' => q|$\supset$|, # superset of
+ # note that nsup, 'not a superset of' is not covered by the Symbol font
+ # encoding and is not included.
+ 'nsub' => q|$\not\subset$|, # not a subset of
+ 'sube' => q|$\subseteq$|, # subset of or equal to
+ 'supe' => q|$\supseteq$|, # superset of or equal to
+ 'oplus' => q|$\oplus$|, # circled plus = direct sum
+ 'otimes' => q|$\otimes$|, # circled times = vector product
+ 'perp' => q|$\perp$|, # up tack = orthogonal to = perpendicular
+ 'sdot' => q|$\cdot$|, # dot operator
+ # dot operator is NOT the same character as middle dot
+
+ # Miscellaneous Technical
+ 'lceil' => q|$\lceil$|, # left ceiling = apl upstile
+ 'rceil' => q|$\rceil$|, # right ceiling
+ 'lfloor' => q|$\lfloor$|, # left floor = apl downstile
+ 'rfloor' => q|$\rfloor$|, # right floor
+ 'lang' => q|$\langle$|, # left-pointing angle bracket = bra
+ # lang is NOT the same character as 'less than' or 'single left-pointing
+ # angle quotation mark'
+ 'rang' => q|$\rangle$|, # right-pointing angle bracket = ket
+ # rang is NOT the same character as 'greater than' or 'single
+ # right-pointing angle quotation mark'
+
+ # Geometric Shapes
+ 'loz' => q|$\lozenge$|, # lozenge
+
+ # Miscellaneous Symbols
+ 'spades' => q|$\spadesuit$|, # black spade suit
+ 'clubs' => q|$\clubsuit$|, # black club suit = shamrock
+ 'hearts' => q|$\heartsuit$|, # black heart suit = valentine
+ 'diams' => q|$\diamondsuit$|, # black diamond suit
+
+ # C0 Controls and Basic Latin
+ 'quot' => q|"|, # quotation mark = APL quote ["]
+ 'amp' => q|\&|, # ampersand
+ 'lt' => q|<|, # less-than sign
+ 'gt' => q|>|, # greater-than sign
+ 'OElig' => q|\OE{}|, # latin capital ligature OE
+ 'oelig' => q|\oe{}|, # latin small ligature oe
+ 'Scaron' => q|\v{S}|, # latin capital letter S with caron
+ 'scaron' => q|\v{s}|, # latin small letter s with caron
+ 'Yuml' => q|\"Y|, # latin capital letter Y with diaeresis
+ 'circ' => q|\textasciicircum{}|, # modifier letter circumflex accent
+ 'tilde' => q|\textasciitilde{}|, # small tilde
+ 'ensp' => q|\phantom{n}|, # en space
+ 'emsp' => q|\hspace{1em}|, # em space
+ 'thinsp' => q|\,|, # thin space
+ 'zwnj' => q|{}|, # zero width non-joiner
+# 'zwj' => q||, # zero width joiner
+# 'lrm' => q||, # left-to-right mark
+# 'rlm' => q||, # right-to-left mark
+ 'ndash' => q|--|, # en dash
+ 'mdash' => q|---|, # em dash
+ 'lsquo' => q|\textquoteleft{}|, # left single quotation mark
+ 'rsquo' => q|\textquoteright{}|, # right single quotation mark
+ 'sbquo' => q|\quotesinglbase{}|, # single low-9 quotation mark
+ 'ldquo' => q|\textquotedblleft{}|, # left double quotation mark
+ 'rdquo' => q|\textquotedblright{}|, # right double quotation mark
+ 'bdquo' => q|\quotedblbase{}|, # double low-9 quotation mark
+ 'dagger' => q|\textdagger{}|, # dagger
+ 'Dagger' => q|\textdaggerdbl{}|, # double dagger
+ 'permil' => q|\textperthousand{}|, # per mille sign
+ 'lsaquo' => q|\guilsinglleft{}|, # single left-pointing angle quotation mark
+ 'rsaquo' => q|\guilsinglright{}|, # single right-pointing angle quotation mark
+ 'euro' => q|\texteuro{}|, # euro sign
+);
+
+=head1 OBJECT METHODS
+
+The following methods are provided in this module. Methods inherited
+from C<Pod::Select> are not described in the public interface.
+
+=over 4
+
+=begin __PRIVATE__
+
+=item C<initialize>
+
+Initialise the object. This method is subclassed from C<Pod::Parser>.
+The base class method is invoked. This method defines the default
+behaviour of the object unless overridden by supplying arguments to
+the constructor.
+
+Internal settings are defaulted as well as the public instance data.
+Internal hash values are accessed directly (rather than through
+a method) and start with an underscore.
+
+This method should not be invoked by the user directly.
+
+=end __PRIVATE__
+
+=cut
+
+
+
+# - An array for nested lists
+
+# Arguments have already been read by this point
+
+sub initialize {
+ my $self = shift;
+
+ # print Dumper($self);
+
+ # Internals
+ $self->{_Lists} = []; # For nested lists
+ $self->{_suppress_all_para} = 0; # For =begin blocks
+ $self->{_dont_modify_any_para}=0; # For =begin blocks
+ $self->{_CURRENT_HEAD1} = ''; # Name of current HEAD1 section
+
+ # Options - only initialise if not already set
+
+ # Cause the '=head1 NAME' field to be treated specially
+ # The contents of the NAME paragraph will be converted
+ # to a section title. All subsequent =head1 will be converted
+ # to =head2 and down. Will not affect =head1's prior to NAME
+ # Assumes: 'Module - purpose' format
+ # Also creates a purpose field
+ # The name is used for Labeling of the subsequent subsections
+ $self->{ReplaceNAMEwithSection} = 0
+ unless exists $self->{ReplaceNAMEwithSection};
+ $self->{AddPreamble} = 1 # make full latex document
+ unless exists $self->{AddPreamble};
+ $self->{StartWithNewPage} = 0 # Start new page for pod section
+ unless exists $self->{StartWithNewPage};
+ $self->{TableOfContents} = 0 # Add table of contents
+ unless exists $self->{TableOfContents}; # only relevent if AddPreamble=1
+ $self->{AddPostamble} = 1 # Add closing latex code at end
+ unless exists $self->{AddPostamble}; # effectively end{document} and index
+ $self->{MakeIndex} = 1 # Add index (only relevant AddPostamble
+ unless exists $self->{MakeIndex}; # and AddPreamble)
+
+ $self->{UniqueLabels} = 1 # Use label unique for each pod
+ unless exists $self->{UniqueLabels}; # either based on the filename
+ # or supplied
+
+ # Control the level of =head1. default is \section
+ #
+ $self->{Head1Level} = 1 # Offset in latex sections
+ unless exists $self->{Head1Level}; # 0 is chapter, 2 is subsection
+
+ # Control at which level numbering of sections is turned off
+ # ie subsection becomes subsection*
+ # The numbering is relative to the latex sectioning commands
+ # and is independent of Pod heading level
+ # default is to number \section but not \subsection
+ $self->{LevelNoNum} = 2
+ unless exists $self->{LevelNoNum};
+
+ # Label to be used as prefix to all internal section names
+ # If not defined will attempt to derive it from the filename
+ # This can not happen when running parse_from_filehandle though
+ # hence the ability to set the label externally
+ # The label could then be Pod::Parser_DESCRIPTION or somesuch
+
+ $self->{Label} = undef # label to be used as prefix
+ unless exists $self->{Label}; # to all internal section names
+
+ # These allow the caller to add arbritrary latex code to
+ # start and end of document. AddPreamble and AddPostamble are ignored
+ # if these are set.
+ # Also MakeIndex and TableOfContents are also ignored.
+ $self->{UserPreamble} = undef # User supplied start (AddPreamble =1)
+ unless exists $self->{Label};
+ $self->{UserPostamble} = undef # Use supplied end (AddPostamble=1)
+ unless exists $self->{Label};
+
+ # Run base initialize
+ $self->SUPER::initialize;
+
+}
+
+=back
+
+=head2 Data Accessors
+
+The following methods are provided for accessing instance data. These
+methods should be used for accessing configuration parameters rather
+than assuming the object is a hash.
+
+Default values can be supplied by using these names as keys to a hash
+of arguments when using the C<new()> constructor.
+
+=over 4
+
+=item B<AddPreamble>
+
+Logical to control whether a C<latex> preamble is to be written.
+If true, a valid C<latex> preamble is written before the pod data is written.
+This is similar to:
+
+ \documentclass{article}
+ \usepackage[T1]{fontenc}
+ \usepackage{textcomp}
+ \begin{document}
+
+but will be more complicated if table of contents and indexing are required.
+Can be used to set or retrieve the current value.
+
+ $add = $parser->AddPreamble();
+ $parser->AddPreamble(1);
+
+If used in conjunction with C<AddPostamble> a full latex document will
+be written that could be immediately processed by C<latex>.
+
+For some pod escapes it may be necessary to include the amsmath
+package. This is not yet added to the preamble automaatically.
+
+=cut
+
+sub AddPreamble {
+ my $self = shift;
+ if (@_) {
+ $self->{AddPreamble} = shift;
+ }
+ return $self->{AddPreamble};
+}
+
+=item B<AddPostamble>
+
+Logical to control whether a standard C<latex> ending is written to the output
+file after the document has been processed.
+In its simplest form this is simply:
+
+ \end{document}
+
+but can be more complicated if a index is required.
+Can be used to set or retrieve the current value.
+
+ $add = $parser->AddPostamble();
+ $parser->AddPostamble(1);
+
+If used in conjunction with C<AddPreaamble> a full latex document will
+be written that could be immediately processed by C<latex>.
+
+=cut
+
+sub AddPostamble {
+ my $self = shift;
+ if (@_) {
+ $self->{AddPostamble} = shift;
+ }
+ return $self->{AddPostamble};
+}
+
+=item B<Head1Level>
+
+The C<latex> sectioning level that should be used to correspond to
+a pod C<=head1> directive. This can be used, for example, to turn
+a C<=head1> into a C<latex> C<subsection>. This should hold a number
+corresponding to the required position in an array containing the
+following elements:
+
+ [0] chapter
+ [1] section
+ [2] subsection
+ [3] subsubsection
+ [4] paragraph
+ [5] subparagraph
+
+Can be used to set or retrieve the current value:
+
+ $parser->Head1Level(2);
+ $sect = $parser->Head1Level;
+
+Setting this number too high can result in sections that may not be reproducible
+in the expected way. For example, setting this to 4 would imply that C<=head3>
+do not have a corresponding C<latex> section (C<=head1> would correspond to
+a C<paragraph>).
+
+A check is made to ensure that the supplied value is an integer in the
+range 0 to 5.
+
+Default is for a value of 1 (i.e. a C<section>).
+
+=cut
+
+sub Head1Level {
+ my $self = shift;
+ if (@_) {
+ my $arg = shift;
+ if ($arg =~ /^\d$/ && $arg <= $#LatexSections) {
+ $self->{Head1Level} = $arg;
+ } else {
+ carp "Head1Level supplied ($arg) must be integer in range 0 to ".$#LatexSections . "- Ignoring\n";
+ }
+ }
+ return $self->{Head1Level};
+}
+
+=item B<Label>
+
+This is the label that is prefixed to all C<latex> label and index
+entries to make them unique. In general, pods have similarly titled
+sections (NAME, DESCRIPTION etc) and a C<latex> label will be multiply
+defined if more than one pod document is to be included in a single
+C<latex> file. To overcome this, this label is prefixed to a label
+whenever a label is required (joined with an underscore) or to an
+index entry (joined by an exclamation mark which is the normal index
+separator). For example, C<\label{text}> becomes C<\label{Label_text}>.
+
+Can be used to set or retrieve the current value:
+
+ $label = $parser->Label;
+ $parser->Label($label);
+
+This label is only used if C<UniqueLabels> is true.
+Its value is set automatically from the C<NAME> field
+if C<ReplaceNAMEwithSection> is true. If this is not the case
+it must be set manually before starting the parse.
+
+Default value is C<undef>.
+
+=cut
+
+sub Label {
+ my $self = shift;
+ if (@_) {
+ $self->{Label} = shift;
+ }
+ return $self->{Label};
+}
+
+=item B<LevelNoNum>
+
+Control the point at which C<latex> section numbering is turned off.
+For example, this can be used to make sure that C<latex> sections
+are numbered but subsections are not.
+
+Can be used to set or retrieve the current value:
+
+ $lev = $parser->LevelNoNum;
+ $parser->LevelNoNum(2);
+
+The argument must be an integer between 0 and 5 and is the same as the
+number described in C<Head1Level> method description. The number has
+nothing to do with the pod heading number, only the C<latex> sectioning.
+
+Default is 2. (i.e. C<latex> subsections are written as C<subsection*>
+but sections are numbered).
+
+=cut
+
+sub LevelNoNum {
+ my $self = shift;
+ if (@_) {
+ $self->{LevelNoNum} = shift;
+ }
+ return $self->{LevelNoNum};
+}
+
+=item B<MakeIndex>
+
+Controls whether C<latex> commands for creating an index are to be inserted
+into the preamble and postamble
+
+ $makeindex = $parser->MakeIndex;
+ $parser->MakeIndex(0);
+
+Irrelevant if both C<AddPreamble> and C<AddPostamble> are false (or equivalently,
+C<UserPreamble> and C<UserPostamble> are set).
+
+Default is for an index to be created.
+
+=cut
+
+sub MakeIndex {
+ my $self = shift;
+ if (@_) {
+ $self->{MakeIndex} = shift;
+ }
+ return $self->{MakeIndex};
+}
+
+=item B<ReplaceNAMEwithSection>
+
+This controls whether the C<NAME> section in the pod is to be translated
+literally or converted to a slightly modified output where the section
+name is the pod name rather than "NAME".
+
+If true, the pod segment
+
+ =head1 NAME
+
+ pod::name - purpose
+
+ =head1 SYNOPSIS
+
+is converted to the C<latex>
+
+ \section{pod::name\label{pod_name}\index{pod::name}}
+
+ Purpose
+
+ \subsection*{SYNOPSIS\label{pod_name_SYNOPSIS}%
+ \index{pod::name!SYNOPSIS}}
+
+(dependent on the value of C<Head1Level> and C<LevelNoNum>). Note that
+subsequent C<head1> directives translate to subsections rather than
+sections and that the labels and index now include the pod name (dependent
+on the value of C<UniqueLabels>).
+
+The C<Label> is set from the pod name regardless of any current value
+of C<Label>.
+
+ $mod = $parser->ReplaceNAMEwithSection;
+ $parser->ReplaceNAMEwithSection(0);
+
+Default is to translate the pod literally.
+
+=cut
+
+sub ReplaceNAMEwithSection {
+ my $self = shift;
+ if (@_) {
+ $self->{ReplaceNAMEwithSection} = shift;
+ }
+ return $self->{ReplaceNAMEwithSection};
+}
+
+=item B<StartWithNewPage>
+
+If true, each pod translation will begin with a C<latex>
+C<\clearpage>.
+
+ $parser->StartWithNewPage(1);
+ $newpage = $parser->StartWithNewPage;
+
+Default is false.
+
+=cut
+
+sub StartWithNewPage {
+ my $self = shift;
+ if (@_) {
+ $self->{StartWithNewPage} = shift;
+ }
+ return $self->{StartWithNewPage};
+}
+
+=item B<TableOfContents>
+
+If true, a table of contents will be created.
+Irrelevant if C<AddPreamble> is false or C<UserPreamble>
+is set.
+
+ $toc = $parser->TableOfContents;
+ $parser->TableOfContents(1);
+
+Default is false.
+
+=cut
+
+sub TableOfContents {
+ my $self = shift;
+ if (@_) {
+ $self->{TableOfContents} = shift;
+ }
+ return $self->{TableOfContents};
+}
+
+=item B<UniqueLabels>
+
+If true, the translator will attempt to make sure that
+each C<latex> label or index entry will be uniquely identified
+by prefixing the contents of C<Label>. This allows
+multiple documents to be combined without clashing
+common labels such as C<DESCRIPTION> and C<SYNOPSIS>
+
+ $parser->UniqueLabels(1);
+ $unq = $parser->UniqueLabels;
+
+Default is true.
+
+=cut
+
+sub UniqueLabels {
+ my $self = shift;
+ if (@_) {
+ $self->{UniqueLabels} = shift;
+ }
+ return $self->{UniqueLabels};
+}
+
+=item B<UserPreamble>
+
+User supplied C<latex> preamble. Added before the pod translation
+data.
+
+If set, the contents will be prepended to the output file before the translated
+data regardless of the value of C<AddPreamble>.
+C<MakeIndex> and C<TableOfContents> will also be ignored.
+
+=cut
+
+sub UserPreamble {
+ my $self = shift;
+ if (@_) {
+ $self->{UserPreamble} = shift;
+ }
+ return $self->{UserPreamble};
+}
+
+=item B<UserPostamble>
+
+User supplied C<latex> postamble. Added after the pod translation
+data.
+
+If set, the contents will be prepended to the output file after the translated
+data regardless of the value of C<AddPostamble>.
+C<MakeIndex> will also be ignored.
+
+=cut
+
+sub UserPostamble {
+ my $self = shift;
+ if (@_) {
+ $self->{UserPostamble} = shift;
+ }
+ return $self->{UserPostamble};
+}
+
+=begin __PRIVATE__
+
+=item B<Lists>
+
+Contains details of the currently active lists.
+ The array contains C<Pod::List> objects. A new C<Pod::List>
+object is created each time a list is encountered and it is
+pushed onto this stack. When the list context ends, it
+is popped from the stack. The array will be empty if no
+lists are active.
+
+Returns array of list information in list context
+Returns array ref in scalar context
+
+=cut
+
+
+
+sub lists {
+ my $self = shift;
+ return @{ $self->{_Lists} } if wantarray();
+ return $self->{_Lists};
+}
+
+=end __PRIVATE__
+
+=back
+
+=begin __PRIVATE__
+
+=head2 Subclassed methods
+
+The following methods override methods provided in the C<Pod::Select>
+base class. See C<Pod::Parser> and C<Pod::Select> for more information
+on what these methods require.
+
+=over 4
+
+=cut
+
+######### END ACCESSORS ###################
+
+# Opening pod
+
+=item B<begin_pod>
+
+Writes the C<latex> preamble if requested. Only writes something
+if AddPreamble is true. Writes a standard header unless a UserPreamble
+is defined.
+
+=cut
+
+sub begin_pod {
+ my $self = shift;
+
+ # Get the pod identification
+ # This should really come from the '=head1 NAME' paragraph
+
+ my $infile = $self->input_file;
+ my $class = ref($self);
+ my $date = gmtime(time);
+
+ # Comment message to say where this came from
+ my $comment = << "__TEX_COMMENT__";
+%% Latex generated from POD in document $infile
+%% Using the perl module $class
+%% Converted on $date
+__TEX_COMMENT__
+
+ # Write the preamble
+ # If the caller has supplied one then we just use that
+
+ my $preamble = '';
+
+ if ($self->AddPreamble) {
+
+ if (defined $self->UserPreamble) {
+
+ $preamble = $self->UserPreamble;
+
+ # Add the description of where this came from
+ $preamble .= "\n$comment\n%% Preamble supplied by user.\n\n";
+
+ } else {
+
+ # Write our own preamble
+
+ # Code to initialise index making
+ # Use an array so that we can prepend comment if required
+ my @makeidx = (
+ '\usepackage{makeidx}',
+ '\makeindex',
+ );
+
+ unless ($self->MakeIndex) {
+ foreach (@makeidx) {
+ $_ = '%% ' . $_;
+ }
+ }
+ my $makeindex = join("\n",@makeidx) . "\n";
+
+ # Table of contents
+ my $tableofcontents = '\tableofcontents';
+
+ $tableofcontents = '%% ' . $tableofcontents
+ unless $self->TableOfContents;
+
+ # Roll our own
+ $preamble = << "__TEX_HEADER__";
+\\documentclass{article}
+\\usepackage[T1]{fontenc}
+\\usepackage{textcomp}
+
+$comment
+
+$makeindex
+
+\\begin{document}
+
+$tableofcontents
+
+__TEX_HEADER__
+
+ }
+ }
+
+ # Write the header (blank if none)
+ $self->_output($preamble);
+
+ # Start on new page if requested
+ $self->_output("\\clearpage\n") if $self->StartWithNewPage;
+
+}
+
+
+=item B<end_pod>
+
+Write the closing C<latex> code. Only writes something if AddPostamble
+is true. Writes a standard header unless a UserPostamble is defined.
+
+=cut
+
+sub end_pod {
+ my $self = shift;
+
+ # End string
+ my $end = '';
+
+ # Use the user version of the postamble if defined
+ if ($self->AddPostamble) {
+
+ if (defined $self->UserPostamble) {
+ $end = $self->UserPostamble;
+
+ } else {
+
+ # Check for index
+ my $makeindex = '\printindex';
+
+ $makeindex = '%% '. $makeindex unless $self->MakeIndex;
+
+ $end = "$makeindex\n\n\\end{document}\n";
+ }
+ }
+
+ $self->_output($end);
+
+}
+
+=item B<command>
+
+Process basic pod commands.
+
+=cut
+
+sub command {
+ my $self = shift;
+ my ($command, $paragraph, $line_num, $parobj) = @_;
+
+ # return if we dont care
+ return if $command eq 'pod';
+
+ # Store a copy of the raw text in case we are in a =for
+ # block and need to preserve the existing latex
+ my $rawpara = $paragraph;
+
+ # Do the latex escapes
+ $paragraph = $self->_replace_special_chars($paragraph);
+
+ # Interpolate pod sequences in paragraph
+ $paragraph = $self->interpolate($paragraph, $line_num);
+ $paragraph =~ s/\s+$//;
+
+ # Replace characters that can only be done after
+ # interpolation of interior sequences
+ $paragraph = $self->_replace_special_chars_late($paragraph);
+
+ # Now run the command
+ if ($command eq 'over') {
+
+ $self->begin_list($paragraph, $line_num);
+
+ } elsif ($command eq 'item') {
+
+ $self->add_item($paragraph, $line_num);
+
+ } elsif ($command eq 'back') {
+
+ $self->end_list($line_num);
+
+ } elsif ($command eq 'head1') {
+
+ # Store the name of the section
+ $self->{_CURRENT_HEAD1} = $paragraph;
+
+ # Print it
+ $self->head(1, $paragraph, $parobj);
+
+ } elsif ($command eq 'head2') {
+
+ $self->head(2, $paragraph, $parobj);
+
+ } elsif ($command eq 'head3') {
+
+ $self->head(3, $paragraph, $parobj);
+
+ } elsif ($command eq 'head4') {
+
+ $self->head(4, $paragraph, $parobj);
+
+ } elsif ($command eq 'head5') {
+
+ $self->head(5, $paragraph, $parobj);
+
+ } elsif ($command eq 'head6') {
+
+ $self->head(6, $paragraph, $parobj);
+
+ } elsif ($command eq 'begin') {
+
+ # pass through if latex
+ if ($paragraph =~ /^latex/i) {
+ # Make sure that subsequent paragraphs are not modfied before printing
+ $self->{_dont_modify_any_para} = 1;
+
+ } else {
+ # Suppress all subsequent paragraphs unless
+ # it is explcitly intended for latex
+ $self->{_suppress_all_para} = 1;
+ }
+
+ } elsif ($command eq 'for') {
+
+ # =for latex
+ # some latex
+
+ # With =for we will get the text for the full paragraph
+ # as well as the format name.
+ # We do not get an additional paragraph later on. The next
+ # paragraph is not governed by the =for
+
+ # The first line contains the format and the rest is the
+ # raw code.
+ my ($format, $chunk) = split(/\n/, $rawpara, 2);
+
+ # If we have got some latex code print it out immediately
+ # unmodified. Else do nothing.
+ if ($format =~ /^latex/i) {
+ # Make sure that next paragraph is not modfied before printing
+ $self->_output( $chunk );
+
+ }
+
+ } elsif ($command eq 'end') {
+
+ # Reset suppression
+ $self->{_suppress_all_para} = 0;
+ $self->{_dont_modify_any_para} = 0;
+
+ } elsif ($command eq 'pod') {
+
+ # Do nothing
+
+ } else {
+ carp "Command $command not recognised at line $line_num\n";
+ }
+
+}
+
+=item B<verbatim>
+
+Verbatim text
+
+=cut
+
+sub verbatim {
+ my $self = shift;
+ my ($paragraph, $line_num, $parobj) = @_;
+
+ # Expand paragraph unless in =begin block
+ if ($self->{_dont_modify_any_para}) {
+ # Just print as is
+ $self->_output($paragraph);
+
+ } else {
+
+ return if $paragraph =~ /^\s+$/;
+
+ # Clean trailing space
+ $paragraph =~ s/\s+$//;
+
+ # Clean tabs. Routine taken from Tabs.pm
+ # by David Muir Sharnoff muir@idiom.com,
+ # slightly modified by hsmyers@sdragons.com 10/22/01
+ my @l = split("\n",$paragraph);
+ foreach (@l) {
+ 1 while s/(^|\n)([^\t\n]*)(\t+)/
+ $1. $2 . (" " x
+ (8 * length($3)
+ - (length($2) % 8)))
+ /sex;
+ }
+ $paragraph = join("\n",@l);
+ # End of change.
+
+
+
+ $self->_output('\begin{verbatim}' . "\n$paragraph\n". '\end{verbatim}'."\n");
+ }
+}
+
+=item B<textblock>
+
+Plain text paragraph.
+
+=cut
+
+sub textblock {
+ my $self = shift;
+ my ($paragraph, $line_num, $parobj) = @_;
+
+ # print Dumper($self);
+
+ # Expand paragraph unless in =begin block
+ if ($self->{_dont_modify_any_para}) {
+ # Just print as is
+ $self->_output($paragraph);
+
+ return;
+ }
+
+
+ # Escape latex special characters
+ $paragraph = $self->_replace_special_chars($paragraph);
+
+ # Interpolate interior sequences
+ my $expansion = $self->interpolate($paragraph, $line_num);
+ $expansion =~ s/\s+$//;
+
+ # Escape special characters that can not be done earlier
+ $expansion = $self->_replace_special_chars_late($expansion);
+
+ # If we are replacing 'head1 NAME' with a section
+ # we need to look in the paragraph and rewrite things
+ # Need to make sure this is called only on the first paragraph
+ # following 'head1 NAME' and not on subsequent paragraphs that may be
+ # present.
+ if ($self->{_CURRENT_HEAD1} =~ /^NAME/i && $self->ReplaceNAMEwithSection()) {
+
+ # Strip white space from start and end
+ $paragraph =~ s/^\s+//;
+ $paragraph =~ s/\s$//;
+
+ # Split the string into 2 parts
+ my ($name, $purpose) = split(/\s+-\s+/, $expansion,2);
+
+ # Now prevent this from triggering until a new head1 NAME is set
+ $self->{_CURRENT_HEAD1} = '_NAME';
+
+ # Might want to clear the Label() before doing this (CHECK)
+
+ # Print the heading
+ $self->head(1, $name, $parobj);
+
+ # Set the labeling in case we want unique names later
+ $self->Label( $self->_create_label( $name, 1 ) );
+
+ # Raise the Head1Level by one so that subsequent =head1 appear
+ # as subsections of the main name section unless we are already
+ # at maximum [Head1Level() could check this itself - CHECK]
+ $self->Head1Level( $self->Head1Level() + 1)
+ unless $self->Head1Level == $#LatexSections;
+
+ # Now write out the new latex paragraph
+ $purpose = ucfirst($purpose);
+ $self->_output("\n\n$purpose\n\n");
+
+ } else {
+ # Just write the output
+ $self->_output("\n\n$expansion\n\n");
+ }
+
+}
+
+=item B<interior_sequence>
+
+Interior sequence expansion
+
+=cut
+
+sub interior_sequence {
+ my $self = shift;
+
+ my ($seq_command, $seq_argument, $pod_seq) = @_;
+
+ if ($seq_command eq 'B') {
+ return "\\textbf{$seq_argument}";
+
+ } elsif ($seq_command eq 'I') {
+ return "\\textit{$seq_argument}";
+
+ } elsif ($seq_command eq 'E') {
+
+ # If it is simply a number
+ if ($seq_argument =~ /^\d+$/) {
+ return chr($seq_argument);
+ # Look up escape in hash table
+ } elsif (exists $HTML_Escapes{$seq_argument}) {
+ return $HTML_Escapes{$seq_argument};
+
+ } else {
+ my ($file, $line) = $pod_seq->file_line();
+ warn "Escape sequence $seq_argument not recognised at line $line of file $file\n";
+ return;
+ }
+
+ } elsif ($seq_command eq 'Z') {
+
+ # Zero width space
+ return '{}';
+
+ } elsif ($seq_command eq 'C') {
+ return "\\texttt{$seq_argument}";
+
+ } elsif ($seq_command eq 'F') {
+ return "\\emph{$seq_argument}";
+
+ } elsif ($seq_command eq 'S') {
+ # non breakable spaces
+ my $nbsp = '~';
+
+ $seq_argument =~ s/\s/$nbsp/g;
+ return $seq_argument;
+
+ } elsif ($seq_command eq 'L') {
+ my $link = new Pod::Hyperlink($seq_argument);
+
+ # undef on failure
+ unless (defined $link) {
+ carp $@;
+ return;
+ }
+
+ # Handle internal links differently
+ my $type = $link->type;
+ my $page = $link->page;
+
+ if ($type eq 'section' && $page eq '') {
+ # Use internal latex reference
+ my $node = $link->node;
+
+ # Convert to a label
+ $node = $self->_create_label($node);
+
+ return "\\S\\ref{$node}";
+
+ } else {
+ # Use default markup for external references
+ # (although Starlink would use \xlabel)
+ my $markup = $link->markup;
+ my ($file, $line) = $pod_seq->file_line();
+
+ return $self->interpolate($link->markup, $line);
+ }
+
+
+
+ } elsif ($seq_command eq 'P') {
+ # Special markup for Pod::Hyperlink
+ # Replace :: with / - but not sure if I want to do this
+ # any more.
+ my $link = $seq_argument;
+ $link =~ s|::|/|g;
+
+ my $ref = "\\emph{$seq_argument}";
+ return $ref;
+
+ } elsif ($seq_command eq 'Q') {
+ # Special markup for Pod::Hyperlink
+ return "\\textsf{$seq_argument}";
+
+ } elsif ($seq_command eq 'X') {
+ # Index entries
+
+ # use \index command
+ # I will let '!' go through for now
+ # not sure how sub categories are handled in X<>
+ my $index = $self->_create_index($seq_argument);
+ return "\\index{$index}\n";
+
+ } else {
+ carp "Unknown sequence $seq_command<$seq_argument>";
+ }
+
+}
+
+=back
+
+=head2 List Methods
+
+Methods used to handle lists.
+
+=over 4
+
+=item B<begin_list>
+
+Called when a new list is found (via the C<over> directive).
+Creates a new C<Pod::List> object and stores it on the
+list stack.
+
+ $parser->begin_list($indent, $line_num);
+
+=cut
+
+sub begin_list {
+ my $self = shift;
+ my $indent = shift;
+ my $line_num = shift;
+
+ # Indicate that a list should be started for the next item
+ # need to do this to work out the type of list
+ push ( @{$self->lists}, new Pod::List(-indent => $indent,
+ -start => $line_num,
+ -file => $self->input_file,
+ )
+ );
+
+}
+
+=item B<end_list>
+
+Called when the end of a list is found (the C<back> directive).
+Pops the C<Pod::List> object off the stack of lists and writes
+the C<latex> code required to close a list.
+
+ $parser->end_list($line_num);
+
+=cut
+
+sub end_list {
+ my $self = shift;
+ my $line_num = shift;
+
+ unless (defined $self->lists->[-1]) {
+ my $file = $self->input_file;
+ warn "No list is active at line $line_num (file=$file). Missing =over?\n";
+ return;
+ }
+
+ # What to write depends on list type
+ my $type = $self->lists->[-1]->type;
+
+ # Dont write anything if the list type is not set
+ # iomplying that a list was created but no entries were
+ # placed in it (eg because of a =begin/=end combination)
+ $self->_output("\\end{$type}\n")
+ if (defined $type && length($type) > 0);
+
+ # Clear list
+ pop(@{ $self->lists});
+
+}
+
+=item B<add_item>
+
+Add items to the list. The first time an item is encountered
+(determined from the state of the current C<Pod::List> object)
+the type of list is determined (ordered, unnumbered or description)
+and the relevant latex code issued.
+
+ $parser->add_item($paragraph, $line_num);
+
+=cut
+
+sub add_item {
+ my $self = shift;
+ my $paragraph = shift;
+ my $line_num = shift;
+
+ unless (defined $self->lists->[-1]) {
+ my $file = $self->input_file;
+ warn "List has already ended by line $line_num of file $file. Missing =over?\n";
+ # Replace special chars
+# $paragraph = $self->_replace_special_chars($paragraph);
+ $self->_output("$paragraph\n\n");
+ return;
+ }
+
+ # If paragraphs printing is turned off via =begin/=end or whatver
+ # simply return immediately
+ return if $self->{_suppress_all_para};
+
+ # Check to see whether we are starting a new lists
+ if (scalar($self->lists->[-1]->item) == 0) {
+
+ # Examine the paragraph to determine what type of list
+ # we have
+ $paragraph =~ s/\s+$//;
+ $paragraph =~ s/^\s+//;
+
+ my $type;
+ if (substr($paragraph, 0,1) eq '*') {
+ $type = 'itemize';
+ } elsif ($paragraph =~ /^\d/) {
+ $type = 'enumerate';
+ } else {
+ $type = 'description';
+ }
+ $self->lists->[-1]->type($type);
+
+ $self->_output("\\begin{$type}\n");
+
+ }
+
+ my $type = $self->lists->[-1]->type;
+
+ if ($type eq 'description') {
+ # Handle long items - long items do not wrap
+ # If the string is longer than 40 characters we split
+ # it into a real item header and some bold text.
+ my $maxlen = 40;
+ my ($hunk1, $hunk2) = $self->_split_delimited( $paragraph, $maxlen );
+
+ # Print the first hunk
+ $self->_output("\n\\item[{$hunk1}] ");
+
+ # and the second hunk if it is defined
+ if ($hunk2) {
+ $self->_output("\\textbf{$hunk2}");
+ } else {
+ # Not there so make sure we have a new line
+ $self->_output("\\mbox{}");
+ }
+
+ } else {
+ # If the item was '* Something' or '\d+ something' we still need to write
+ # out the something. Also allow 1) and 1.
+ my $extra_info = $paragraph;
+ $extra_info =~ s/^(\*|\d+[\.\)]?)\s*//;
+ $self->_output("\n\\item $extra_info");
+ }
+
+ # Store the item name in the object. Required so that
+ # we can tell if the list is new or not
+ $self->lists->[-1]->item($paragraph);
+
+}
+
+=back
+
+=head2 Methods for headings
+
+=over 4
+
+=item B<head>
+
+Print a heading of the required level.
+
+ $parser->head($level, $paragraph, $parobj);
+
+The first argument is the pod heading level. The second argument
+is the contents of the heading. The 3rd argument is a Pod::Paragraph
+object so that the line number can be extracted.
+
+=cut
+
+sub head {
+ my $self = shift;
+ my $num = shift;
+ my $paragraph = shift;
+ my $parobj = shift;
+
+ # If we are replace 'head1 NAME' with a section
+ # we return immediately if we get it
+ return
+ if ($self->{_CURRENT_HEAD1} =~ /^NAME/i && $self->ReplaceNAMEwithSection());
+
+ # Create a label
+ my $label = $self->_create_label($paragraph);
+
+ # Create an index entry
+ my $index = $self->_create_index($paragraph);
+
+ # Work out position in the above array taking into account
+ # that =head1 is equivalent to $self->Head1Level
+
+ my $level = $self->Head1Level() - 1 + $num;
+
+ # Warn if heading to large
+ if ($num > $#LatexSections) {
+ my $line = $parobj->file_line;
+ my $file = $self->input_file;
+ warn "Heading level too large ($level) for LaTeX at line $line of file $file\n";
+ $level = $#LatexSections;
+ }
+
+ # Check to see whether section should be unnumbered
+ my $star = ($level >= $self->LevelNoNum ? '*' : '');
+
+ # Section
+ $self->_output("\\" .$LatexSections[$level] .$star ."{$paragraph\\label{".$label ."}\\index{".$index."}}\n");
+
+}
+
+
+=back
+
+=end __PRIVATE__
+
+=begin __PRIVATE__
+
+=head2 Internal methods
+
+Internal routines are described in this section. They do not form part of the
+public interface. All private methods start with an underscore.
+
+=over 4
+
+=item B<_output>
+
+Output text to the output filehandle. This method must be always be called
+to output parsed text.
+
+ $parser->_output($text);
+
+Does not write anything if a =begin is active that should be
+ignored.
+
+=cut
+
+sub _output {
+ my $self = shift;
+ my $text = shift;
+
+ print { $self->output_handle } $text
+ unless $self->{_suppress_all_para};
+
+}
+
+
+=item B<_replace_special_chars>
+
+Subroutine to replace characters that are special in C<latex>
+with the escaped forms
+
+ $escaped = $parser->_replace_special_chars($paragraph);
+
+Need to call this routine before interior_sequences are munged but not
+if verbatim. It must be called before interpolation of interior
+sequences so that curly brackets and special latex characters inserted
+during interpolation are not themselves escaped. This means that < and
+> can not be modified here since the text still contains interior
+sequences.
+
+Special characters and the C<latex> equivalents are:
+
+ } \}
+ { \{
+ _ \_
+ $ \$
+ % \%
+ & \&
+ \ $\backslash$
+ ^ \^{}
+ ~ \~{}
+ # \#
+
+=cut
+
+sub _replace_special_chars {
+ my $self = shift;
+ my $paragraph = shift;
+
+ # Replace a \ with $\backslash$
+ # This is made more complicated because the dollars will be escaped
+ # by the subsequent replacement. Easiest to add \backslash
+ # now and then add the dollars
+ $paragraph =~ s/\\/\\backslash/g;
+
+ # Must be done after escape of \ since this command adds latex escapes
+ # Replace characters that can be escaped
+ $paragraph =~ s/([\$\#&%_{}])/\\$1/g;
+
+ # Replace ^ characters with \^{} so that $^F works okay
+ $paragraph =~ s/(\^)/\\$1\{\}/g;
+
+ # Replace tilde (~) with \texttt{\~{}}
+ $paragraph =~ s/~/\\texttt\{\\~\{\}\}/g;
+
+ # Now add the dollars around each \backslash
+ $paragraph =~ s/(\\backslash)/\$$1\$/g;
+ return $paragraph;
+}
+
+=item B<_replace_special_chars_late>
+
+Replace special characters that can not be replaced before interior
+sequence interpolation. See C<_replace_special_chars> for a routine
+to replace special characters prior to interpolation of interior
+sequences.
+
+Does the following transformation:
+
+ < $<$
+ > $>$
+ | $|$
+
+
+=cut
+
+sub _replace_special_chars_late {
+ my $self = shift;
+ my $paragraph = shift;
+
+ # < and >
+ $paragraph =~ s/(<|>)/\$$1\$/g;
+
+ # Replace | with $|$
+ $paragraph =~ s'\|'$|$'g;
+
+
+ return $paragraph;
+}
+
+
+=item B<_create_label>
+
+Return a string that can be used as an internal reference
+in a C<latex> document (i.e. accepted by the C<\label> command)
+
+ $label = $parser->_create_label($string)
+
+If UniqueLabels is true returns a label prefixed by Label()
+This can be suppressed with an optional second argument.
+
+ $label = $parser->_create_label($string, $suppress);
+
+If a second argument is supplied (of any value including undef)
+the Label() is never prefixed. This means that this routine can
+be called to create a Label() without prefixing a previous setting.
+
+=cut
+
+sub _create_label {
+ my $self = shift;
+ my $paragraph = shift;
+ my $suppress = (@_ ? 1 : 0 );
+
+ # Remove latex commands
+ $paragraph = $self->_clean_latex_commands($paragraph);
+
+ # Remove non alphanumerics from the label and replace with underscores
+ # want to protect '-' though so use negated character classes
+ $paragraph =~ s/[^-:\w]/_/g;
+
+ # Multiple underscores will look unsightly so remove repeats
+ # This will also have the advantage of tidying up the end and
+ # start of string
+ $paragraph =~ s/_+/_/g;
+
+ # If required need to make sure that the label is unique
+ # since it is possible to have multiple pods in a single
+ # document
+ if (!$suppress && $self->UniqueLabels() && defined $self->Label) {
+ $paragraph = $self->Label() .'_'. $paragraph;
+ }
+
+ return $paragraph;
+}
+
+
+=item B<_create_index>
+
+Similar to C<_create_label> except an index entry is created.
+If C<UniqueLabels> is true, the index entry is prefixed by
+the current C<Label> and an exclamation mark.
+
+ $ind = $parser->_create_index($paragraph);
+
+An exclamation mark is used by C<makeindex> to generate
+sub-entries in an index.
+
+=cut
+
+sub _create_index {
+ my $self = shift;
+ my $paragraph = shift;
+ my $suppress = (@_ ? 1 : 0 );
+
+ # Remove latex commands
+ $paragraph = $self->_clean_latex_commands($paragraph);
+
+ # If required need to make sure that the index entry is unique
+ # since it is possible to have multiple pods in a single
+ # document
+ if (!$suppress && $self->UniqueLabels() && defined $self->Label) {
+ $paragraph = $self->Label() .'!'. $paragraph;
+ }
+
+ # Need to replace _ with space
+ $paragraph =~ s/_/ /g;
+
+ return $paragraph;
+
+}
+
+=item B<_clean_latex_commands>
+
+Removes latex commands from text. The latex command is assumed to be of the
+form C<\command{ text }>. "C<text>" is retained
+
+ $clean = $parser->_clean_latex_commands($text);
+
+=cut
+
+sub _clean_latex_commands {
+ my $self = shift;
+ my $paragraph = shift;
+
+ # Remove latex commands of the form \text{ }
+ # and replace with the contents of the { }
+ # need to make this non-greedy so that it can handle
+ # "\text{a} and \text2{b}"
+ # without converting it to
+ # "a} and \text2{b"
+ # This match will still get into trouble if \} is present
+ # This is not vital since the subsequent replacement of non-alphanumeric
+ # characters will tidy it up anyway
+ $paragraph =~ s/\\\w+{(.*?)}/$1/g;
+
+ return $paragraph
+}
+
+=item B<_split_delimited>
+
+Split the supplied string into two parts at approximately the
+specified word boundary. Special care is made to make sure that it
+does not split in the middle of some curly brackets.
+
+e.g. "this text is \textbf{very bold}" would not be split into
+"this text is \textbf{very" and " bold".
+
+ ($hunk1, $hunk2) = $self->_split_delimited( $para, $length);
+
+The length indicates the maximum length of hunk1.
+
+=cut
+
+# initially Supplied by hsmyers@sdragons.com
+# 10/25/01, utility to split \hbox
+# busting lines. Reformatted by TimJ to match module style.
+sub _split_delimited {
+ my $self = shift;
+ my $input = shift;
+ my $limit = shift;
+
+ # Return immediately if already small
+ return ($input, '') if length($input) < $limit;
+
+ my @output;
+ my $s = '';
+ my $t = '';
+ my $depth = 0;
+ my $token;
+
+ $input =~ s/\n/ /gm;
+ $input .= ' ';
+ foreach ( split ( //, $input ) ) {
+ $token .= $_;
+ if (/\{/) {
+ $depth++;
+ } elsif ( /}/ ) {
+ $depth--;
+ } elsif ( / / and $depth == 0) {
+ push @output, $token if ( $token and $token ne ' ' );
+ $token = '';
+ }
+ }
+
+ foreach (@output) {
+ if (length($s) < $limit) {
+ $s .= $_;
+ } else {
+ $t .= $_;
+ }
+ }
+
+ # Tidy up
+ $s =~ s/\s+$//;
+ $t =~ s/\s+$//;
+ return ($s,$t);
+}
+
+=back
+
+=end __PRIVATE__
+
+=head1 NOTES
+
+Compatible with C<latex2e> only. Can not be used with C<latex> v2.09
+or earlier.
+
+A subclass of C<Pod::Select> so that specific pod sections can be
+converted to C<latex> by using the C<select> method.
+
+Some HTML escapes are missing and many have not been tested.
+
+=head1 SEE ALSO
+
+L<Pod::Parser>, L<Pod::Select>, L<pod2latex>
+
+=head1 AUTHORS
+
+Tim Jenness E<lt>tjenness@cpan.orgE<gt>
+
+Bug fixes and improvements have been received from: Simon Cozens
+E<lt>simon@cozens.netE<gt>, Mark A. Hershberger
+E<lt>mah@everybody.orgE<gt>, Marcel Grunauer
+E<lt>marcel@codewerk.comE<gt>, Hugh S Myers
+E<lt>hsmyers@sdragons.comE<gt>, Peter J Acklam
+E<lt>jacklam@math.uio.noE<gt>, Sudhi Herle E<lt>sudhi@herle.netE<gt>,
+Ariel Scolnicov E<lt>ariels@compugen.co.ilE<gt>,
+Adriano Rodrigues Ferreira E<lt>ferreira@triang.com.brE<gt> and
+R. de Vries E<lt>r.de.vries@dutchspace.nlE<gt>.
+
+
+=head1 COPYRIGHT
+
+Copyright (C) 2000-2004 Tim Jenness. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=begin __PRIVATE__
+
+=head1 REVISION
+
+$Id: LaTeX.pm,v 1.19 2004/12/30 01:40:44 timj Exp $
+
+=end __PRIVATE__
+
+=cut
+
+1;
diff --git a/Master/tlpkg/tlperl/lib/Pod/Man.pm b/Master/tlpkg/tlperl/lib/Pod/Man.pm
new file mode 100644
index 00000000000..693e4c46896
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Man.pm
@@ -0,0 +1,1413 @@
+# Pod::Man -- Convert POD data to formatted *roff input.
+# $Id: Man.pm,v 1.37 2003/03/30 22:34:11 eagle Exp $
+#
+# Copyright 1999, 2000, 2001, 2002, 2003 by Russ Allbery <rra@stanford.edu>
+#
+# This program is free software; you may redistribute it and/or modify it
+# under the same terms as Perl itself.
+#
+# 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.
+#
+# Perl core hackers, please note that this module is also separately
+# maintained outside of the Perl core as part of the podlators. Please send
+# me any patches at the address above in addition to sending them to the
+# standard Perl mailing lists.
+
+##############################################################################
+# Modules and declarations
+##############################################################################
+
+package Pod::Man;
+
+require 5.005;
+
+use Carp qw(carp croak);
+use Pod::ParseLink qw(parselink);
+use Pod::Parser ();
+
+use strict;
+use subs qw(makespace);
+use vars qw(@ISA %ESCAPES $PREAMBLE $VERSION);
+
+@ISA = qw(Pod::Parser);
+
+# Don't use the CVS revision as the version, since this module is also in Perl
+# core and too many things could munge CVS magic revision strings. This
+# number should ideally be the same as the CVS revision in podlators, however.
+$VERSION = 1.37;
+
+
+##############################################################################
+# Preamble and *roff output tables
+##############################################################################
+
+# The following is the static preamble which starts all *roff output we
+# generate. It's completely 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@. $PREAMBLE
+# should therefore be run through s/\@CFONT\@/<font>/g before output.
+$PREAMBLE = <<'----END OF PREAMBLE----';
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.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" ''
+'br\}
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. nr % 0
+. rr F
+.\}
+.\"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.hy 0
+.if n .na
+.\"
+.\" 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
+
+# This table is taken nearly verbatim 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. Note that some of these are quoted
+# with double quotes since they contain embedded single quotes, so use \\
+# uniformly for backslash for readability.
+%ESCAPES = (
+ 'amp' => '&', # ampersand
+ 'apos' => "'", # apostrophe
+ 'lt' => '<', # left chevron, less-than
+ 'gt' => '>', # right chevron, greater-than
+ 'quot' => '"', # double quote
+ 'sol' => '/', # solidus (forward slash)
+ 'verbar' => '|', # vertical bar
+
+ 'Aacute' => "A\\*'", # capital A, acute accent
+ 'aacute' => "a\\*'", # small a, acute accent
+ 'Acirc' => 'A\\*^', # capital A, circumflex accent
+ 'acirc' => 'a\\*^', # small a, circumflex accent
+ 'AElig' => '\*(AE', # capital AE diphthong (ligature)
+ 'aelig' => '\*(ae', # small ae diphthong (ligature)
+ 'Agrave' => "A\\*`", # capital A, grave accent
+ 'agrave' => "A\\*`", # small a, grave accent
+ 'Aring' => 'A\\*o', # capital A, ring
+ 'aring' => 'a\\*o', # small a, ring
+ 'Atilde' => 'A\\*~', # capital A, tilde
+ 'atilde' => 'a\\*~', # small a, tilde
+ 'Auml' => 'A\\*:', # capital A, dieresis or umlaut mark
+ 'auml' => 'a\\*:', # small a, dieresis or umlaut mark
+ 'Ccedil' => 'C\\*,', # capital C, cedilla
+ 'ccedil' => 'c\\*,', # small c, cedilla
+ 'Eacute' => "E\\*'", # capital E, acute accent
+ 'eacute' => "e\\*'", # small e, acute accent
+ 'Ecirc' => 'E\\*^', # capital E, circumflex accent
+ 'ecirc' => 'e\\*^', # small e, circumflex accent
+ 'Egrave' => 'E\\*`', # capital E, grave accent
+ 'egrave' => 'e\\*`', # small e, grave accent
+ 'ETH' => '\\*(D-', # capital Eth, Icelandic
+ 'eth' => '\\*(d-', # small eth, Icelandic
+ 'Euml' => 'E\\*:', # capital E, dieresis or umlaut mark
+ 'euml' => 'e\\*:', # small e, dieresis or umlaut mark
+ 'Iacute' => "I\\*'", # capital I, acute accent
+ 'iacute' => "i\\*'", # small i, acute accent
+ 'Icirc' => 'I\\*^', # capital I, circumflex accent
+ 'icirc' => 'i\\*^', # small i, circumflex accent
+ 'Igrave' => 'I\\*`', # capital I, grave accent
+ 'igrave' => 'i\\*`', # small i, grave accent
+ 'Iuml' => 'I\\*:', # capital I, dieresis or umlaut mark
+ 'iuml' => 'i\\*:', # small i, dieresis or umlaut mark
+ 'Ntilde' => 'N\*~', # capital N, tilde
+ 'ntilde' => 'n\*~', # small n, tilde
+ 'Oacute' => "O\\*'", # capital O, acute accent
+ 'oacute' => "o\\*'", # small o, acute accent
+ 'Ocirc' => 'O\\*^', # capital O, circumflex accent
+ 'ocirc' => 'o\\*^', # small o, circumflex accent
+ 'Ograve' => 'O\\*`', # capital O, grave accent
+ 'ograve' => 'o\\*`', # small o, grave accent
+ 'Oslash' => 'O\\*/', # capital O, slash
+ 'oslash' => 'o\\*/', # small o, slash
+ 'Otilde' => 'O\\*~', # capital O, tilde
+ 'otilde' => 'o\\*~', # small o, tilde
+ 'Ouml' => 'O\\*:', # capital O, dieresis or umlaut mark
+ 'ouml' => 'o\\*:', # small o, dieresis or umlaut mark
+ 'szlig' => '\*8', # small sharp s, German (sz ligature)
+ 'THORN' => '\\*(Th', # capital THORN, Icelandic
+ 'thorn' => '\\*(th', # small thorn, Icelandic
+ 'Uacute' => "U\\*'", # capital U, acute accent
+ 'uacute' => "u\\*'", # small u, acute accent
+ 'Ucirc' => 'U\\*^', # capital U, circumflex accent
+ 'ucirc' => 'u\\*^', # small u, circumflex accent
+ 'Ugrave' => 'U\\*`', # capital U, grave accent
+ 'ugrave' => 'u\\*`', # small u, grave accent
+ 'Uuml' => 'U\\*:', # capital U, dieresis or umlaut mark
+ 'uuml' => 'u\\*:', # small u, dieresis or umlaut mark
+ 'Yacute' => "Y\\*'", # capital Y, acute accent
+ 'yacute' => "y\\*'", # small y, acute accent
+ 'yuml' => 'y\\*:', # small y, dieresis or umlaut mark
+
+ 'nbsp' => '\\ ', # non-breaking space
+ 'shy' => '', # soft (discretionary) hyphen
+);
+
+
+##############################################################################
+# Static helper functions
+##############################################################################
+
+# 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 {
+ local $_ = shift;
+ s/^([.\'\\])/\\&$1/mg;
+ $_;
+}
+
+# Translate a font string into an escape.
+sub toescape { (length ($_[0]) > 1 ? '\f(' : '\f') . $_[0] }
+
+
+##############################################################################
+# Initialization
+##############################################################################
+
+# Initialize the object. Here, we also process any additional options passed
+# to the constructor or set up defaults if none were given. center is the
+# centered title, release is the version number, and date is the date for the
+# documentation. Note that we can't know what file name we're processing due
+# to the architecture of Pod::Parser, so that *has* to either be passed to the
+# constructor or set separately with Pod::Man::name().
+sub initialize {
+ my $self = shift;
+
+ # Figure out the fixed-width font. If user-supplied, make sure that they
+ # are the right length.
+ for (qw/fixed fixedbold fixeditalic fixedbolditalic/) {
+ if (defined $$self{$_}) {
+ if (length ($$self{$_}) < 1 || length ($$self{$_}) > 2) {
+ croak qq(roff font should be 1 or 2 chars,)
+ . qq( not "$$self{$_}");
+ }
+ } else {
+ $$self{$_} = '';
+ }
+ }
+
+ # Set the default fonts. We can't be sure what fixed bold-italic is going
+ # to be called, 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})};
+
+ # Extra stuff for page titles.
+ $$self{center} = 'User Contributed Perl Documentation'
+ unless defined $$self{center};
+ $$self{indent} = 4 unless defined $$self{indent};
+
+ # 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.
+ if (!defined $$self{release}) {
+ my @version = ($] =~ /^(\d+)\.(\d{3})(\d{0,3})$/);
+ $version[2] ||= 0;
+ $version[2] *= 10 ** (3 - length $version[2]);
+ for (@version) { $_ += 0 }
+ $$self{release} = 'perl v' . join ('.', @version);
+ }
+
+ # Double quotes in things that will be quoted.
+ for (qw/center date release/) {
+ $$self{$_} =~ s/\"/\"\"/g if $$self{$_};
+ }
+
+ # Figure out what quotes we'll be using for C<> text.
+ $$self{quotes} ||= '"';
+ if ($$self{quotes} eq 'none') {
+ $$self{LQUOTE} = $$self{RQUOTE} = '';
+ } elsif (length ($$self{quotes}) == 1) {
+ $$self{LQUOTE} = $$self{RQUOTE} = $$self{quotes};
+ } elsif ($$self{quotes} =~ /^(.)(.)$/
+ || $$self{quotes} =~ /^(..)(..)$/) {
+ $$self{LQUOTE} = $1;
+ $$self{RQUOTE} = $2;
+ } else {
+ croak qq(Invalid quote specification "$$self{quotes}");
+ }
+
+ # 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/\"/\"\"/;
+
+ $self->SUPER::initialize;
+}
+
+# For each document we process, output the preamble first.
+sub begin_pod {
+ my $self = shift;
+
+ # Try to figure out the name and section from the file name.
+ my $section = $$self{section} || 1;
+ my $name = $$self{name};
+ if (!defined $name) {
+ $name = $self->input_file;
+ $section = 3 if (!$$self{section} && $name =~ /\.pm\z/i);
+ $name =~ s/\.p(od|[lm])\z//i;
+ if ($section !~ /^3/) {
+ require File::Basename;
+ $name = uc File::Basename::basename ($name);
+ } else {
+ # Assume that 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
+ # everything up to the first of:
+ #
+ # */lib/*perl*/ standard or site_perl module
+ # */*perl*/lib/ from -Dprefix=/opt/perl
+ # */*perl*/ random module hierarchy
+ #
+ # which works. Also strip off a leading site or site_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.
+ require File::Spec;
+ my ($volume, $dirs, $file) = File::Spec->splitpath ($name);
+ my @dirs = File::Spec->splitdir ($dirs);
+ my $cut = 0;
+ my $i;
+ for ($i = 0; $i < scalar @dirs; $i++) {
+ if ($dirs[$i] eq 'lib' && $dirs[$i + 1] =~ /perl/) {
+ $cut = $i + 2;
+ last;
+ } elsif ($dirs[$i] =~ /perl/) {
+ $cut = $i + 1;
+ $cut++ if $dirs[$i + 1] eq 'lib';
+ last;
+ }
+ }
+ if ($cut > 0) {
+ splice (@dirs, 0, $cut);
+ shift @dirs if ($dirs[0] =~ /^site(_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);
+ }
+ }
+
+ # If $name contains spaces, quote it; this mostly comes up in the case of
+ # input from stdin.
+ $name = '"' . $name . '"' if ($name =~ /\s/);
+
+ # Modification date header. Try to use the modification time of our
+ # input.
+ if (!defined $$self{date}) {
+ my $time = (stat $self->input_file)[9] || time;
+ my ($day, $month, $year) = (localtime $time)[3,4,5];
+ $month++;
+ $year += 1900;
+ $$self{date} = sprintf ('%4d-%02d-%02d', $year, $month, $day);
+ }
+
+ # Now, 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.
+ local $_ = $PREAMBLE;
+ s/\@CFONT\@/$$self{fixed}/;
+ s/\@LQUOTE\@/$$self{LQUOTE}/;
+ s/\@RQUOTE\@/$$self{RQUOTE}/;
+ chomp $_;
+ my $pversion = $Pod::Parser::VERSION;
+ print { $self->output_handle } <<"----END OF HEADER----";
+.\\" Automatically generated by Pod::Man v$VERSION, Pod::Parser v$pversion
+.\\"
+.\\" Standard preamble:
+.\\" ========================================================================
+$_
+.\\" ========================================================================
+.\\"
+.IX Title "$name $section"
+.TH $name $section "$$self{date}" "$$self{release}" "$$self{center}"
+----END OF HEADER----
+
+ # Initialize a few per-file 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.
+}
+
+
+##############################################################################
+# Core overrides
+##############################################################################
+
+# Called for each command paragraph. Gets the command, the associated
+# paragraph, the line number, and a Pod::Paragraph object. Just dispatches
+# the command to a method named the same as the command. =cut is handled
+# internally by Pod::Parser.
+sub command {
+ my $self = shift;
+ my $command = shift;
+ return if $command eq 'pod';
+ return if ($$self{EXCLUDE} && $command ne 'end');
+ if ($self->can ('cmd_' . $command)) {
+ $command = 'cmd_' . $command;
+ $self->$command (@_);
+ } else {
+ my ($text, $line, $paragraph) = @_;
+ my $file;
+ ($file, $line) = $paragraph->file_line;
+ $text =~ s/\n+\z//;
+ $text = " $text" if ($text =~ /^\S/);
+ warn qq($file:$line: Unknown command paragraph "=$command$text"\n);
+ return;
+ }
+}
+
+# Called for a verbatim paragraph. Gets the paragraph, the line number, and a
+# Pod::Paragraph object. Rofficate backslashes, untabify, put a zero-width
+# character at the beginning of each line to protect against commands, and
+# wrap in .Vb/.Ve.
+sub verbatim {
+ my $self = shift;
+ return if $$self{EXCLUDE};
+ local $_ = shift;
+ return if /^\s+$/;
+ s/\s+$/\n/;
+ my $lines = tr/\n/\n/;
+ 1 while s/^(.*?)(\t+)/$1 . ' ' x (length ($2) * 8 - length ($1) % 8)/me;
+ s/\\/\\e/g;
+ s/-/\\-/g;
+ s/'/\\(aq/g;
+ s/^(\s*\S)/'\&' . $1/gme;
+ $self->makespace;
+ $self->output (".Vb $lines\n$_.Ve\n");
+ $$self{NEEDSPACE} = 1;
+}
+
+# Called for a regular text block. Gets the paragraph, the line number, and a
+# Pod::Paragraph object. Perform interpolation and output the results.
+sub textblock {
+ my $self = shift;
+ return if $$self{EXCLUDE};
+ $self->output ($_[0]), return if $$self{VERBATIM};
+
+ # Parse the tree. collapse knows about references to scalars as well as
+ # scalars and does the right thing with them. Tidy up any trailing
+ # whitespace.
+ my $text = shift;
+ $text = $self->parse ($text, @_);
+ $text =~ s/\n\s*$/\n/;
+
+ # 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;
+ }
+ $self->output (protect $self->textmapfonts ($text));
+ $self->outindex;
+ $$self{NEEDSPACE} = 1;
+}
+
+# Called for a formatting code. Takes a Pod::InteriorSequence object and
+# returns a reference to a scalar. This scalar is the final formatted text.
+# It's returned as a reference to an array so that other formatting codes
+# above us know that the text has already been processed.
+sub sequence {
+ my ($self, $seq) = @_;
+ my $command = $seq->cmd_name;
+
+ # We have to defer processing of the inside of an L<> formatting code. If
+ # this code is nested inside an L<> code, return the literal raw text of
+ # it.
+ my $parent = $seq->nested;
+ while (defined $parent) {
+ return $seq->raw_text if ($parent->cmd_name eq 'L');
+ $parent = $parent->nested;
+ }
+
+ # Zero-width characters.
+ return [ '\&' ] if ($command eq 'Z');
+
+ # C<>, L<>, X<>, and E<> don't apply guesswork to their contents. C<>
+ # needs some additional special handling.
+ my $literal = ($command =~ /^[CELX]$/);
+ local $_ = $self->collapse ($seq->parse_tree, $literal, $command eq 'C');
+
+ # Handle E<> escapes. Numeric escapes that match one of the supported ISO
+ # 8859-1 characters don't work at present.
+ if ($command eq 'E') {
+ if (/^\d+$/) {
+ return [ chr ($_) ];
+ } elsif (exists $ESCAPES{$_}) {
+ return [ $ESCAPES{$_} ];
+ } else {
+ my ($file, $line) = $seq->file_line;
+ warn "$file:$line: Unknown escape E<$_>\n";
+ return [ "E<$_>" ];
+ }
+ }
+
+ # For all the other codes, empty content produces no output.
+ return '' if $_ eq '';
+
+ # Handle simple formatting codes.
+ if ($command eq 'B') {
+ return [ '\f(BS' . $_ . '\f(BE' ];
+ } elsif ($command eq 'F' || $command eq 'I') {
+ return [ '\f(IS' . $_ . '\f(IE' ];
+ } elsif ($command eq 'C') {
+ return [ $self->quote_literal ($_) ];
+ }
+
+ # Handle links.
+ if ($command eq 'L') {
+ my ($text, $type) = (parselink ($_))[1,4];
+ return '' unless $text;
+ my ($file, $line) = $seq->file_line;
+ $text = $self->parse ($text, $line);
+ $text = '<' . $text . '>' if $type eq 'url';
+ return [ $text ];
+ }
+
+ # Whitespace protection replaces whitespace with "\ ".
+ if ($command eq 'S') {
+ s/\s+/\\ /g;
+ return [ $_ ];
+ }
+
+ # Add an index entry to the list of ones waiting to be output.
+ if ($command eq 'X') {
+ push (@{ $$self{INDEX} }, $_);
+ return '';
+ }
+
+ # Anything else is unknown.
+ my ($file, $line) = $seq->file_line;
+ warn "$file:$line: Unknown formatting code $command<$_>\n";
+}
+
+
+##############################################################################
+# Command paragraphs
+##############################################################################
+
+# All command paragraphs take the paragraph and the line number.
+
+# 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 \s1 and \s-1. Maintain IN_NAME as
+# appropriate, but don't leave it set while calling parse() so as to not
+# override guesswork on section headings after NAME.
+sub cmd_head1 {
+ my $self = shift;
+ $$self{IN_NAME} = 0;
+ local $_ = $self->parse (@_);
+ s/\s+$//;
+ s/\\s-?\d//g;
+ s/\s*\n\s*/ /g;
+ if ($$self{ITEMS} > 1) {
+ $$self{ITEMS} = 0;
+ $self->output (".PD\n");
+ }
+ $self->output ($self->switchquotes ('.SH', $self->mapfonts ($_)));
+ $self->outindex (($_ eq 'NAME') ? () : ('Header', $_));
+ $$self{NEEDSPACE} = 0;
+ $$self{IN_NAME} = ($_ eq 'NAME');
+}
+
+# Second level heading.
+sub cmd_head2 {
+ my $self = shift;
+ local $_ = $self->parse (@_);
+ s/\s+$//;
+ s/\s*\n\s*/ /g;
+ if ($$self{ITEMS} > 1) {
+ $$self{ITEMS} = 0;
+ $self->output (".PD\n");
+ }
+ $self->output ($self->switchquotes ('.Sh', $self->mapfonts ($_)));
+ $self->outindex ('Subsection', $_);
+ $$self{NEEDSPACE} = 0;
+}
+
+# Third level heading.
+sub cmd_head3 {
+ my $self = shift;
+ local $_ = $self->parse (@_);
+ s/\s+$//;
+ s/\s*\n\s*/ /g;
+ if ($$self{ITEMS} > 1) {
+ $$self{ITEMS} = 0;
+ $self->output (".PD\n");
+ }
+ $self->makespace;
+ $self->output ($self->textmapfonts ('\f(IS' . $_ . '\f(IE') . "\n");
+ $self->outindex ('Subsection', $_);
+ $$self{NEEDSPACE} = 1;
+}
+
+# Fourth level heading.
+sub cmd_head4 {
+ my $self = shift;
+ local $_ = $self->parse (@_);
+ s/\s+$//;
+ s/\s*\n\s*/ /g;
+ if ($$self{ITEMS} > 1) {
+ $$self{ITEMS} = 0;
+ $self->output (".PD\n");
+ }
+ $self->makespace;
+ $self->output ($self->textmapfonts ($_) . "\n");
+ $self->outindex ('Subsection', $_);
+ $$self{NEEDSPACE} = 1;
+}
+
+# Start a list. For indents after the first, wrap the outside indent in .RS
+# so that hanging paragraph tags will be correct.
+sub cmd_over {
+ my $self = shift;
+ local $_ = shift;
+ unless (/^[-+]?\d+\s+$/) { $_ = $$self{indent} }
+ if (@{ $$self{SHIFTS} } < @{ $$self{INDENTS} }) {
+ $self->output (".RS $$self{INDENT}\n");
+ push (@{ $$self{SHIFTS} }, $$self{INDENT});
+ }
+ push (@{ $$self{INDENTS} }, $$self{INDENT});
+ push (@{ $$self{ITEMTYPES} }, 'unknown');
+ $$self{INDENT} = ($_ + 0);
+ $$self{SHIFTWAIT} = 1;
+}
+
+# End a list. If we've closed an embedded indent, we've mangled the hanging
+# paragraph indent, so temporarily replace it with .RS and set WEIRDINDENT.
+# We'll close that .RS at the next =back or =item.
+sub cmd_back {
+ my $self = shift;
+ $$self{INDENT} = pop @{ $$self{INDENTS} };
+ if (defined $$self{INDENT}) {
+ pop @{ $$self{ITEMTYPES} };
+ } else {
+ my ($file, $line, $paragraph) = @_;
+ ($file, $line) = $paragraph->file_line;
+ warn "$file:$line: Unmatched =back\n";
+ $$self{INDENT} = 0;
+ }
+ if (@{ $$self{SHIFTS} } > @{ $$self{INDENTS} }) {
+ $self->output (".RE\n");
+ pop @{ $$self{SHIFTS} };
+ }
+ if (@{ $$self{INDENTS} } > 0) {
+ $self->output (".RE\n");
+ $self->output (".RS $$self{INDENT}\n");
+ }
+ $$self{NEEDSPACE} = 1;
+ $$self{SHIFTWAIT} = 0;
+}
+
+# An individual list item. Emit an index entry for anything that's
+# interesting, but don't emit index entries for things like bullets and
+# numbers. rofficate bullets too while we're at it (so for nice output, use *
+# for your lists rather than o or . or - or some other thing). Newlines in an
+# item title are turned into spaces since *roff can't handle them embedded.
+sub cmd_item {
+ my $self = shift;
+ local $_ = $self->parse (@_);
+ s/\s+$//;
+ s/\s*\n\s*/ /g;
+ my $index;
+ if (/\w/ && !/^\w[.\)]\s*$/) {
+ $index = $_;
+ $index =~ s/^\s*[-*+o.]?(?:\s+|\Z)//;
+ }
+ $_ = '*' unless length ($_) > 0;
+ my $type = $$self{ITEMTYPES}[0];
+ unless (defined $type) {
+ my ($file, $line, $paragraph) = @_;
+ ($file, $line) = $paragraph->file_line;
+ $type = 'unknown';
+ }
+ if ($type eq 'unknown') {
+ $type = /^\*\s*\Z/ ? 'bullet' : 'text';
+ $$self{ITEMTYPES}[0] = $type if $$self{ITEMTYPES}[0];
+ }
+ s/^\*\s*\Z/\\\(bu/ if $type eq 'bullet';
+ if (@{ $$self{SHIFTS} } == @{ $$self{INDENTS} }) {
+ $self->output (".RE\n");
+ pop @{ $$self{SHIFTS} };
+ }
+ $_ = $self->textmapfonts ($_);
+ $self->output (".PD 0\n") if ($$self{ITEMS} == 1);
+ $self->output ($self->switchquotes ('.IP', $_, $$self{INDENT}));
+ $self->outindex ($index ? ('Item', $index) : ());
+ $$self{NEEDSPACE} = 0;
+ $$self{ITEMS}++;
+ $$self{SHIFTWAIT} = 0;
+}
+
+# Begin a block for a particular translator. Setting VERBATIM triggers
+# special handling in textblock().
+sub cmd_begin {
+ my $self = shift;
+ local $_ = shift;
+ my ($kind) = /^(\S+)/ or return;
+ if ($kind eq 'man' || $kind eq 'roff') {
+ $$self{VERBATIM} = 1;
+ } else {
+ $$self{EXCLUDE} = 1;
+ }
+}
+
+# End a block for a particular translator. We assume that all =begin/=end
+# pairs are properly closed.
+sub cmd_end {
+ my $self = shift;
+ $$self{EXCLUDE} = 0;
+ $$self{VERBATIM} = 0;
+}
+
+# One paragraph for a particular translator. Ignore it unless it's intended
+# for man or roff, in which case we output it verbatim.
+sub cmd_for {
+ my $self = shift;
+ local $_ = shift;
+ return unless s/^(?:man|roff)\b[ \t]*\n?//;
+ $self->output ($_);
+}
+
+
+##############################################################################
+# Escaping and fontification
+##############################################################################
+
+# At this point, we'll have embedded font codes of the form \f(<font>[SE]
+# where <font> is one of B, I, or F. Turn those into the right font start or
+# end codes. The old pod2man didn't get B<someI<thing> else> right; after I<>
+# it switched back to normal text rather than bold. We take care of this by
+# using variables as a combined pointer to our current font sequence, and set
+# each to the number of current nestings of start tags for that font. Use
+# them as a vector to look up what font sequence to use.
+#
+# \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 = shift;
+ local $_ = shift;
+
+ my ($fixed, $bold, $italic) = (0, 0, 0);
+ my %magic = (F => \$fixed, B => \$bold, I => \$italic);
+ my $last = '\fR';
+ 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;
+ $_;
+}
+
+# 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 = shift;
+ local $_ = shift;
+
+ my ($fixed, $bold, $italic) = (0, 0, 0);
+ my %magic = (F => \$fixed, B => \$bold, I => \$italic);
+ s { \\f\((.)(.) } {
+ ${ $magic{$1} } += ($2 eq 'S') ? 1 : -1;
+ $$self{FONTS}{($fixed && 1) . ($bold && 1) . ($italic && 1)};
+ }gxe;
+ $_;
+}
+
+
+##############################################################################
+# *roff-specific parsing and magic
+##############################################################################
+
+# Called instead of parse_text, calls parse_text with the right flags.
+sub parse {
+ my $self = shift;
+ $self->parse_text ({ -expand_seq => 'sequence',
+ -expand_ptree => 'collapse' }, @_);
+}
+
+# Takes a parse tree, a flag saying whether or not to treat it as literal text
+# (not call guesswork on it), and a flag saying whether or not to clean some
+# things up for *roff, and returns the concatenation of all of the text
+# strings in that parse tree. If the literal flag isn't true, guesswork()
+# will be called on all plain scalars in the parse tree. Otherwise, if
+# collapse is being called on a C<> code, $cleanup should be set to true and
+# some additional cleanup will be done. Assumes that everything in the parse
+# tree is either a scalar or a reference to a scalar.
+sub collapse {
+ my ($self, $ptree, $literal, $cleanup) = @_;
+
+ # If we're processing the NAME section, don't do normal guesswork. This
+ # is because NAME lines are often extracted by utilities like catman that
+ # require plain text and don't understand *roff markup. We still need to
+ # escape backslashes and hyphens for *roff (and catman expects \- instead
+ # of -).
+ if ($$self{IN_NAME}) {
+ $literal = 1;
+ $cleanup = 1;
+ }
+
+ # Do the collapse of the parse tree as described above.
+ return join ('', map {
+ if (ref $_) {
+ join ('', @$_);
+ } elsif ($literal) {
+ if ($cleanup) {
+ s/\\/\\e/g;
+ s/-/\\-/g;
+ s/__/_\\|_/g;
+ }
+ $_;
+ } else {
+ $self->guesswork ($_);
+ }
+ } $ptree->children);
+}
+
+# Takes a text block to perform guesswork on; this is guaranteed not to
+# contain any formatting codes. Returns the text block with remapping done.
+sub guesswork {
+ my $self = shift;
+ local $_ = shift;
+
+ # rofficate backslashes.
+ s/\\/\\e/g;
+
+ # Ensure double underbars have a tiny space between them.
+ s/__/_\\|_/g;
+
+ # Leave hyphens only if they're part of regular words and there is only
+ # one dash at a time. Leave a dash after the first character as a regular
+ # non-breaking dash, but don't let it mark the rest of the word invalid
+ # for hyphenation.
+ s/-/\\-/g;
+ 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.
+ s{ (\s) \\-\\- (\s) } { $1 . '\*(--' . $2 }egx;
+ s{ (\b[a-zA-Z]+) \\-\\- (\s|\Z|[a-zA-Z]+\b) } { $1 . '\*(--' . $2 }egx;
+
+ # Make all caps a little smaller. Be careful here, since we don't want to
+ # make @ARGV into small caps, nor do we want to fix the MIME in
+ # MIME-Version, since it looks weird with the full-height V.
+ s{
+ ( ^ | [\s\(\"\'\`\[\{<>] )
+ ( [A-Z] [A-Z] (?: [/A-Z+:\d_\$&] | \\- )* )
+ (?= [\s>\}\]\(\)\'\".?!,;] | \\*\(-- | $ )
+ } { $1 . '\s-1' . $2 . '\s0' }egx;
+
+ # Italize functions in the form func().
+ s{
+ ( \b | \\s-1 )
+ (
+ [A-Za-z_] ([:\w]|\\s-?[01])+ \(\)
+ )
+ } { $1 . '\f(IS' . $2 . '\f(IE' }egx;
+
+ # func(n) is a reference to a manual page. Make it \fIfunc\fR\|(n).
+ s{
+ ( \b | \\s-1 )
+ ( [A-Za-z_] (?:[.:\w]|\\-|\\s-?[01])+ )
+ (
+ \( \d [a-z]* \)
+ )
+ } { $1 . '\f(IS' . $2 . '\f(IE\|' . $3 }egx;
+
+ # Convert simple Perl variable references to a fixed-width font.
+ s{
+ ( \s+ )
+ ( [\$\@%] [\w:]+ )
+ (?! \( )
+ } { $1 . '\f(FS' . $2 . '\f(FE'}egx;
+
+ # Fix up double quotes.
+ s{ \" ([^\"]+) \" } { '\*(L"' . $1 . '\*(R"' }egx;
+
+ # Make C++ into \*(C+, which is a squinched version.
+ s{ \b C\+\+ } {\\*\(C+}gx;
+
+ # All done.
+ $_;
+}
+
+# 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 = '(?: \[.*\] | \{.*\} )?';
+
+ # 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
+ | \` .* \' # `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 '\f(FS' . $_ . '\f(FE';
+
+ # If we didn't return, go ahead and quote the text.
+ return '\f(FS\*(C`' . $_ . "\\*(C'\\f(FE";
+}
+
+
+##############################################################################
+# Output formatting
+##############################################################################
+
+# Make vertical whitespace.
+sub makespace {
+ my $self = shift;
+ $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);
+ $$self{INDEX} = [];
+ my @output;
+ if (@entries) {
+ push (@output, [ 'Xref', join (' ', @entries) ]);
+ }
+ if ($section) {
+ $index =~ s/\\-/-/g;
+ $index =~ s/\\(?:s-?\d|.\(..|.)//g;
+ push (@output, [ $section, $index ]);
+ }
+ for (@output) {
+ my ($type, $entry) = @$_;
+ $entry =~ s/\"/\"\"/g;
+ $entry =~ s/\\/\\e/g;
+ $self->output (".IX $type " . '"' . $entry . '"' . "\n");
+ }
+}
+
+# Output text to the output device.
+sub output { print { $_[0]->output_handle } $_[1] }
+
+# 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 = shift;
+ my $command = shift;
+ local $_ = shift;
+ my $extra = shift;
+ 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 (/\"/ || /$fixedpat/) {
+ s/\"/\"\"/g;
+ my $nroff = $_;
+ my $troff = $_;
+ $troff =~ s/\"\"([^\"]*)\"\"/\`\`$1\'\'/g;
+ if ($c_is_quote && /\\\*\(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.
+ $nroff =~ s/\Q$$self{FONTS}{100}\E(.*)\\f[PR]/$1/g;
+ $nroff =~ s/\Q$$self{FONTS}{101}\E(.*)\\f([PR])/\\fI$1\\f$2/g;
+ $nroff =~ s/\Q$$self{FONTS}{110}\E(.*)\\f([PR])/\\fB$1\\f$2/g;
+ $nroff =~ s/\Q$$self{FONTS}{111}\E(.*)\\f([PR])/\\f\(BI$1\\f$2/g;
+
+ # Now finally output the command. Only bother with .ie if the nroff
+ # and troff output isn't the same.
+ if ($nroff ne $troff) {
+ return ".ie n $command $nroff\n.el $command $troff\n";
+ } else {
+ return "$command $nroff\n";
+ }
+ } else {
+ $_ = qq("$_") . ($extra ? " $extra" : '');
+ return "$command $_\n";
+ }
+}
+
+##############################################################################
+# Module return value and documentation
+##############################################################################
+
+1;
+__END__
+
+=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_from_filehandle;
+
+ # 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<nroff(1)>, normally via L<man(1)>, or printing using L<troff(1)>.
+It is conventionally invoked using the driver script B<pod2man>, but it can
+also be used directly.
+
+As a derived class from Pod::Parser, Pod::Man supports the same methods and
+interfaces. See L<Pod::Parser> for all the details; briefly, one creates a
+new parser with C<< Pod::Man->new() >> and then calls either
+parse_from_filehandle() or parse_from_file().
+
+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
+STDIN for input).
+
+Pod::Man assumes that your *roff formatters have a fixed-width font named
+CW. If yours is called something else (like CR), use the C<fixed> 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 underbars, makes ALLCAPS a teeny bit
+smaller in B<troff>, 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 to use instead of "User Contributed Perl
+Documentation".
+
+=item date
+
+Sets the left-hand footer. By default, the modification date of the input
+file will be used, or the current date if stat() can't find that file (the
+case if the input is from STDIN), and the date will be formatted as
+YYYY-MM-DD.
+
+=item fixed
+
+The fixed-width font to use for vertabim text and code. Defaults to CW.
+Some systems may want CR instead. Only matters for B<troff> output.
+
+=item fixedbold
+
+Bold version of the fixed-width font. Defaults to CB. Only matters for
+B<troff> 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 CI. Only matters for B<troff> 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 CB. Some systems
+(such as Solaris) have this font available as CX. Only matters for B<troff>
+output.
+
+=item name
+
+Set the name of the manual page. 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<Pod::Man>. This option, if given, overrides any automatic
+determination of the name.
+
+=item quotes
+
+Sets the quote marks used to surround CE<lt>> text. If the value is a
+single character, it is used as both the left and right quote; if it is two
+characters, the first character is used as the left quote and the second as
+the right quoted; and if it is four characters, the first two are used as
+the left quote and the second two as the right quote.
+
+This may also be set to the special value C<none>, in which case no quote
+marks are added around CE<lt>> text (but the font is still changed for troff
+output).
+
+=item release
+
+Set the centered footer. By default, this is the version of Perl you run
+Pod::Man under. Note that some system an macro sets assume that the
+centered footer will be a modification date and will prepend something like
+"Last modified: "; if this is the case, you may want to set C<release> to
+the last modified date and C<date> 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 .pm in which case
+section 3 will be selected.
+
+=back
+
+The standard Pod::Parser method parse_from_filehandle() takes up to two
+arguments, the first being the file handle to read POD from and the second
+being the file handle to write the formatted output to. The first defaults
+to STDIN if not given, and the second defaults to STDOUT. The method
+parse_from_file() is almost identical, except that its two arguments are the
+input and output disk files instead. See L<Pod::Parser> for the specific
+details.
+
+=head1 DIAGNOSTICS
+
+=over 4
+
+=item roff font should be 1 or 2 chars, not "%s"
+
+(F) You specified a *roff font (using C<fixed>, C<fixedbold>, 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<nroff> and B<troff> don't either).
+
+=item Invalid link %s
+
+(W) The POD source contained a C<LE<lt>E<gt>> formatting code that
+Pod::Man was unable to parse. You should never see this error message; it
+probably indicates a bug in Pod::Man.
+
+=item Invalid quote specification "%s"
+
+(F) The quote specification given (the quotes option to the constructor) was
+invalid. A quote specification must be one, two, or four characters long.
+
+=item %s:%d: Unknown command paragraph "%s".
+
+(W) The POD source contained a non-standard command paragraph (something of
+the form C<=command args>) that Pod::Man didn't know about. It was ignored.
+
+=item %s:%d: Unknown escape EE<lt>%sE<gt>
+
+(W) The POD source contained an C<EE<lt>E<gt>> escape that Pod::Man didn't
+know about. C<EE<lt>%sE<gt>> was printed verbatim in the output.
+
+=item %s:%d: Unknown formatting code %s
+
+(W) The POD source contained a non-standard formatting code (something of
+the form C<XE<lt>E<gt>>) that Pod::Man didn't know about. It was ignored.
+
+=item %s:%d: Unmatched =back
+
+(W) Pod::Man encountered a C<=back> command that didn't correspond to an
+C<=over> command.
+
+=back
+
+=head1 BUGS
+
+Eight-bit input data isn't handled at all well at present. The correct
+approach would be to map EE<lt>E<gt> escapes to the appropriate UTF-8
+characters and then do a translation pass on the output according to the
+user-specified output character set. Unfortunately, we can't send eight-bit
+data directly to the output unless the user says this is okay, since some
+vendor *roff implementations can't handle eight-bit data. If the *roff
+implementation can, however, that's far superior to the current hacked
+characters that only work under troff.
+
+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).
+
+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.
+
+Pod::Man doesn't handle font names longer than two characters. Neither do
+most B<troff> 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 EE<lt>E<gt> escapes for 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
+
+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<troff> output.
+
+When and whether to use small caps is somewhat tricky, and Pod::Man doesn't
+necessarily get it right.
+
+=head1 SEE ALSO
+
+L<Pod::Parser>, L<perlpod(1)>, L<pod2man(1)>, L<nroff(1)>, L<troff(1)>,
+L<man(1)>, L<man(7)>
+
+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<nroff> and B<troff>. At the time of
+this writing, it's available at
+L<http://www.cs.bell-labs.com/cm/cs/cstr.html>.
+
+The man page documenting the man macro set may be L<man(5)> instead of
+L<man(7)> on your system. Also, please see L<pod2man(1)> 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<http://www.eyrie.org/~eagle/software/podlators/>. It is also part of the
+Perl core distribution as of 5.6.0.
+
+=head1 AUTHOR
+
+Russ Allbery <rra@stanford.edu>, based I<very> heavily on the original
+B<pod2man> by Tom Christiansen <tchrist@mox.perl.com>.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 1999, 2000, 2001, 2002, 2003 by Russ Allbery <rra@stanford.edu>.
+
+This program is free software; you may redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut
diff --git a/Master/tlpkg/tlperl/lib/Pod/ParseLink.pm b/Master/tlpkg/tlperl/lib/Pod/ParseLink.pm
new file mode 100644
index 00000000000..7e4153da3d0
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/ParseLink.pm
@@ -0,0 +1,184 @@
+# Pod::ParseLink -- Parse an L<> formatting code in POD text.
+# $Id: ParseLink.pm,v 1.6 2002/07/15 05:46:00 eagle Exp $
+#
+# Copyright 2001 by Russ Allbery <rra@stanford.edu>
+#
+# This program is free software; you may redistribute it and/or modify it
+# under the same terms as Perl itself.
+#
+# 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.
+#
+# Perl core hackers, please note that this module is also separately
+# maintained outside of the Perl core as part of the podlators. Please send
+# me any patches at the address above in addition to sending them to the
+# standard Perl mailing lists.
+
+##############################################################################
+# Modules and declarations
+##############################################################################
+
+package Pod::ParseLink;
+
+require 5.004;
+
+use strict;
+use vars qw(@EXPORT @ISA $VERSION);
+
+use Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(parselink);
+
+# Don't use the CVS revision as the version, since this module is also in Perl
+# core and too many things could munge CVS magic revision strings. This
+# number should ideally be the same as the CVS revision in podlators, however.
+$VERSION = 1.06;
+
+
+##############################################################################
+# 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;
+ if ($link =~ /\A\w+:[^:\s]\S*\Z/) {
+ return (undef, $link, $link, undef, 'url');
+ } else {
+ my $text;
+ if ($link =~ /\|/) {
+ ($text, $link) = split (/\|/, $link, 2);
+ }
+ my ($name, $section) = _parse_section ($link);
+ my $inferred = $text || _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__
+
+=head1 NAME
+
+Pod::ParseLink - Parse an LE<lt>E<gt> formatting code in POD text
+
+=head1 SYNOPSIS
+
+ use Pod::ParseLink;
+ my ($text, $inferred, $name, $section, $type) = parselink ($link);
+
+=head1 DESCRIPTION
+
+This module only provides a single function, parselink(), which takes the
+text of an LE<lt>E<gt> 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 'url', 'pod', or 'man', indicating a URL, a
+link to a POD page, or a link to a Unix manual page.
+
+Parsing is implemented per L<perlpodspec>. 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<lt>/sectionE<gt>).
+
+The inferred anchor text is implemented per L<perlpodspec>:
+
+ L<name> => L<name|name>
+ L</section> => L<"section"|/section>
+ L<name/section> => L<"section" in name|name/section>
+
+The name may contain embedded EE<lt>E<gt> and ZE<lt>E<gt> 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 LE<lt>E<gt> escape is entirely enclosed in double quotes,
+it's interpreted as a link to a section for backwards compatibility.
+
+No attempt is made to resolve formatting codes. This must be done after
+calling parselink (since EE<lt>E<gt> 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:
+
+ L<verticalE<verbar>barE<sol>slash>
+
+which should be interpreted as a link to the C<vertical|bar/slash> POD page
+and not as a link to the C<slash> section of the C<bar> POD page with an
+anchor text of C<vertical>. 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 EE<lt>E<gt> and ZE<lt>E<gt> 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<perlpodspec> for more information.
+
+=head1 SEE ALSO
+
+L<Pod::Parser>
+
+The current version of this module is always available from its web site at
+L<http://www.eyrie.org/~eagle/software/podlators/>.
+
+=head1 AUTHOR
+
+Russ Allbery <rra@stanford.edu>.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2001 by Russ Allbery <rra@stanford.edu>.
+
+This program is free software; you may redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut
diff --git a/Master/tlpkg/tlperl/lib/Pod/ParseUtils.pm b/Master/tlpkg/tlperl/lib/Pod/ParseUtils.pm
new file mode 100644
index 00000000000..878860121d3
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/ParseUtils.pm
@@ -0,0 +1,852 @@
+#############################################################################
+# Pod/ParseUtils.pm -- helpers for POD parsing and conversion
+#
+# Copyright (C) 1999-2000 by Marek Rouchal. All rights reserved.
+# This file is part of "PodParser". PodParser is free software;
+# you can redistribute it and/or modify it under the same terms
+# as Perl itself.
+#############################################################################
+
+package Pod::ParseUtils;
+
+use vars qw($VERSION);
+$VERSION = 1.33; ## Current version of this package
+require 5.005; ## requires this Perl version or later
+
+=head1 NAME
+
+Pod::ParseUtils - helpers for POD parsing and conversion
+
+=head1 SYNOPSIS
+
+ use Pod::ParseUtils;
+
+ my $list = new Pod::List;
+ my $link = Pod::Hyperlink->new('Pod::Parser');
+
+=head1 DESCRIPTION
+
+B<Pod::ParseUtils> contains a few object-oriented helper packages for
+POD parsing and processing (i.e. in POD formatters and translators).
+
+=cut
+
+#-----------------------------------------------------------------------------
+# Pod::List
+#
+# class to hold POD list info (=over, =item, =back)
+#-----------------------------------------------------------------------------
+
+package Pod::List;
+
+use Carp;
+
+=head2 Pod::List
+
+B<Pod::List> can be used to hold information about POD lists
+(written as =over ... =item ... =back) for further processing.
+The following methods are available:
+
+=over 4
+
+=item Pod::List-E<gt>new()
+
+Create a new list object. Properties may be specified through a hash
+reference like this:
+
+ my $list = Pod::List->new({ -start => $., -indent => 4 });
+
+See the individual methods/properties for details.
+
+=cut
+
+sub new {
+ my $this = shift;
+ my $class = ref($this) || $this;
+ my %params = @_;
+ my $self = {%params};
+ bless $self, $class;
+ $self->initialize();
+ return $self;
+}
+
+sub initialize {
+ my $self = shift;
+ $self->{-file} ||= 'unknown';
+ $self->{-start} ||= 'unknown';
+ $self->{-indent} ||= 4; # perlpod: "should be the default"
+ $self->{_items} = [];
+ $self->{-type} ||= '';
+}
+
+=item $list-E<gt>file()
+
+Without argument, retrieves the file name the list is in. This must
+have been set before by either specifying B<-file> in the B<new()>
+method or by calling the B<file()> method with a scalar argument.
+
+=cut
+
+# The POD file name the list appears in
+sub file {
+ return (@_ > 1) ? ($_[0]->{-file} = $_[1]) : $_[0]->{-file};
+}
+
+=item $list-E<gt>start()
+
+Without argument, retrieves the line number where the list started.
+This must have been set before by either specifying B<-start> in the
+B<new()> method or by calling the B<start()> method with a scalar
+argument.
+
+=cut
+
+# The line in the file the node appears
+sub start {
+ return (@_ > 1) ? ($_[0]->{-start} = $_[1]) : $_[0]->{-start};
+}
+
+=item $list-E<gt>indent()
+
+Without argument, retrieves the indent level of the list as specified
+in C<=over n>. This must have been set before by either specifying
+B<-indent> in the B<new()> method or by calling the B<indent()> method
+with a scalar argument.
+
+=cut
+
+# indent level
+sub indent {
+ return (@_ > 1) ? ($_[0]->{-indent} = $_[1]) : $_[0]->{-indent};
+}
+
+=item $list-E<gt>type()
+
+Without argument, retrieves the list type, which can be an arbitrary value,
+e.g. C<OL>, C<UL>, ... when thinking the HTML way.
+This must have been set before by either specifying
+B<-type> in the B<new()> method or by calling the B<type()> method
+with a scalar argument.
+
+=cut
+
+# The type of the list (UL, OL, ...)
+sub type {
+ return (@_ > 1) ? ($_[0]->{-type} = $_[1]) : $_[0]->{-type};
+}
+
+=item $list-E<gt>rx()
+
+Without argument, retrieves a regular expression for simplifying the
+individual item strings once the list type has been determined. Usage:
+E.g. when converting to HTML, one might strip the leading number in
+an ordered list as C<E<lt>OLE<gt>> already prints numbers itself.
+This must have been set before by either specifying
+B<-rx> in the B<new()> method or by calling the B<rx()> method
+with a scalar argument.
+
+=cut
+
+# The regular expression to simplify the items
+sub rx {
+ return (@_ > 1) ? ($_[0]->{-rx} = $_[1]) : $_[0]->{-rx};
+}
+
+=item $list-E<gt>item()
+
+Without argument, retrieves the array of the items in this list.
+The items may be represented by any scalar.
+If an argument has been given, it is pushed on the list of items.
+
+=cut
+
+# The individual =items of this list
+sub item {
+ my ($self,$item) = @_;
+ if(defined $item) {
+ push(@{$self->{_items}}, $item);
+ return $item;
+ }
+ else {
+ return @{$self->{_items}};
+ }
+}
+
+=item $list-E<gt>parent()
+
+Without argument, retrieves information about the parent holding this
+list, which is represented as an arbitrary scalar.
+This must have been set before by either specifying
+B<-parent> in the B<new()> method or by calling the B<parent()> method
+with a scalar argument.
+
+=cut
+
+# possibility for parsers/translators to store information about the
+# lists's parent object
+sub parent {
+ return (@_ > 1) ? ($_[0]->{-parent} = $_[1]) : $_[0]->{-parent};
+}
+
+=item $list-E<gt>tag()
+
+Without argument, retrieves information about the list tag, which can be
+any scalar.
+This must have been set before by either specifying
+B<-tag> in the B<new()> method or by calling the B<tag()> method
+with a scalar argument.
+
+=back
+
+=cut
+
+# possibility for parsers/translators to store information about the
+# list's object
+sub tag {
+ return (@_ > 1) ? ($_[0]->{-tag} = $_[1]) : $_[0]->{-tag};
+}
+
+#-----------------------------------------------------------------------------
+# Pod::Hyperlink
+#
+# class to manipulate POD hyperlinks (L<>)
+#-----------------------------------------------------------------------------
+
+package Pod::Hyperlink;
+
+=head2 Pod::Hyperlink
+
+B<Pod::Hyperlink> is a class for manipulation of POD hyperlinks. Usage:
+
+ my $link = Pod::Hyperlink->new('alternative text|page/"section in page"');
+
+The B<Pod::Hyperlink> class is mainly designed to parse the contents of the
+C<LE<lt>...E<gt>> sequence, providing a simple interface for accessing the
+different parts of a POD hyperlink for further processing. It can also be
+used to construct hyperlinks.
+
+=over 4
+
+=item Pod::Hyperlink-E<gt>new()
+
+The B<new()> method can either be passed a set of key/value pairs or a single
+scalar value, namely the contents of a C<LE<lt>...E<gt>> sequence. An object
+of the class C<Pod::Hyperlink> is returned. The value C<undef> indicates a
+failure, the error message is stored in C<$@>.
+
+=cut
+
+use Carp;
+
+sub new {
+ my $this = shift;
+ my $class = ref($this) || $this;
+ my $self = +{};
+ bless $self, $class;
+ $self->initialize();
+ if(defined $_[0]) {
+ if(ref($_[0])) {
+ # called with a list of parameters
+ %$self = %{$_[0]};
+ $self->_construct_text();
+ }
+ else {
+ # called with L<> contents
+ return undef unless($self->parse($_[0]));
+ }
+ }
+ return $self;
+}
+
+sub initialize {
+ my $self = shift;
+ $self->{-line} ||= 'undef';
+ $self->{-file} ||= 'undef';
+ $self->{-page} ||= '';
+ $self->{-node} ||= '';
+ $self->{-alttext} ||= '';
+ $self->{-type} ||= 'undef';
+ $self->{_warnings} = [];
+}
+
+=item $link-E<gt>parse($string)
+
+This method can be used to (re)parse a (new) hyperlink, i.e. the contents
+of a C<LE<lt>...E<gt>> sequence. The result is stored in the current object.
+Warnings are stored in the B<warnings> property.
+E.g. sections like C<LE<lt>open(2)E<gt>> are deprecated, as they do not point
+to Perl documents. C<LE<lt>DBI::foo(3p)E<gt>> is wrong as well, the manpage
+section can simply be dropped.
+
+=cut
+
+sub parse {
+ my $self = shift;
+ local($_) = $_[0];
+ # syntax check the link and extract destination
+ my ($alttext,$page,$node,$type,$quoted) = (undef,'','','',0);
+
+ $self->{_warnings} = [];
+
+ # collapse newlines with whitespace
+ s/\s*\n+\s*/ /g;
+
+ # strip leading/trailing whitespace
+ if(s/^[\s\n]+//) {
+ $self->warning("ignoring leading whitespace in link");
+ }
+ if(s/[\s\n]+$//) {
+ $self->warning("ignoring trailing whitespace in link");
+ }
+ unless(length($_)) {
+ _invalid_link("empty link");
+ return undef;
+ }
+
+ ## Check for different possibilities. This is tedious and error-prone
+ # we match all possibilities (alttext, page, section/item)
+ #warn "DEBUG: link=$_\n";
+
+ # only page
+ # problem: a lot of people use (), or (1) or the like to indicate
+ # man page sections. But this collides with L<func()> that is supposed
+ # to point to an internal funtion...
+ my $page_rx = '[\w.-]+(?:::[\w.-]+)*(?:[(](?:\d\w*|)[)]|)';
+ # page name only
+ if(m!^($page_rx)$!o) {
+ $page = $1;
+ $type = 'page';
+ }
+ # alttext, page and "section"
+ elsif(m!^(.*?)\s*[|]\s*($page_rx)\s*/\s*"(.+)"$!o) {
+ ($alttext, $page, $node) = ($1, $2, $3);
+ $type = 'section';
+ $quoted = 1; #... therefore | and / are allowed
+ }
+ # alttext and page
+ elsif(m!^(.*?)\s*[|]\s*($page_rx)$!o) {
+ ($alttext, $page) = ($1, $2);
+ $type = 'page';
+ }
+ # alttext and "section"
+ elsif(m!^(.*?)\s*[|]\s*(?:/\s*|)"(.+)"$!) {
+ ($alttext, $node) = ($1,$2);
+ $type = 'section';
+ $quoted = 1;
+ }
+ # page and "section"
+ elsif(m!^($page_rx)\s*/\s*"(.+)"$!o) {
+ ($page, $node) = ($1, $2);
+ $type = 'section';
+ $quoted = 1;
+ }
+ # page and item
+ elsif(m!^($page_rx)\s*/\s*(.+)$!o) {
+ ($page, $node) = ($1, $2);
+ $type = 'item';
+ }
+ # only "section"
+ elsif(m!^/?"(.+)"$!) {
+ $node = $1;
+ $type = 'section';
+ $quoted = 1;
+ }
+ # only item
+ elsif(m!^\s*/(.+)$!) {
+ $node = $1;
+ $type = 'item';
+ }
+ # non-standard: Hyperlink
+ elsif(m!^(\w+:[^:\s]\S*)$!i) {
+ $node = $1;
+ $type = 'hyperlink';
+ }
+ # alttext, page and item
+ elsif(m!^(.*?)\s*[|]\s*($page_rx)\s*/\s*(.+)$!o) {
+ ($alttext, $page, $node) = ($1, $2, $3);
+ $type = 'item';
+ }
+ # alttext and item
+ elsif(m!^(.*?)\s*[|]\s*/(.+)$!) {
+ ($alttext, $node) = ($1,$2);
+ }
+ # nonstandard: alttext and hyperlink
+ elsif(m!^(.*?)\s*[|]\s*(\w+:[^:\s]\S*)$!) {
+ ($alttext, $node) = ($1,$2);
+ $type = 'hyperlink';
+ }
+ # must be an item or a "malformed" section (without "")
+ else {
+ $node = $_;
+ $type = 'item';
+ }
+ # collapse whitespace in nodes
+ $node =~ s/\s+/ /gs;
+
+ # empty alternative text expands to node name
+ if(defined $alttext) {
+ if(!length($alttext)) {
+ $alttext = $node | $page;
+ }
+ }
+ else {
+ $alttext = '';
+ }
+
+ if($page =~ /[(]\w*[)]$/) {
+ $self->warning("(section) in '$page' deprecated");
+ }
+ if(!$quoted && $node =~ m:[|/]: && $type ne 'hyperlink') {
+ $self->warning("node '$node' contains non-escaped | or /");
+ }
+ if($alttext =~ m:[|/]:) {
+ $self->warning("alternative text '$node' contains non-escaped | or /");
+ }
+ $self->{-page} = $page;
+ $self->{-node} = $node;
+ $self->{-alttext} = $alttext;
+ #warn "DEBUG: page=$page section=$section item=$item alttext=$alttext\n";
+ $self->{-type} = $type;
+ $self->_construct_text();
+ 1;
+}
+
+sub _construct_text {
+ my $self = shift;
+ my $alttext = $self->alttext();
+ my $type = $self->type();
+ my $section = $self->node();
+ my $page = $self->page();
+ my $page_ext = '';
+ $page =~ s/([(]\w*[)])$// && ($page_ext = $1);
+ if($alttext) {
+ $self->{_text} = $alttext;
+ }
+ elsif($type eq 'hyperlink') {
+ $self->{_text} = $section;
+ }
+ else {
+ $self->{_text} = ($section || '') .
+ (($page && $section) ? ' in ' : '') .
+ "$page$page_ext";
+ }
+ # for being marked up later
+ # use the non-standard markers P<> and Q<>, so that the resulting
+ # text can be parsed by the translators. It's their job to put
+ # the correct hypertext around the linktext
+ if($alttext) {
+ $self->{_markup} = "Q<$alttext>";
+ }
+ elsif($type eq 'hyperlink') {
+ $self->{_markup} = "Q<$section>";
+ }
+ else {
+ $self->{_markup} = (!$section ? '' : "Q<$section>") .
+ ($page ? ($section ? ' in ':'') . "P<$page>$page_ext" : '');
+ }
+}
+
+=item $link-E<gt>markup($string)
+
+Set/retrieve the textual value of the link. This string contains special
+markers C<PE<lt>E<gt>> and C<QE<lt>E<gt>> that should be expanded by the
+translator's interior sequence expansion engine to the
+formatter-specific code to highlight/activate the hyperlink. The details
+have to be implemented in the translator.
+
+=cut
+
+#' retrieve/set markuped text
+sub markup {
+ return (@_ > 1) ? ($_[0]->{_markup} = $_[1]) : $_[0]->{_markup};
+}
+
+=item $link-E<gt>text()
+
+This method returns the textual representation of the hyperlink as above,
+but without markers (read only). Depending on the link type this is one of
+the following alternatives (the + and * denote the portions of the text
+that are marked up):
+
+ +perl+ L<perl>
+ *$|* in +perlvar+ L<perlvar/$|>
+ *OPTIONS* in +perldoc+ L<perldoc/"OPTIONS">
+ *DESCRIPTION* L<"DESCRIPTION">
+
+=cut
+
+# The complete link's text
+sub text {
+ $_[0]->{_text};
+}
+
+=item $link-E<gt>warning()
+
+After parsing, this method returns any warnings encountered during the
+parsing process.
+
+=cut
+
+# Set/retrieve warnings
+sub warning {
+ my $self = shift;
+ if(@_) {
+ push(@{$self->{_warnings}}, @_);
+ return @_;
+ }
+ return @{$self->{_warnings}};
+}
+
+=item $link-E<gt>file()
+
+=item $link-E<gt>line()
+
+Just simple slots for storing information about the line and the file
+the link was encountered in. Has to be filled in manually.
+
+=cut
+
+# The line in the file the link appears
+sub line {
+ return (@_ > 1) ? ($_[0]->{-line} = $_[1]) : $_[0]->{-line};
+}
+
+# The POD file name the link appears in
+sub file {
+ return (@_ > 1) ? ($_[0]->{-file} = $_[1]) : $_[0]->{-file};
+}
+
+=item $link-E<gt>page()
+
+This method sets or returns the POD page this link points to.
+
+=cut
+
+# The POD page the link appears on
+sub page {
+ if (@_ > 1) {
+ $_[0]->{-page} = $_[1];
+ $_[0]->_construct_text();
+ }
+ $_[0]->{-page};
+}
+
+=item $link-E<gt>node()
+
+As above, but the destination node text of the link.
+
+=cut
+
+# The link destination
+sub node {
+ if (@_ > 1) {
+ $_[0]->{-node} = $_[1];
+ $_[0]->_construct_text();
+ }
+ $_[0]->{-node};
+}
+
+=item $link-E<gt>alttext()
+
+Sets or returns an alternative text specified in the link.
+
+=cut
+
+# Potential alternative text
+sub alttext {
+ if (@_ > 1) {
+ $_[0]->{-alttext} = $_[1];
+ $_[0]->_construct_text();
+ }
+ $_[0]->{-alttext};
+}
+
+=item $link-E<gt>type()
+
+The node type, either C<section> or C<item>. As an unofficial type,
+there is also C<hyperlink>, derived from e.g. C<LE<lt>http://perl.comE<gt>>
+
+=cut
+
+# The type: item or headn
+sub type {
+ return (@_ > 1) ? ($_[0]->{-type} = $_[1]) : $_[0]->{-type};
+}
+
+=item $link-E<gt>link()
+
+Returns the link as contents of C<LE<lt>E<gt>>. Reciprocal to B<parse()>.
+
+=back
+
+=cut
+
+# The link itself
+sub link {
+ my $self = shift;
+ my $link = $self->page() || '';
+ if($self->node()) {
+ my $node = $self->node();
+ $text =~ s/\|/E<verbar>/g;
+ $text =~ s:/:E<sol>:g;
+ if($self->type() eq 'section') {
+ $link .= ($link ? '/' : '') . '"' . $node . '"';
+ }
+ elsif($self->type() eq 'hyperlink') {
+ $link = $self->node();
+ }
+ else { # item
+ $link .= '/' . $node;
+ }
+ }
+ if($self->alttext()) {
+ my $text = $self->alttext();
+ $text =~ s/\|/E<verbar>/g;
+ $text =~ s:/:E<sol>:g;
+ $link = "$text|$link";
+ }
+ $link;
+}
+
+sub _invalid_link {
+ my ($msg) = @_;
+ # this sets @_
+ #eval { die "$msg\n" };
+ #chomp $@;
+ $@ = $msg; # this seems to work, too!
+ undef;
+}
+
+#-----------------------------------------------------------------------------
+# Pod::Cache
+#
+# class to hold POD page details
+#-----------------------------------------------------------------------------
+
+package Pod::Cache;
+
+=head2 Pod::Cache
+
+B<Pod::Cache> holds information about a set of POD documents,
+especially the nodes for hyperlinks.
+The following methods are available:
+
+=over 4
+
+=item Pod::Cache-E<gt>new()
+
+Create a new cache object. This object can hold an arbitrary number of
+POD documents of class Pod::Cache::Item.
+
+=cut
+
+sub new {
+ my $this = shift;
+ my $class = ref($this) || $this;
+ my $self = [];
+ bless $self, $class;
+ return $self;
+}
+
+=item $cache-E<gt>item()
+
+Add a new item to the cache. Without arguments, this method returns a
+list of all cache elements.
+
+=cut
+
+sub item {
+ my ($self,%param) = @_;
+ if(%param) {
+ my $item = Pod::Cache::Item->new(%param);
+ push(@$self, $item);
+ return $item;
+ }
+ else {
+ return @{$self};
+ }
+}
+
+=item $cache-E<gt>find_page($name)
+
+Look for a POD document named C<$name> in the cache. Returns the
+reference to the corresponding Pod::Cache::Item object or undef if
+not found.
+
+=back
+
+=cut
+
+sub find_page {
+ my ($self,$page) = @_;
+ foreach(@$self) {
+ if($_->page() eq $page) {
+ return $_;
+ }
+ }
+ undef;
+}
+
+package Pod::Cache::Item;
+
+=head2 Pod::Cache::Item
+
+B<Pod::Cache::Item> holds information about individual POD documents,
+that can be grouped in a Pod::Cache object.
+It is intended to hold information about the hyperlink nodes of POD
+documents.
+The following methods are available:
+
+=over 4
+
+=item Pod::Cache::Item-E<gt>new()
+
+Create a new object.
+
+=cut
+
+sub new {
+ my $this = shift;
+ my $class = ref($this) || $this;
+ my %params = @_;
+ my $self = {%params};
+ bless $self, $class;
+ $self->initialize();
+ return $self;
+}
+
+sub initialize {
+ my $self = shift;
+ $self->{-nodes} = [] unless(defined $self->{-nodes});
+}
+
+=item $cacheitem-E<gt>page()
+
+Set/retrieve the POD document name (e.g. "Pod::Parser").
+
+=cut
+
+# The POD page
+sub page {
+ return (@_ > 1) ? ($_[0]->{-page} = $_[1]) : $_[0]->{-page};
+}
+
+=item $cacheitem-E<gt>description()
+
+Set/retrieve the POD short description as found in the C<=head1 NAME>
+section.
+
+=cut
+
+# The POD description, taken out of NAME if present
+sub description {
+ return (@_ > 1) ? ($_[0]->{-description} = $_[1]) : $_[0]->{-description};
+}
+
+=item $cacheitem-E<gt>path()
+
+Set/retrieve the POD file storage path.
+
+=cut
+
+# The file path
+sub path {
+ return (@_ > 1) ? ($_[0]->{-path} = $_[1]) : $_[0]->{-path};
+}
+
+=item $cacheitem-E<gt>file()
+
+Set/retrieve the POD file name.
+
+=cut
+
+# The POD file name
+sub file {
+ return (@_ > 1) ? ($_[0]->{-file} = $_[1]) : $_[0]->{-file};
+}
+
+=item $cacheitem-E<gt>nodes()
+
+Add a node (or a list of nodes) to the document's node list. Note that
+the order is kept, i.e. start with the first node and end with the last.
+If no argument is given, the current list of nodes is returned in the
+same order the nodes have been added.
+A node can be any scalar, but usually is a pair of node string and
+unique id for the C<find_node> method to work correctly.
+
+=cut
+
+# The POD nodes
+sub nodes {
+ my ($self,@nodes) = @_;
+ if(@nodes) {
+ push(@{$self->{-nodes}}, @nodes);
+ return @nodes;
+ }
+ else {
+ return @{$self->{-nodes}};
+ }
+}
+
+=item $cacheitem-E<gt>find_node($name)
+
+Look for a node or index entry named C<$name> in the object.
+Returns the unique id of the node (i.e. the second element of the array
+stored in the node arry) or undef if not found.
+
+=cut
+
+sub find_node {
+ my ($self,$node) = @_;
+ my @search;
+ push(@search, @{$self->{-nodes}}) if($self->{-nodes});
+ push(@search, @{$self->{-idx}}) if($self->{-idx});
+ foreach(@search) {
+ if($_->[0] eq $node) {
+ return $_->[1]; # id
+ }
+ }
+ undef;
+}
+
+=item $cacheitem-E<gt>idx()
+
+Add an index entry (or a list of them) to the document's index list. Note that
+the order is kept, i.e. start with the first node and end with the last.
+If no argument is given, the current list of index entries is returned in the
+same order the entries have been added.
+An index entry can be any scalar, but usually is a pair of string and
+unique id.
+
+=back
+
+=cut
+
+# The POD index entries
+sub idx {
+ my ($self,@idx) = @_;
+ if(@idx) {
+ push(@{$self->{-idx}}, @idx);
+ return @idx;
+ }
+ else {
+ return @{$self->{-idx}};
+ }
+}
+
+=head1 AUTHOR
+
+Please report bugs using L<http://rt.cpan.org>.
+
+Marek Rouchal E<lt>marekr@cpan.orgE<gt>, borrowing
+a lot of things from L<pod2man> and L<pod2roff> as well as other POD
+processing tools by Tom Christiansen, Brad Appleton and Russ Allbery.
+
+=head1 SEE ALSO
+
+L<pod2man>, L<pod2roff>, L<Pod::Parser>, L<Pod::Checker>,
+L<pod2html>
+
+=cut
+
+1;
diff --git a/Master/tlpkg/tlperl/lib/Pod/Parser.pm b/Master/tlpkg/tlperl/lib/Pod/Parser.pm
new file mode 100644
index 00000000000..a5fde848503
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Parser.pm
@@ -0,0 +1,1799 @@
+#############################################################################
+# Pod/Parser.pm -- package which defines a base class for parsing POD docs.
+#
+# Copyright (C) 1996-2000 by Bradford Appleton. All rights reserved.
+# This file is part of "PodParser". PodParser is free software;
+# you can redistribute it and/or modify it under the same terms
+# as Perl itself.
+#############################################################################
+
+package Pod::Parser;
+
+use vars qw($VERSION);
+$VERSION = 1.32; ## Current version of this package
+require 5.005; ## requires this Perl version or later
+
+#############################################################################
+
+=head1 NAME
+
+Pod::Parser - base class for creating POD filters and translators
+
+=head1 SYNOPSIS
+
+ use Pod::Parser;
+
+ package MyParser;
+ @ISA = qw(Pod::Parser);
+
+ sub command {
+ my ($parser, $command, $paragraph, $line_num) = @_;
+ ## Interpret the command and its text; sample actions might be:
+ if ($command eq 'head1') { ... }
+ elsif ($command eq 'head2') { ... }
+ ## ... other commands and their actions
+ my $out_fh = $parser->output_handle();
+ my $expansion = $parser->interpolate($paragraph, $line_num);
+ print $out_fh $expansion;
+ }
+
+ sub verbatim {
+ my ($parser, $paragraph, $line_num) = @_;
+ ## Format verbatim paragraph; sample actions might be:
+ my $out_fh = $parser->output_handle();
+ print $out_fh $paragraph;
+ }
+
+ sub textblock {
+ my ($parser, $paragraph, $line_num) = @_;
+ ## Translate/Format this block of text; sample actions might be:
+ my $out_fh = $parser->output_handle();
+ my $expansion = $parser->interpolate($paragraph, $line_num);
+ print $out_fh $expansion;
+ }
+
+ sub interior_sequence {
+ my ($parser, $seq_command, $seq_argument) = @_;
+ ## Expand an interior sequence; sample actions might be:
+ return "*$seq_argument*" if ($seq_command eq 'B');
+ return "`$seq_argument'" if ($seq_command eq 'C');
+ return "_${seq_argument}_'" if ($seq_command eq 'I');
+ ## ... other sequence commands and their resulting text
+ }
+
+ package main;
+
+ ## Create a parser object and have it parse file whose name was
+ ## given on the command-line (use STDIN if no files were given).
+ $parser = new MyParser();
+ $parser->parse_from_filehandle(\*STDIN) if (@ARGV == 0);
+ for (@ARGV) { $parser->parse_from_file($_); }
+
+=head1 REQUIRES
+
+perl5.005, Pod::InputObjects, Exporter, Symbol, Carp
+
+=head1 EXPORTS
+
+Nothing.
+
+=head1 DESCRIPTION
+
+B<Pod::Parser> is a base class for creating POD filters and translators.
+It handles most of the effort involved with parsing the POD sections
+from an input stream, leaving subclasses free to be concerned only with
+performing the actual translation of text.
+
+B<Pod::Parser> parses PODs, and makes method calls to handle the various
+components of the POD. Subclasses of B<Pod::Parser> override these methods
+to translate the POD into whatever output format they desire.
+
+=head1 QUICK OVERVIEW
+
+To create a POD filter for translating POD documentation into some other
+format, you create a subclass of B<Pod::Parser> which typically overrides
+just the base class implementation for the following methods:
+
+=over 2
+
+=item *
+
+B<command()>
+
+=item *
+
+B<verbatim()>
+
+=item *
+
+B<textblock()>
+
+=item *
+
+B<interior_sequence()>
+
+=back
+
+You may also want to override the B<begin_input()> and B<end_input()>
+methods for your subclass (to perform any needed per-file and/or
+per-document initialization or cleanup).
+
+If you need to perform any preprocesssing of input before it is parsed
+you may want to override one or more of B<preprocess_line()> and/or
+B<preprocess_paragraph()>.
+
+Sometimes it may be necessary to make more than one pass over the input
+files. If this is the case you have several options. You can make the
+first pass using B<Pod::Parser> and override your methods to store the
+intermediate results in memory somewhere for the B<end_pod()> method to
+process. You could use B<Pod::Parser> for several passes with an
+appropriate state variable to control the operation for each pass. If
+your input source can't be reset to start at the beginning, you can
+store it in some other structure as a string or an array and have that
+structure implement a B<getline()> method (which is all that
+B<parse_from_filehandle()> uses to read input).
+
+Feel free to add any member data fields you need to keep track of things
+like current font, indentation, horizontal or vertical position, or
+whatever else you like. Be sure to read L<"PRIVATE METHODS AND DATA">
+to avoid name collisions.
+
+For the most part, the B<Pod::Parser> base class should be able to
+do most of the input parsing for you and leave you free to worry about
+how to intepret the commands and translate the result.
+
+Note that all we have described here in this quick overview is the
+simplest most straightforward use of B<Pod::Parser> to do stream-based
+parsing. It is also possible to use the B<Pod::Parser::parse_text> function
+to do more sophisticated tree-based parsing. See L<"TREE-BASED PARSING">.
+
+=head1 PARSING OPTIONS
+
+A I<parse-option> is simply a named option of B<Pod::Parser> with a
+value that corresponds to a certain specified behavior. These various
+behaviors of B<Pod::Parser> may be enabled/disabled by setting
+or unsetting one or more I<parse-options> using the B<parseopts()> method.
+The set of currently accepted parse-options is as follows:
+
+=over 3
+
+=item B<-want_nonPODs> (default: unset)
+
+Normally (by default) B<Pod::Parser> will only provide access to
+the POD sections of the input. Input paragraphs that are not part
+of the POD-format documentation are not made available to the caller
+(not even using B<preprocess_paragraph()>). Setting this option to a
+non-empty, non-zero value will allow B<preprocess_paragraph()> to see
+non-POD sections of the input as well as POD sections. The B<cutting()>
+method can be used to determine if the corresponding paragraph is a POD
+paragraph, or some other input paragraph.
+
+=item B<-process_cut_cmd> (default: unset)
+
+Normally (by default) B<Pod::Parser> handles the C<=cut> POD directive
+by itself and does not pass it on to the caller for processing. Setting
+this option to a non-empty, non-zero value will cause B<Pod::Parser> to
+pass the C<=cut> directive to the caller just like any other POD command
+(and hence it may be processed by the B<command()> method).
+
+B<Pod::Parser> will still interpret the C<=cut> directive to mean that
+"cutting mode" has been (re)entered, but the caller will get a chance
+to capture the actual C<=cut> paragraph itself for whatever purpose
+it desires.
+
+=item B<-warnings> (default: unset)
+
+Normally (by default) B<Pod::Parser> recognizes a bare minimum of
+pod syntax errors and warnings and issues diagnostic messages
+for errors, but not for warnings. (Use B<Pod::Checker> to do more
+thorough checking of POD syntax.) Setting this option to a non-empty,
+non-zero value will cause B<Pod::Parser> to issue diagnostics for
+the few warnings it recognizes as well as the errors.
+
+=back
+
+Please see L<"parseopts()"> for a complete description of the interface
+for the setting and unsetting of parse-options.
+
+=cut
+
+#############################################################################
+
+use vars qw(@ISA);
+use strict;
+#use diagnostics;
+use Pod::InputObjects;
+use Carp;
+use Exporter;
+BEGIN {
+ if ($] < 5.6) {
+ require Symbol;
+ import Symbol;
+ }
+}
+@ISA = qw(Exporter);
+
+## These "variables" are used as local "glob aliases" for performance
+use vars qw(%myData %myOpts @input_stack);
+
+#############################################################################
+
+=head1 RECOMMENDED SUBROUTINE/METHOD OVERRIDES
+
+B<Pod::Parser> provides several methods which most subclasses will probably
+want to override. These methods are as follows:
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=head1 B<command()>
+
+ $parser->command($cmd,$text,$line_num,$pod_para);
+
+This method should be overridden by subclasses to take the appropriate
+action when a POD command paragraph (denoted by a line beginning with
+"=") is encountered. When such a POD directive is seen in the input,
+this method is called and is passed:
+
+=over 3
+
+=item C<$cmd>
+
+the name of the command for this POD paragraph
+
+=item C<$text>
+
+the paragraph text for the given POD paragraph command.
+
+=item C<$line_num>
+
+the line-number of the beginning of the paragraph
+
+=item C<$pod_para>
+
+a reference to a C<Pod::Paragraph> object which contains further
+information about the paragraph command (see L<Pod::InputObjects>
+for details).
+
+=back
+
+B<Note> that this method I<is> called for C<=pod> paragraphs.
+
+The base class implementation of this method simply treats the raw POD
+command as normal block of paragraph text (invoking the B<textblock()>
+method with the command paragraph).
+
+=cut
+
+sub command {
+ my ($self, $cmd, $text, $line_num, $pod_para) = @_;
+ ## Just treat this like a textblock
+ $self->textblock($pod_para->raw_text(), $line_num, $pod_para);
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<verbatim()>
+
+ $parser->verbatim($text,$line_num,$pod_para);
+
+This method may be overridden by subclasses to take the appropriate
+action when a block of verbatim text is encountered. It is passed the
+following parameters:
+
+=over 3
+
+=item C<$text>
+
+the block of text for the verbatim paragraph
+
+=item C<$line_num>
+
+the line-number of the beginning of the paragraph
+
+=item C<$pod_para>
+
+a reference to a C<Pod::Paragraph> object which contains further
+information about the paragraph (see L<Pod::InputObjects>
+for details).
+
+=back
+
+The base class implementation of this method simply prints the textblock
+(unmodified) to the output filehandle.
+
+=cut
+
+sub verbatim {
+ my ($self, $text, $line_num, $pod_para) = @_;
+ my $out_fh = $self->{_OUTPUT};
+ print $out_fh $text;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<textblock()>
+
+ $parser->textblock($text,$line_num,$pod_para);
+
+This method may be overridden by subclasses to take the appropriate
+action when a normal block of POD text is encountered (although the base
+class method will usually do what you want). It is passed the following
+parameters:
+
+=over 3
+
+=item C<$text>
+
+the block of text for the a POD paragraph
+
+=item C<$line_num>
+
+the line-number of the beginning of the paragraph
+
+=item C<$pod_para>
+
+a reference to a C<Pod::Paragraph> object which contains further
+information about the paragraph (see L<Pod::InputObjects>
+for details).
+
+=back
+
+In order to process interior sequences, subclasses implementations of
+this method will probably want to invoke either B<interpolate()> or
+B<parse_text()>, passing it the text block C<$text>, and the corresponding
+line number in C<$line_num>, and then perform any desired processing upon
+the returned result.
+
+The base class implementation of this method simply prints the text block
+as it occurred in the input stream).
+
+=cut
+
+sub textblock {
+ my ($self, $text, $line_num, $pod_para) = @_;
+ my $out_fh = $self->{_OUTPUT};
+ print $out_fh $self->interpolate($text, $line_num);
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<interior_sequence()>
+
+ $parser->interior_sequence($seq_cmd,$seq_arg,$pod_seq);
+
+This method should be overridden by subclasses to take the appropriate
+action when an interior sequence is encountered. An interior sequence is
+an embedded command within a block of text which appears as a command
+name (usually a single uppercase character) followed immediately by a
+string of text which is enclosed in angle brackets. This method is
+passed the sequence command C<$seq_cmd> and the corresponding text
+C<$seq_arg>. It is invoked by the B<interpolate()> method for each interior
+sequence that occurs in the string that it is passed. It should return
+the desired text string to be used in place of the interior sequence.
+The C<$pod_seq> argument is a reference to a C<Pod::InteriorSequence>
+object which contains further information about the interior sequence.
+Please see L<Pod::InputObjects> for details if you need to access this
+additional information.
+
+Subclass implementations of this method may wish to invoke the
+B<nested()> method of C<$pod_seq> to see if it is nested inside
+some other interior-sequence (and if so, which kind).
+
+The base class implementation of the B<interior_sequence()> method
+simply returns the raw text of the interior sequence (as it occurred
+in the input) to the caller.
+
+=cut
+
+sub interior_sequence {
+ my ($self, $seq_cmd, $seq_arg, $pod_seq) = @_;
+ ## Just return the raw text of the interior sequence
+ return $pod_seq->raw_text();
+}
+
+#############################################################################
+
+=head1 OPTIONAL SUBROUTINE/METHOD OVERRIDES
+
+B<Pod::Parser> provides several methods which subclasses may want to override
+to perform any special pre/post-processing. These methods do I<not> have to
+be overridden, but it may be useful for subclasses to take advantage of them.
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=head1 B<new()>
+
+ my $parser = Pod::Parser->new();
+
+This is the constructor for B<Pod::Parser> and its subclasses. You
+I<do not> need to override this method! It is capable of constructing
+subclass objects as well as base class objects, provided you use
+any of the following constructor invocation styles:
+
+ my $parser1 = MyParser->new();
+ my $parser2 = new MyParser();
+ my $parser3 = $parser2->new();
+
+where C<MyParser> is some subclass of B<Pod::Parser>.
+
+Using the syntax C<MyParser::new()> to invoke the constructor is I<not>
+recommended, but if you insist on being able to do this, then the
+subclass I<will> need to override the B<new()> constructor method. If
+you do override the constructor, you I<must> be sure to invoke the
+B<initialize()> method of the newly blessed object.
+
+Using any of the above invocations, the first argument to the
+constructor is always the corresponding package name (or object
+reference). No other arguments are required, but if desired, an
+associative array (or hash-table) my be passed to the B<new()>
+constructor, as in:
+
+ my $parser1 = MyParser->new( MYDATA => $value1, MOREDATA => $value2 );
+ my $parser2 = new MyParser( -myflag => 1 );
+
+All arguments passed to the B<new()> constructor will be treated as
+key/value pairs in a hash-table. The newly constructed object will be
+initialized by copying the contents of the given hash-table (which may
+have been empty). The B<new()> constructor for this class and all of its
+subclasses returns a blessed reference to the initialized object (hash-table).
+
+=cut
+
+sub new {
+ ## Determine if we were called via an object-ref or a classname
+ my $this = shift;
+ my $class = ref($this) || $this;
+ ## Any remaining arguments are treated as initial values for the
+ ## hash that is used to represent this object.
+ my %params = @_;
+ my $self = { %params };
+ ## Bless ourselves into the desired class and perform any initialization
+ bless $self, $class;
+ $self->initialize();
+ return $self;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<initialize()>
+
+ $parser->initialize();
+
+This method performs any necessary object initialization. It takes no
+arguments (other than the object instance of course, which is typically
+copied to a local variable named C<$self>). If subclasses override this
+method then they I<must> be sure to invoke C<$self-E<gt>SUPER::initialize()>.
+
+=cut
+
+sub initialize {
+ #my $self = shift;
+ #return;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<begin_pod()>
+
+ $parser->begin_pod();
+
+This method is invoked at the beginning of processing for each POD
+document that is encountered in the input. Subclasses should override
+this method to perform any per-document initialization.
+
+=cut
+
+sub begin_pod {
+ #my $self = shift;
+ #return;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<begin_input()>
+
+ $parser->begin_input();
+
+This method is invoked by B<parse_from_filehandle()> immediately I<before>
+processing input from a filehandle. The base class implementation does
+nothing, however, subclasses may override it to perform any per-file
+initializations.
+
+Note that if multiple files are parsed for a single POD document
+(perhaps the result of some future C<=include> directive) this method
+is invoked for every file that is parsed. If you wish to perform certain
+initializations once per document, then you should use B<begin_pod()>.
+
+=cut
+
+sub begin_input {
+ #my $self = shift;
+ #return;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<end_input()>
+
+ $parser->end_input();
+
+This method is invoked by B<parse_from_filehandle()> immediately I<after>
+processing input from a filehandle. The base class implementation does
+nothing, however, subclasses may override it to perform any per-file
+cleanup actions.
+
+Please note that if multiple files are parsed for a single POD document
+(perhaps the result of some kind of C<=include> directive) this method
+is invoked for every file that is parsed. If you wish to perform certain
+cleanup actions once per document, then you should use B<end_pod()>.
+
+=cut
+
+sub end_input {
+ #my $self = shift;
+ #return;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<end_pod()>
+
+ $parser->end_pod();
+
+This method is invoked at the end of processing for each POD document
+that is encountered in the input. Subclasses should override this method
+to perform any per-document finalization.
+
+=cut
+
+sub end_pod {
+ #my $self = shift;
+ #return;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<preprocess_line()>
+
+ $textline = $parser->preprocess_line($text, $line_num);
+
+This method should be overridden by subclasses that wish to perform
+any kind of preprocessing for each I<line> of input (I<before> it has
+been determined whether or not it is part of a POD paragraph). The
+parameter C<$text> is the input line; and the parameter C<$line_num> is
+the line number of the corresponding text line.
+
+The value returned should correspond to the new text to use in its
+place. If the empty string or an undefined value is returned then no
+further processing will be performed for this line.
+
+Please note that the B<preprocess_line()> method is invoked I<before>
+the B<preprocess_paragraph()> method. After all (possibly preprocessed)
+lines in a paragraph have been assembled together and it has been
+determined that the paragraph is part of the POD documentation from one
+of the selected sections, then B<preprocess_paragraph()> is invoked.
+
+The base class implementation of this method returns the given text.
+
+=cut
+
+sub preprocess_line {
+ my ($self, $text, $line_num) = @_;
+ return $text;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<preprocess_paragraph()>
+
+ $textblock = $parser->preprocess_paragraph($text, $line_num);
+
+This method should be overridden by subclasses that wish to perform any
+kind of preprocessing for each block (paragraph) of POD documentation
+that appears in the input stream. The parameter C<$text> is the POD
+paragraph from the input file; and the parameter C<$line_num> is the
+line number for the beginning of the corresponding paragraph.
+
+The value returned should correspond to the new text to use in its
+place If the empty string is returned or an undefined value is
+returned, then the given C<$text> is ignored (not processed).
+
+This method is invoked after gathering up all the lines in a paragraph
+and after determining the cutting state of the paragraph,
+but before trying to further parse or interpret them. After
+B<preprocess_paragraph()> returns, the current cutting state (which
+is returned by C<$self-E<gt>cutting()>) is examined. If it evaluates
+to true then input text (including the given C<$text>) is cut (not
+processed) until the next POD directive is encountered.
+
+Please note that the B<preprocess_line()> method is invoked I<before>
+the B<preprocess_paragraph()> method. After all (possibly preprocessed)
+lines in a paragraph have been assembled together and either it has been
+determined that the paragraph is part of the POD documentation from one
+of the selected sections or the C<-want_nonPODs> option is true,
+then B<preprocess_paragraph()> is invoked.
+
+The base class implementation of this method returns the given text.
+
+=cut
+
+sub preprocess_paragraph {
+ my ($self, $text, $line_num) = @_;
+ return $text;
+}
+
+#############################################################################
+
+=head1 METHODS FOR PARSING AND PROCESSING
+
+B<Pod::Parser> provides several methods to process input text. These
+methods typically won't need to be overridden (and in some cases they
+can't be overridden), but subclasses may want to invoke them to exploit
+their functionality.
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=head1 B<parse_text()>
+
+ $ptree1 = $parser->parse_text($text, $line_num);
+ $ptree2 = $parser->parse_text({%opts}, $text, $line_num);
+ $ptree3 = $parser->parse_text(\%opts, $text, $line_num);
+
+This method is useful if you need to perform your own interpolation
+of interior sequences and can't rely upon B<interpolate> to expand
+them in simple bottom-up order.
+
+The parameter C<$text> is a string or block of text to be parsed
+for interior sequences; and the parameter C<$line_num> is the
+line number curresponding to the beginning of C<$text>.
+
+B<parse_text()> will parse the given text into a parse-tree of "nodes."
+and interior-sequences. Each "node" in the parse tree is either a
+text-string, or a B<Pod::InteriorSequence>. The result returned is a
+parse-tree of type B<Pod::ParseTree>. Please see L<Pod::InputObjects>
+for more information about B<Pod::InteriorSequence> and B<Pod::ParseTree>.
+
+If desired, an optional hash-ref may be specified as the first argument
+to customize certain aspects of the parse-tree that is created and
+returned. The set of recognized option keywords are:
+
+=over 3
+
+=item B<-expand_seq> =E<gt> I<code-ref>|I<method-name>
+
+Normally, the parse-tree returned by B<parse_text()> will contain an
+unexpanded C<Pod::InteriorSequence> object for each interior-sequence
+encountered. Specifying B<-expand_seq> tells B<parse_text()> to "expand"
+every interior-sequence it sees by invoking the referenced function
+(or named method of the parser object) and using the return value as the
+expanded result.
+
+If a subroutine reference was given, it is invoked as:
+
+ &$code_ref( $parser, $sequence )
+
+and if a method-name was given, it is invoked as:
+
+ $parser->method_name( $sequence )
+
+where C<$parser> is a reference to the parser object, and C<$sequence>
+is a reference to the interior-sequence object.
+[I<NOTE>: If the B<interior_sequence()> method is specified, then it is
+invoked according to the interface specified in L<"interior_sequence()">].
+
+=item B<-expand_text> =E<gt> I<code-ref>|I<method-name>
+
+Normally, the parse-tree returned by B<parse_text()> will contain a
+text-string for each contiguous sequence of characters outside of an
+interior-sequence. Specifying B<-expand_text> tells B<parse_text()> to
+"preprocess" every such text-string it sees by invoking the referenced
+function (or named method of the parser object) and using the return value
+as the preprocessed (or "expanded") result. [Note that if the result is
+an interior-sequence, then it will I<not> be expanded as specified by the
+B<-expand_seq> option; Any such recursive expansion needs to be handled by
+the specified callback routine.]
+
+If a subroutine reference was given, it is invoked as:
+
+ &$code_ref( $parser, $text, $ptree_node )
+
+and if a method-name was given, it is invoked as:
+
+ $parser->method_name( $text, $ptree_node )
+
+where C<$parser> is a reference to the parser object, C<$text> is the
+text-string encountered, and C<$ptree_node> is a reference to the current
+node in the parse-tree (usually an interior-sequence object or else the
+top-level node of the parse-tree).
+
+=item B<-expand_ptree> =E<gt> I<code-ref>|I<method-name>
+
+Rather than returning a C<Pod::ParseTree>, pass the parse-tree as an
+argument to the referenced subroutine (or named method of the parser
+object) and return the result instead of the parse-tree object.
+
+If a subroutine reference was given, it is invoked as:
+
+ &$code_ref( $parser, $ptree )
+
+and if a method-name was given, it is invoked as:
+
+ $parser->method_name( $ptree )
+
+where C<$parser> is a reference to the parser object, and C<$ptree>
+is a reference to the parse-tree object.
+
+=back
+
+=cut
+
+sub parse_text {
+ my $self = shift;
+ local $_ = '';
+
+ ## Get options and set any defaults
+ my %opts = (ref $_[0]) ? %{ shift() } : ();
+ my $expand_seq = $opts{'-expand_seq'} || undef;
+ my $expand_text = $opts{'-expand_text'} || undef;
+ my $expand_ptree = $opts{'-expand_ptree'} || undef;
+
+ my $text = shift;
+ my $line = shift;
+ my $file = $self->input_file();
+ my $cmd = "";
+
+ ## Convert method calls into closures, for our convenience
+ my $xseq_sub = $expand_seq;
+ my $xtext_sub = $expand_text;
+ my $xptree_sub = $expand_ptree;
+ if (defined $expand_seq and $expand_seq eq 'interior_sequence') {
+ ## If 'interior_sequence' is the method to use, we have to pass
+ ## more than just the sequence object, we also need to pass the
+ ## sequence name and text.
+ $xseq_sub = sub {
+ my ($self, $iseq) = @_;
+ my $args = join("", $iseq->parse_tree->children);
+ return $self->interior_sequence($iseq->name, $args, $iseq);
+ };
+ }
+ ref $xseq_sub or $xseq_sub = sub { shift()->$expand_seq(@_) };
+ ref $xtext_sub or $xtext_sub = sub { shift()->$expand_text(@_) };
+ ref $xptree_sub or $xptree_sub = sub { shift()->$expand_ptree(@_) };
+
+ ## Keep track of the "current" interior sequence, and maintain a stack
+ ## of "in progress" sequences.
+ ##
+ ## NOTE that we push our own "accumulator" at the very beginning of the
+ ## stack. It's really a parse-tree, not a sequence; but it implements
+ ## the methods we need so we can use it to gather-up all the sequences
+ ## and strings we parse. Thus, by the end of our parsing, it should be
+ ## the only thing left on our stack and all we have to do is return it!
+ ##
+ my $seq = Pod::ParseTree->new();
+ my @seq_stack = ($seq);
+ my ($ldelim, $rdelim) = ('', '');
+
+ ## Iterate over all sequence starts text (NOTE: split with
+ ## capturing parens keeps the delimiters)
+ $_ = $text;
+ my @tokens = split /([A-Z]<(?:<+\s)?)/;
+ while ( @tokens ) {
+ $_ = shift @tokens;
+ ## Look for the beginning of a sequence
+ if ( /^([A-Z])(<(?:<+\s)?)$/ ) {
+ ## Push a new sequence onto the stack of those "in-progress"
+ my $ldelim_orig;
+ ($cmd, $ldelim_orig) = ($1, $2);
+ ($ldelim = $ldelim_orig) =~ s/\s+$//;
+ ($rdelim = $ldelim) =~ tr/</>/;
+ $seq = Pod::InteriorSequence->new(
+ -name => $cmd,
+ -ldelim => $ldelim_orig, -rdelim => $rdelim,
+ -file => $file, -line => $line
+ );
+ (@seq_stack > 1) and $seq->nested($seq_stack[-1]);
+ push @seq_stack, $seq;
+ }
+ ## Look for sequence ending
+ elsif ( @seq_stack > 1 ) {
+ ## Make sure we match the right kind of closing delimiter
+ my ($seq_end, $post_seq) = ("", "");
+ if ( ($ldelim eq '<' and /\A(.*?)(>)/s)
+ or /\A(.*?)(\s+$rdelim)/s )
+ {
+ ## Found end-of-sequence, capture the interior and the
+ ## closing the delimiter, and put the rest back on the
+ ## token-list
+ $post_seq = substr($_, length($1) + length($2));
+ ($_, $seq_end) = ($1, $2);
+ (length $post_seq) and unshift @tokens, $post_seq;
+ }
+ if (length) {
+ ## In the middle of a sequence, append this text to it, and
+ ## dont forget to "expand" it if that's what the caller wanted
+ $seq->append($expand_text ? &$xtext_sub($self,$_,$seq) : $_);
+ $_ .= $seq_end;
+ }
+ if (length $seq_end) {
+ ## End of current sequence, record terminating delimiter
+ $seq->rdelim($seq_end);
+ ## Pop it off the stack of "in progress" sequences
+ pop @seq_stack;
+ ## Append result to its parent in current parse tree
+ $seq_stack[-1]->append($expand_seq ? &$xseq_sub($self,$seq)
+ : $seq);
+ ## Remember the current cmd-name and left-delimiter
+ if(@seq_stack > 1) {
+ $cmd = $seq_stack[-1]->name;
+ $ldelim = $seq_stack[-1]->ldelim;
+ $rdelim = $seq_stack[-1]->rdelim;
+ } else {
+ $cmd = $ldelim = $rdelim = '';
+ }
+ }
+ }
+ elsif (length) {
+ ## In the middle of a sequence, append this text to it, and
+ ## dont forget to "expand" it if that's what the caller wanted
+ $seq->append($expand_text ? &$xtext_sub($self,$_,$seq) : $_);
+ }
+ ## Keep track of line count
+ $line += tr/\n//;
+ ## Remember the "current" sequence
+ $seq = $seq_stack[-1];
+ }
+
+ ## Handle unterminated sequences
+ my $errorsub = (@seq_stack > 1) ? $self->errorsub() : undef;
+ while (@seq_stack > 1) {
+ ($cmd, $file, $line) = ($seq->name, $seq->file_line);
+ $ldelim = $seq->ldelim;
+ ($rdelim = $ldelim) =~ tr/</>/;
+ $rdelim =~ s/^(\S+)(\s*)$/$2$1/;
+ pop @seq_stack;
+ my $errmsg = "*** ERROR: unterminated ${cmd}${ldelim}...${rdelim}".
+ " at line $line in file $file\n";
+ (ref $errorsub) and &{$errorsub}($errmsg)
+ or (defined $errorsub) and $self->$errorsub($errmsg)
+ or warn($errmsg);
+ $seq_stack[-1]->append($expand_seq ? &$xseq_sub($self,$seq) : $seq);
+ $seq = $seq_stack[-1];
+ }
+
+ ## Return the resulting parse-tree
+ my $ptree = (pop @seq_stack)->parse_tree;
+ return $expand_ptree ? &$xptree_sub($self, $ptree) : $ptree;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<interpolate()>
+
+ $textblock = $parser->interpolate($text, $line_num);
+
+This method translates all text (including any embedded interior sequences)
+in the given text string C<$text> and returns the interpolated result. The
+parameter C<$line_num> is the line number corresponding to the beginning
+of C<$text>.
+
+B<interpolate()> merely invokes a private method to recursively expand
+nested interior sequences in bottom-up order (innermost sequences are
+expanded first). If there is a need to expand nested sequences in
+some alternate order, use B<parse_text> instead.
+
+=cut
+
+sub interpolate {
+ my($self, $text, $line_num) = @_;
+ my %parse_opts = ( -expand_seq => 'interior_sequence' );
+ my $ptree = $self->parse_text( \%parse_opts, $text, $line_num );
+ return join "", $ptree->children();
+}
+
+##---------------------------------------------------------------------------
+
+=begin __PRIVATE__
+
+=head1 B<parse_paragraph()>
+
+ $parser->parse_paragraph($text, $line_num);
+
+This method takes the text of a POD paragraph to be processed, along
+with its corresponding line number, and invokes the appropriate method
+(one of B<command()>, B<verbatim()>, or B<textblock()>).
+
+For performance reasons, this method is invoked directly without any
+dynamic lookup; Hence subclasses may I<not> override it!
+
+=end __PRIVATE__
+
+=cut
+
+sub parse_paragraph {
+ my ($self, $text, $line_num) = @_;
+ local *myData = $self; ## alias to avoid deref-ing overhead
+ local *myOpts = ($myData{_PARSEOPTS} ||= {}); ## get parse-options
+ local $_;
+
+ ## See if we want to preprocess nonPOD paragraphs as well as POD ones.
+ my $wantNonPods = $myOpts{'-want_nonPODs'};
+
+ ## Update cutting status
+ $myData{_CUTTING} = 0 if $text =~ /^={1,2}\S/;
+
+ ## Perform any desired preprocessing if we wanted it this early
+ $wantNonPods and $text = $self->preprocess_paragraph($text, $line_num);
+
+ ## Ignore up until next POD directive if we are cutting
+ return if $myData{_CUTTING};
+
+ ## Now we know this is block of text in a POD section!
+
+ ##-----------------------------------------------------------------
+ ## This is a hook (hack ;-) for Pod::Select to do its thing without
+ ## having to override methods, but also without Pod::Parser assuming
+ ## $self is an instance of Pod::Select (if the _SELECTED_SECTIONS
+ ## field exists then we assume there is an is_selected() method for
+ ## us to invoke (calling $self->can('is_selected') could verify this
+ ## but that is more overhead than I want to incur)
+ ##-----------------------------------------------------------------
+
+ ## Ignore this block if it isnt in one of the selected sections
+ if (exists $myData{_SELECTED_SECTIONS}) {
+ $self->is_selected($text) or return ($myData{_CUTTING} = 1);
+ }
+
+ ## If we havent already, perform any desired preprocessing and
+ ## then re-check the "cutting" state
+ unless ($wantNonPods) {
+ $text = $self->preprocess_paragraph($text, $line_num);
+ return 1 unless ((defined $text) and (length $text));
+ return 1 if ($myData{_CUTTING});
+ }
+
+ ## Look for one of the three types of paragraphs
+ my ($pfx, $cmd, $arg, $sep) = ('', '', '', '');
+ my $pod_para = undef;
+ if ($text =~ /^(={1,2})(?=\S)/) {
+ ## Looks like a command paragraph. Capture the command prefix used
+ ## ("=" or "=="), as well as the command-name, its paragraph text,
+ ## and whatever sequence of characters was used to separate them
+ $pfx = $1;
+ $_ = substr($text, length $pfx);
+ ($cmd, $sep, $text) = split /(\s+)/, $_, 2;
+ ## If this is a "cut" directive then we dont need to do anything
+ ## except return to "cutting" mode.
+ if ($cmd eq 'cut') {
+ $myData{_CUTTING} = 1;
+ return unless $myOpts{'-process_cut_cmd'};
+ }
+ }
+ ## Save the attributes indicating how the command was specified.
+ $pod_para = new Pod::Paragraph(
+ -name => $cmd,
+ -text => $text,
+ -prefix => $pfx,
+ -separator => $sep,
+ -file => $myData{_INFILE},
+ -line => $line_num
+ );
+ # ## Invoke appropriate callbacks
+ # if (exists $myData{_CALLBACKS}) {
+ # ## Look through the callback list, invoke callbacks,
+ # ## then see if we need to do the default actions
+ # ## (invoke_callbacks will return true if we do).
+ # return 1 unless $self->invoke_callbacks($cmd, $text, $line_num, $pod_para);
+ # }
+ if (length $cmd) {
+ ## A command paragraph
+ $self->command($cmd, $text, $line_num, $pod_para);
+ }
+ elsif ($text =~ /^\s+/) {
+ ## Indented text - must be a verbatim paragraph
+ $self->verbatim($text, $line_num, $pod_para);
+ }
+ else {
+ ## Looks like an ordinary block of text
+ $self->textblock($text, $line_num, $pod_para);
+ }
+ return 1;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<parse_from_filehandle()>
+
+ $parser->parse_from_filehandle($in_fh,$out_fh);
+
+This method takes an input filehandle (which is assumed to already be
+opened for reading) and reads the entire input stream looking for blocks
+(paragraphs) of POD documentation to be processed. If no first argument
+is given the default input filehandle C<STDIN> is used.
+
+The C<$in_fh> parameter may be any object that provides a B<getline()>
+method to retrieve a single line of input text (hence, an appropriate
+wrapper object could be used to parse PODs from a single string or an
+array of strings).
+
+Using C<$in_fh-E<gt>getline()>, input is read line-by-line and assembled
+into paragraphs or "blocks" (which are separated by lines containing
+nothing but whitespace). For each block of POD documentation
+encountered it will invoke a method to parse the given paragraph.
+
+If a second argument is given then it should correspond to a filehandle where
+output should be sent (otherwise the default output filehandle is
+C<STDOUT> if no output filehandle is currently in use).
+
+B<NOTE:> For performance reasons, this method caches the input stream at
+the top of the stack in a local variable. Any attempts by clients to
+change the stack contents during processing when in the midst executing
+of this method I<will not affect> the input stream used by the current
+invocation of this method.
+
+This method does I<not> usually need to be overridden by subclasses.
+
+=cut
+
+sub parse_from_filehandle {
+ my $self = shift;
+ my %opts = (ref $_[0] eq 'HASH') ? %{ shift() } : ();
+ my ($in_fh, $out_fh) = @_;
+ $in_fh = \*STDIN unless ($in_fh);
+ local *myData = $self; ## alias to avoid deref-ing overhead
+ local *myOpts = ($myData{_PARSEOPTS} ||= {}); ## get parse-options
+ local $_;
+
+ ## Put this stream at the top of the stack and do beginning-of-input
+ ## processing. NOTE that $in_fh might be reset during this process.
+ my $topstream = $self->_push_input_stream($in_fh, $out_fh);
+ (exists $opts{-cutting}) and $self->cutting( $opts{-cutting} );
+
+ ## Initialize line/paragraph
+ my ($textline, $paragraph) = ('', '');
+ my ($nlines, $plines) = (0, 0);
+
+ ## Use <$fh> instead of $fh->getline where possible (for speed)
+ $_ = ref $in_fh;
+ my $tied_fh = (/^(?:GLOB|FileHandle|IO::\w+)$/ or tied $in_fh);
+
+ ## Read paragraphs line-by-line
+ while (defined ($textline = $tied_fh ? <$in_fh> : $in_fh->getline)) {
+ $textline = $self->preprocess_line($textline, ++$nlines);
+ next unless ((defined $textline) && (length $textline));
+
+ if ((! length $paragraph) && ($textline =~ /^==/)) {
+ ## '==' denotes a one-line command paragraph
+ $paragraph = $textline;
+ $plines = 1;
+ $textline = '';
+ } else {
+ ## Append this line to the current paragraph
+ $paragraph .= $textline;
+ ++$plines;
+ }
+
+ ## See if this line is blank and ends the current paragraph.
+ ## If it isnt, then keep iterating until it is.
+ next unless (($textline =~ /^([^\S\r\n]*)[\r\n]*$/)
+ && (length $paragraph));
+
+ ## Issue a warning about any non-empty blank lines
+ if (length($1) > 0 and $myOpts{'-warnings'} and ! $myData{_CUTTING}) {
+ my $errorsub = $self->errorsub();
+ my $file = $self->input_file();
+ my $errmsg = "*** WARNING: line containing nothing but whitespace".
+ " in paragraph at line $nlines in file $file\n";
+ (ref $errorsub) and &{$errorsub}($errmsg)
+ or (defined $errorsub) and $self->$errorsub($errmsg)
+ or warn($errmsg);
+ }
+
+ ## Now process the paragraph
+ parse_paragraph($self, $paragraph, ($nlines - $plines) + 1);
+ $paragraph = '';
+ $plines = 0;
+ }
+ ## Dont forget about the last paragraph in the file
+ if (length $paragraph) {
+ parse_paragraph($self, $paragraph, ($nlines - $plines) + 1)
+ }
+
+ ## Now pop the input stream off the top of the input stack.
+ $self->_pop_input_stream();
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<parse_from_file()>
+
+ $parser->parse_from_file($filename,$outfile);
+
+This method takes a filename and does the following:
+
+=over 2
+
+=item *
+
+opens the input and output files for reading
+(creating the appropriate filehandles)
+
+=item *
+
+invokes the B<parse_from_filehandle()> method passing it the
+corresponding input and output filehandles.
+
+=item *
+
+closes the input and output files.
+
+=back
+
+If the special input filename "-" or "<&STDIN" is given then the STDIN
+filehandle is used for input (and no open or close is performed). If no
+input filename is specified then "-" is implied.
+
+If a second argument is given then it should be the name of the desired
+output file. If the special output filename "-" or ">&STDOUT" is given
+then the STDOUT filehandle is used for output (and no open or close is
+performed). If the special output filename ">&STDERR" is given then the
+STDERR filehandle is used for output (and no open or close is
+performed). If no output filehandle is currently in use and no output
+filename is specified, then "-" is implied.
+Alternatively, an L<IO::String> object is also accepted as an output
+file handle.
+
+This method does I<not> usually need to be overridden by subclasses.
+
+=cut
+
+sub parse_from_file {
+ my $self = shift;
+ my %opts = (ref $_[0] eq 'HASH') ? %{ shift() } : ();
+ my ($infile, $outfile) = @_;
+ my ($in_fh, $out_fh) = (gensym(), gensym()) if ($] < 5.006);
+ my ($close_input, $close_output) = (0, 0);
+ local *myData = $self;
+ local *_;
+
+ ## Is $infile a filename or a (possibly implied) filehandle
+ if (defined $infile && ref $infile) {
+ if (ref($infile) =~ /^(SCALAR|ARRAY|HASH|CODE|REF)$/) {
+ croak "Input from $1 reference not supported!\n";
+ }
+ ## Must be a filehandle-ref (or else assume its a ref to an object
+ ## that supports the common IO read operations).
+ $myData{_INFILE} = ${$infile};
+ $in_fh = $infile;
+ }
+ elsif (!defined($infile) || !length($infile) || ($infile eq '-')
+ || ($infile =~ /^<&(?:STDIN|0)$/i))
+ {
+ ## Not a filename, just a string implying STDIN
+ $infile ||= '-';
+ $myData{_INFILE} = "<standard input>";
+ $in_fh = \*STDIN;
+ }
+ else {
+ ## We have a filename, open it for reading
+ $myData{_INFILE} = $infile;
+ open($in_fh, "< $infile") or
+ croak "Can't open $infile for reading: $!\n";
+ $close_input = 1;
+ }
+
+ ## NOTE: we need to be *very* careful when "defaulting" the output
+ ## file. We only want to use a default if this is the beginning of
+ ## the entire document (but *not* if this is an included file). We
+ ## determine this by seeing if the input stream stack has been set-up
+ ## already
+
+ ## Is $outfile a filename, a (possibly implied) filehandle, maybe a ref?
+ if (ref $outfile) {
+ ## we need to check for ref() first, as other checks involve reading
+ if (ref($outfile) =~ /^(ARRAY|HASH|CODE)$/) {
+ croak "Output to $1 reference not supported!\n";
+ }
+ elsif (ref($outfile) eq 'SCALAR') {
+# # NOTE: IO::String isn't a part of the perl distribution,
+# # so probably we shouldn't support this case...
+# require IO::String;
+# $myData{_OUTFILE} = "$outfile";
+# $out_fh = IO::String->new($outfile);
+ croak "Output to SCALAR reference not supported!\n";
+ }
+ else {
+ ## Must be a filehandle-ref (or else assume its a ref to an
+ ## object that supports the common IO write operations).
+ $myData{_OUTFILE} = ${$outfile};
+ $out_fh = $outfile;
+ }
+ }
+ elsif (!defined($outfile) || !length($outfile) || ($outfile eq '-')
+ || ($outfile =~ /^>&?(?:STDOUT|1)$/i))
+ {
+ if (defined $myData{_TOP_STREAM}) {
+ $out_fh = $myData{_OUTPUT};
+ }
+ else {
+ ## Not a filename, just a string implying STDOUT
+ $outfile ||= '-';
+ $myData{_OUTFILE} = "<standard output>";
+ $out_fh = \*STDOUT;
+ }
+ }
+ elsif ($outfile =~ /^>&(STDERR|2)$/i) {
+ ## Not a filename, just a string implying STDERR
+ $myData{_OUTFILE} = "<standard error>";
+ $out_fh = \*STDERR;
+ }
+ else {
+ ## We have a filename, open it for writing
+ $myData{_OUTFILE} = $outfile;
+ (-d $outfile) and croak "$outfile is a directory, not POD input!\n";
+ open($out_fh, "> $outfile") or
+ croak "Can't open $outfile for writing: $!\n";
+ $close_output = 1;
+ }
+
+ ## Whew! That was a lot of work to set up reasonably/robust behavior
+ ## in the case of a non-filename for reading and writing. Now we just
+ ## have to parse the input and close the handles when we're finished.
+ $self->parse_from_filehandle(\%opts, $in_fh, $out_fh);
+
+ $close_input and
+ close($in_fh) || croak "Can't close $infile after reading: $!\n";
+ $close_output and
+ close($out_fh) || croak "Can't close $outfile after writing: $!\n";
+}
+
+#############################################################################
+
+=head1 ACCESSOR METHODS
+
+Clients of B<Pod::Parser> should use the following methods to access
+instance data fields:
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=head1 B<errorsub()>
+
+ $parser->errorsub("method_name");
+ $parser->errorsub(\&warn_user);
+ $parser->errorsub(sub { print STDERR, @_ });
+
+Specifies the method or subroutine to use when printing error messages
+about POD syntax. The supplied method/subroutine I<must> return TRUE upon
+successful printing of the message. If C<undef> is given, then the B<warn>
+builtin is used to issue error messages (this is the default behavior).
+
+ my $errorsub = $parser->errorsub()
+ my $errmsg = "This is an error message!\n"
+ (ref $errorsub) and &{$errorsub}($errmsg)
+ or (defined $errorsub) and $parser->$errorsub($errmsg)
+ or warn($errmsg);
+
+Returns a method name, or else a reference to the user-supplied subroutine
+used to print error messages. Returns C<undef> if the B<warn> builtin
+is used to issue error messages (this is the default behavior).
+
+=cut
+
+sub errorsub {
+ return (@_ > 1) ? ($_[0]->{_ERRORSUB} = $_[1]) : $_[0]->{_ERRORSUB};
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<cutting()>
+
+ $boolean = $parser->cutting();
+
+Returns the current C<cutting> state: a boolean-valued scalar which
+evaluates to true if text from the input file is currently being "cut"
+(meaning it is I<not> considered part of the POD document).
+
+ $parser->cutting($boolean);
+
+Sets the current C<cutting> state to the given value and returns the
+result.
+
+=cut
+
+sub cutting {
+ return (@_ > 1) ? ($_[0]->{_CUTTING} = $_[1]) : $_[0]->{_CUTTING};
+}
+
+##---------------------------------------------------------------------------
+
+##---------------------------------------------------------------------------
+
+=head1 B<parseopts()>
+
+When invoked with no additional arguments, B<parseopts> returns a hashtable
+of all the current parsing options.
+
+ ## See if we are parsing non-POD sections as well as POD ones
+ my %opts = $parser->parseopts();
+ $opts{'-want_nonPODs}' and print "-want_nonPODs\n";
+
+When invoked using a single string, B<parseopts> treats the string as the
+name of a parse-option and returns its corresponding value if it exists
+(returns C<undef> if it doesn't).
+
+ ## Did we ask to see '=cut' paragraphs?
+ my $want_cut = $parser->parseopts('-process_cut_cmd');
+ $want_cut and print "-process_cut_cmd\n";
+
+When invoked with multiple arguments, B<parseopts> treats them as
+key/value pairs and the specified parse-option names are set to the
+given values. Any unspecified parse-options are unaffected.
+
+ ## Set them back to the default
+ $parser->parseopts(-warnings => 0);
+
+When passed a single hash-ref, B<parseopts> uses that hash to completely
+reset the existing parse-options, all previous parse-option values
+are lost.
+
+ ## Reset all options to default
+ $parser->parseopts( { } );
+
+See L<"PARSING OPTIONS"> for more information on the name and meaning of each
+parse-option currently recognized.
+
+=cut
+
+sub parseopts {
+ local *myData = shift;
+ local *myOpts = ($myData{_PARSEOPTS} ||= {});
+ return %myOpts if (@_ == 0);
+ if (@_ == 1) {
+ local $_ = shift;
+ return ref($_) ? $myData{_PARSEOPTS} = $_ : $myOpts{$_};
+ }
+ my @newOpts = (%myOpts, @_);
+ $myData{_PARSEOPTS} = { @newOpts };
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<output_file()>
+
+ $fname = $parser->output_file();
+
+Returns the name of the output file being written.
+
+=cut
+
+sub output_file {
+ return $_[0]->{_OUTFILE};
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<output_handle()>
+
+ $fhandle = $parser->output_handle();
+
+Returns the output filehandle object.
+
+=cut
+
+sub output_handle {
+ return $_[0]->{_OUTPUT};
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<input_file()>
+
+ $fname = $parser->input_file();
+
+Returns the name of the input file being read.
+
+=cut
+
+sub input_file {
+ return $_[0]->{_INFILE};
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<input_handle()>
+
+ $fhandle = $parser->input_handle();
+
+Returns the current input filehandle object.
+
+=cut
+
+sub input_handle {
+ return $_[0]->{_INPUT};
+}
+
+##---------------------------------------------------------------------------
+
+=begin __PRIVATE__
+
+=head1 B<input_streams()>
+
+ $listref = $parser->input_streams();
+
+Returns a reference to an array which corresponds to the stack of all
+the input streams that are currently in the middle of being parsed.
+
+While parsing an input stream, it is possible to invoke
+B<parse_from_file()> or B<parse_from_filehandle()> to parse a new input
+stream and then return to parsing the previous input stream. Each input
+stream to be parsed is pushed onto the end of this input stack
+before any of its input is read. The input stream that is currently
+being parsed is always at the end (or top) of the input stack. When an
+input stream has been exhausted, it is popped off the end of the
+input stack.
+
+Each element on this input stack is a reference to C<Pod::InputSource>
+object. Please see L<Pod::InputObjects> for more details.
+
+This method might be invoked when printing diagnostic messages, for example,
+to obtain the name and line number of the all input files that are currently
+being processed.
+
+=end __PRIVATE__
+
+=cut
+
+sub input_streams {
+ return $_[0]->{_INPUT_STREAMS};
+}
+
+##---------------------------------------------------------------------------
+
+=begin __PRIVATE__
+
+=head1 B<top_stream()>
+
+ $hashref = $parser->top_stream();
+
+Returns a reference to the hash-table that represents the element
+that is currently at the top (end) of the input stream stack
+(see L<"input_streams()">). The return value will be the C<undef>
+if the input stack is empty.
+
+This method might be used when printing diagnostic messages, for example,
+to obtain the name and line number of the current input file.
+
+=end __PRIVATE__
+
+=cut
+
+sub top_stream {
+ return $_[0]->{_TOP_STREAM} || undef;
+}
+
+#############################################################################
+
+=head1 PRIVATE METHODS AND DATA
+
+B<Pod::Parser> makes use of several internal methods and data fields
+which clients should not need to see or use. For the sake of avoiding
+name collisions for client data and methods, these methods and fields
+are briefly discussed here. Determined hackers may obtain further
+information about them by reading the B<Pod::Parser> source code.
+
+Private data fields are stored in the hash-object whose reference is
+returned by the B<new()> constructor for this class. The names of all
+private methods and data-fields used by B<Pod::Parser> begin with a
+prefix of "_" and match the regular expression C</^_\w+$/>.
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=begin _PRIVATE_
+
+=head1 B<_push_input_stream()>
+
+ $hashref = $parser->_push_input_stream($in_fh,$out_fh);
+
+This method will push the given input stream on the input stack and
+perform any necessary beginning-of-document or beginning-of-file
+processing. The argument C<$in_fh> is the input stream filehandle to
+push, and C<$out_fh> is the corresponding output filehandle to use (if
+it is not given or is undefined, then the current output stream is used,
+which defaults to standard output if it doesnt exist yet).
+
+The value returned will be reference to the hash-table that represents
+the new top of the input stream stack. I<Please Note> that it is
+possible for this method to use default values for the input and output
+file handles. If this happens, you will need to look at the C<INPUT>
+and C<OUTPUT> instance data members to determine their new values.
+
+=end _PRIVATE_
+
+=cut
+
+sub _push_input_stream {
+ my ($self, $in_fh, $out_fh) = @_;
+ local *myData = $self;
+
+ ## Initialize stuff for the entire document if this is *not*
+ ## an included file.
+ ##
+ ## NOTE: we need to be *very* careful when "defaulting" the output
+ ## filehandle. We only want to use a default value if this is the
+ ## beginning of the entire document (but *not* if this is an included
+ ## file).
+ unless (defined $myData{_TOP_STREAM}) {
+ $out_fh = \*STDOUT unless (defined $out_fh);
+ $myData{_CUTTING} = 1; ## current "cutting" state
+ $myData{_INPUT_STREAMS} = []; ## stack of all input streams
+ }
+
+ ## Initialize input indicators
+ $myData{_OUTFILE} = '(unknown)' unless (defined $myData{_OUTFILE});
+ $myData{_OUTPUT} = $out_fh if (defined $out_fh);
+ $in_fh = \*STDIN unless (defined $in_fh);
+ $myData{_INFILE} = '(unknown)' unless (defined $myData{_INFILE});
+ $myData{_INPUT} = $in_fh;
+ my $input_top = $myData{_TOP_STREAM}
+ = new Pod::InputSource(
+ -name => $myData{_INFILE},
+ -handle => $in_fh,
+ -was_cutting => $myData{_CUTTING}
+ );
+ local *input_stack = $myData{_INPUT_STREAMS};
+ push(@input_stack, $input_top);
+
+ ## Perform beginning-of-document and/or beginning-of-input processing
+ $self->begin_pod() if (@input_stack == 1);
+ $self->begin_input();
+
+ return $input_top;
+}
+
+##---------------------------------------------------------------------------
+
+=begin _PRIVATE_
+
+=head1 B<_pop_input_stream()>
+
+ $hashref = $parser->_pop_input_stream();
+
+This takes no arguments. It will perform any necessary end-of-file or
+end-of-document processing and then pop the current input stream from
+the top of the input stack.
+
+The value returned will be reference to the hash-table that represents
+the new top of the input stream stack.
+
+=end _PRIVATE_
+
+=cut
+
+sub _pop_input_stream {
+ my ($self) = @_;
+ local *myData = $self;
+ local *input_stack = $myData{_INPUT_STREAMS};
+
+ ## Perform end-of-input and/or end-of-document processing
+ $self->end_input() if (@input_stack > 0);
+ $self->end_pod() if (@input_stack == 1);
+
+ ## Restore cutting state to whatever it was before we started
+ ## parsing this file.
+ my $old_top = pop(@input_stack);
+ $myData{_CUTTING} = $old_top->was_cutting();
+
+ ## Dont forget to reset the input indicators
+ my $input_top = undef;
+ if (@input_stack > 0) {
+ $input_top = $myData{_TOP_STREAM} = $input_stack[-1];
+ $myData{_INFILE} = $input_top->name();
+ $myData{_INPUT} = $input_top->handle();
+ } else {
+ delete $myData{_TOP_STREAM};
+ delete $myData{_INPUT_STREAMS};
+ }
+
+ return $input_top;
+}
+
+#############################################################################
+
+=head1 TREE-BASED PARSING
+
+If straightforward stream-based parsing wont meet your needs (as is
+likely the case for tasks such as translating PODs into structured
+markup languages like HTML and XML) then you may need to take the
+tree-based approach. Rather than doing everything in one pass and
+calling the B<interpolate()> method to expand sequences into text, it
+may be desirable to instead create a parse-tree using the B<parse_text()>
+method to return a tree-like structure which may contain an ordered
+list of children (each of which may be a text-string, or a similar
+tree-like structure).
+
+Pay special attention to L<"METHODS FOR PARSING AND PROCESSING"> and
+to the objects described in L<Pod::InputObjects>. The former describes
+the gory details and parameters for how to customize and extend the
+parsing behavior of B<Pod::Parser>. B<Pod::InputObjects> provides
+several objects that may all be used interchangeably as parse-trees. The
+most obvious one is the B<Pod::ParseTree> object. It defines the basic
+interface and functionality that all things trying to be a POD parse-tree
+should do. A B<Pod::ParseTree> is defined such that each "node" may be a
+text-string, or a reference to another parse-tree. Each B<Pod::Paragraph>
+object and each B<Pod::InteriorSequence> object also supports the basic
+parse-tree interface.
+
+The B<parse_text()> method takes a given paragraph of text, and
+returns a parse-tree that contains one or more children, each of which
+may be a text-string, or an InteriorSequence object. There are also
+callback-options that may be passed to B<parse_text()> to customize
+the way it expands or transforms interior-sequences, as well as the
+returned result. These callbacks can be used to create a parse-tree
+with custom-made objects (which may or may not support the parse-tree
+interface, depending on how you choose to do it).
+
+If you wish to turn an entire POD document into a parse-tree, that process
+is fairly straightforward. The B<parse_text()> method is the key to doing
+this successfully. Every paragraph-callback (i.e. the polymorphic methods
+for B<command()>, B<verbatim()>, and B<textblock()> paragraphs) takes
+a B<Pod::Paragraph> object as an argument. Each paragraph object has a
+B<parse_tree()> method that can be used to get or set a corresponding
+parse-tree. So for each of those paragraph-callback methods, simply call
+B<parse_text()> with the options you desire, and then use the returned
+parse-tree to assign to the given paragraph object.
+
+That gives you a parse-tree for each paragraph - so now all you need is
+an ordered list of paragraphs. You can maintain that yourself as a data
+element in the object/hash. The most straightforward way would be simply
+to use an array-ref, with the desired set of custom "options" for each
+invocation of B<parse_text>. Let's assume the desired option-set is
+given by the hash C<%options>. Then we might do something like the
+following:
+
+ package MyPodParserTree;
+
+ @ISA = qw( Pod::Parser );
+
+ ...
+
+ sub begin_pod {
+ my $self = shift;
+ $self->{'-paragraphs'} = []; ## initialize paragraph list
+ }
+
+ sub command {
+ my ($parser, $command, $paragraph, $line_num, $pod_para) = @_;
+ my $ptree = $parser->parse_text({%options}, $paragraph, ...);
+ $pod_para->parse_tree( $ptree );
+ push @{ $self->{'-paragraphs'} }, $pod_para;
+ }
+
+ sub verbatim {
+ my ($parser, $paragraph, $line_num, $pod_para) = @_;
+ push @{ $self->{'-paragraphs'} }, $pod_para;
+ }
+
+ sub textblock {
+ my ($parser, $paragraph, $line_num, $pod_para) = @_;
+ my $ptree = $parser->parse_text({%options}, $paragraph, ...);
+ $pod_para->parse_tree( $ptree );
+ push @{ $self->{'-paragraphs'} }, $pod_para;
+ }
+
+ ...
+
+ package main;
+ ...
+ my $parser = new MyPodParserTree(...);
+ $parser->parse_from_file(...);
+ my $paragraphs_ref = $parser->{'-paragraphs'};
+
+Of course, in this module-author's humble opinion, I'd be more inclined to
+use the existing B<Pod::ParseTree> object than a simple array. That way
+everything in it, paragraphs and sequences, all respond to the same core
+interface for all parse-tree nodes. The result would look something like:
+
+ package MyPodParserTree2;
+
+ ...
+
+ sub begin_pod {
+ my $self = shift;
+ $self->{'-ptree'} = new Pod::ParseTree; ## initialize parse-tree
+ }
+
+ sub parse_tree {
+ ## convenience method to get/set the parse-tree for the entire POD
+ (@_ > 1) and $_[0]->{'-ptree'} = $_[1];
+ return $_[0]->{'-ptree'};
+ }
+
+ sub command {
+ my ($parser, $command, $paragraph, $line_num, $pod_para) = @_;
+ my $ptree = $parser->parse_text({<<options>>}, $paragraph, ...);
+ $pod_para->parse_tree( $ptree );
+ $parser->parse_tree()->append( $pod_para );
+ }
+
+ sub verbatim {
+ my ($parser, $paragraph, $line_num, $pod_para) = @_;
+ $parser->parse_tree()->append( $pod_para );
+ }
+
+ sub textblock {
+ my ($parser, $paragraph, $line_num, $pod_para) = @_;
+ my $ptree = $parser->parse_text({<<options>>}, $paragraph, ...);
+ $pod_para->parse_tree( $ptree );
+ $parser->parse_tree()->append( $pod_para );
+ }
+
+ ...
+
+ package main;
+ ...
+ my $parser = new MyPodParserTree2(...);
+ $parser->parse_from_file(...);
+ my $ptree = $parser->parse_tree;
+ ...
+
+Now you have the entire POD document as one great big parse-tree. You
+can even use the B<-expand_seq> option to B<parse_text> to insert
+whole different kinds of objects. Just don't expect B<Pod::Parser>
+to know what to do with them after that. That will need to be in your
+code. Or, alternatively, you can insert any object you like so long as
+it conforms to the B<Pod::ParseTree> interface.
+
+One could use this to create subclasses of B<Pod::Paragraphs> and
+B<Pod::InteriorSequences> for specific commands (or to create your own
+custom node-types in the parse-tree) and add some kind of B<emit()>
+method to each custom node/subclass object in the tree. Then all you'd
+need to do is recursively walk the tree in the desired order, processing
+the children (most likely from left to right) by formatting them if
+they are text-strings, or by calling their B<emit()> method if they
+are objects/references.
+
+=head1 SEE ALSO
+
+L<Pod::InputObjects>, L<Pod::Select>
+
+B<Pod::InputObjects> defines POD input objects corresponding to
+command paragraphs, parse-trees, and interior-sequences.
+
+B<Pod::Select> is a subclass of B<Pod::Parser> which provides the ability
+to selectively include and/or exclude sections of a POD document from being
+translated based upon the current heading, subheading, subsubheading, etc.
+
+=for __PRIVATE__
+B<Pod::Callbacks> is a subclass of B<Pod::Parser> which gives its users
+the ability the employ I<callback functions> instead of, or in addition
+to, overriding methods of the base class.
+
+=for __PRIVATE__
+B<Pod::Select> and B<Pod::Callbacks> do not override any
+methods nor do they define any new methods with the same name. Because
+of this, they may I<both> be used (in combination) as a base class of
+the same subclass in order to combine their functionality without
+causing any namespace clashes due to multiple inheritance.
+
+=head1 AUTHOR
+
+Please report bugs using L<http://rt.cpan.org>.
+
+Brad Appleton E<lt>bradapp@enteract.comE<gt>
+
+Based on code for B<Pod::Text> written by
+Tom Christiansen E<lt>tchrist@mox.perl.comE<gt>
+
+=cut
+
+1;
+# vim: ts=4 sw=4 et
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc.pm
new file mode 100644
index 00000000000..8f9614838fb
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc.pm
@@ -0,0 +1,1762 @@
+
+require 5;
+use 5.006; # we use some open(X, "<", $y) syntax
+package Pod::Perldoc;
+use strict;
+use warnings;
+use Config '%Config';
+
+use Fcntl; # for sysopen
+use File::Spec::Functions qw(catfile catdir splitdir);
+
+use vars qw($VERSION @Pagers $Bindir $Pod2man
+ $Temp_Files_Created $Temp_File_Lifetime
+);
+$VERSION = '3.14';
+#..........................................................................
+
+BEGIN { # Make a DEBUG constant very first thing...
+ unless(defined &DEBUG) {
+ if(($ENV{'PERLDOCDEBUG'} || '') =~ m/^(\d+)/) { # untaint
+ eval("sub DEBUG () {$1}");
+ die "WHAT? Couldn't eval-up a DEBUG constant!? $@" if $@;
+ } else {
+ *DEBUG = sub () {0};
+ }
+ }
+}
+
+use Pod::Perldoc::GetOptsOO; # uses the DEBUG.
+
+#..........................................................................
+
+sub TRUE () {1}
+sub FALSE () {return}
+
+BEGIN {
+ *IS_VMS = $^O eq 'VMS' ? \&TRUE : \&FALSE unless defined &IS_VMS;
+ *IS_MSWin32 = $^O eq 'MSWin32' ? \&TRUE : \&FALSE unless defined &IS_MSWin32;
+ *IS_Dos = $^O eq 'dos' ? \&TRUE : \&FALSE unless defined &IS_Dos;
+ *IS_OS2 = $^O eq 'os2' ? \&TRUE : \&FALSE unless defined &IS_OS2;
+ *IS_Cygwin = $^O eq 'cygwin' ? \&TRUE : \&FALSE unless defined &IS_Cygwin;
+ *IS_Linux = $^O eq 'linux' ? \&TRUE : \&FALSE unless defined &IS_Linux;
+ *IS_HPUX = $^O =~ m/hpux/ ? \&TRUE : \&FALSE unless defined &IS_HPUX;
+}
+
+$Temp_File_Lifetime ||= 60 * 60 * 24 * 5;
+ # If it's older than five days, it's quite unlikely
+ # that anyone's still looking at it!!
+ # (Currently used only by the MSWin cleanup routine)
+
+
+#..........................................................................
+{ my $pager = $Config{'pager'};
+ push @Pagers, $pager if -x (split /\s+/, $pager)[0] or IS_VMS;
+}
+$Bindir = $Config{'scriptdirexp'};
+$Pod2man = "pod2man" . ( $Config{'versiononly'} ? $Config{'version'} : '' );
+
+# End of class-init stuff
+#
+###########################################################################
+#
+# Option accessors...
+
+foreach my $subname (map "opt_$_", split '', q{mhlvriFfXqnTdU}) {
+ no strict 'refs';
+ *$subname = do{ use strict 'refs'; sub () { shift->_elem($subname, @_) } };
+}
+
+# And these are so that GetOptsOO knows they take options:
+sub opt_f_with { shift->_elem('opt_f', @_) }
+sub opt_q_with { shift->_elem('opt_q', @_) }
+sub opt_d_with { shift->_elem('opt_d', @_) }
+
+sub opt_w_with { # Specify an option for the formatter subclass
+ my($self, $value) = @_;
+ if($value =~ m/^([-_a-zA-Z][-_a-zA-Z0-9]*)(?:[=\:](.*?))?$/s) {
+ my $option = $1;
+ my $option_value = defined($2) ? $2 : "TRUE";
+ $option =~ tr/\-/_/s; # tolerate "foo-bar" for "foo_bar"
+ $self->add_formatter_option( $option, $option_value );
+ } else {
+ warn "\"$value\" isn't a good formatter option name. I'm ignoring it!\n";
+ }
+ return;
+}
+
+sub opt_M_with { # specify formatter class name(s)
+ my($self, $classes) = @_;
+ return unless defined $classes and length $classes;
+ DEBUG > 4 and print "Considering new formatter classes -M$classes\n";
+ my @classes_to_add;
+ foreach my $classname (split m/[,;]+/s, $classes) {
+ next unless $classname =~ m/\S/;
+ if( $classname =~ m/^(\w+(::\w+)+)$/s ) {
+ # A mildly restrictive concept of what modulenames are valid.
+ push @classes_to_add, $1; # untaint
+ } else {
+ warn "\"$classname\" isn't a valid classname. Ignoring.\n";
+ }
+ }
+
+ unshift @{ $self->{'formatter_classes'} }, @classes_to_add;
+
+ DEBUG > 3 and print(
+ "Adding @classes_to_add to the list of formatter classes, "
+ . "making them @{ $self->{'formatter_classes'} }.\n"
+ );
+
+ return;
+}
+
+sub opt_V { # report version and exit
+ print join '',
+ "Perldoc v$VERSION, under perl v$] for $^O",
+
+ (defined(&Win32::BuildNumber) and defined &Win32::BuildNumber())
+ ? (" (win32 build ", &Win32::BuildNumber(), ")") : (),
+
+ (chr(65) eq 'A') ? () : " (non-ASCII)",
+
+ "\n",
+ ;
+ exit;
+}
+
+sub opt_t { # choose plaintext as output format
+ my $self = shift;
+ $self->opt_o_with('text') if @_ and $_[0];
+ return $self->_elem('opt_t', @_);
+}
+
+sub opt_u { # choose raw pod as output format
+ my $self = shift;
+ $self->opt_o_with('pod') if @_ and $_[0];
+ return $self->_elem('opt_u', @_);
+}
+
+sub opt_n_with {
+ # choose man as the output format, and specify the proggy to run
+ my $self = shift;
+ $self->opt_o_with('man') if @_ and $_[0];
+ $self->_elem('opt_n', @_);
+}
+
+sub opt_o_with { # "o" for output format
+ my($self, $rest) = @_;
+ return unless defined $rest and length $rest;
+ if($rest =~ m/^(\w+)$/s) {
+ $rest = $1; #untaint
+ } else {
+ warn "\"$rest\" isn't a valid output format. Skipping.\n";
+ return;
+ }
+
+ $self->aside("Noting \"$rest\" as desired output format...\n");
+
+ # Figure out what class(es) that could actually mean...
+
+ my @classes;
+ foreach my $prefix ("Pod::Perldoc::To", "Pod::Simple::", "Pod::") {
+ # Messy but smart:
+ foreach my $stem (
+ $rest, # Yes, try it first with the given capitalization
+ "\L$rest", "\L\u$rest", "\U$rest" # And then try variations
+
+ ) {
+ push @classes, $prefix . $stem;
+ #print "Considering $prefix$stem\n";
+ }
+
+ # Tidier, but misses too much:
+ #push @classes, $prefix . ucfirst(lc($rest));
+ }
+ $self->opt_M_with( join ";", @classes );
+ return;
+}
+
+###########################################################################
+# % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
+
+sub run { # to be called by the "perldoc" executable
+ my $class = shift;
+ if(DEBUG > 3) {
+ print "Parameters to $class\->run:\n";
+ my @x = @_;
+ while(@x) {
+ $x[1] = '<undef>' unless defined $x[1];
+ $x[1] = "@{$x[1]}" if ref( $x[1] ) eq 'ARRAY';
+ print " [$x[0]] => [$x[1]]\n";
+ splice @x,0,2;
+ }
+ print "\n";
+ }
+ return $class -> new(@_) -> process() || 0;
+}
+
+# % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
+###########################################################################
+
+sub new { # yeah, nothing fancy
+ my $class = shift;
+ my $new = bless {@_}, (ref($class) || $class);
+ DEBUG > 1 and print "New $class object $new\n";
+ $new->init();
+ $new;
+}
+
+#..........................................................................
+
+sub aside { # If we're in -v or DEBUG mode, say this.
+ my $self = shift;
+ if( DEBUG or $self->opt_v ) {
+ my $out = join( '',
+ DEBUG ? do {
+ my $callsub = (caller(1))[3];
+ my $package = quotemeta(__PACKAGE__ . '::');
+ $callsub =~ s/^$package/'/os;
+ # the o is justified, as $package really won't change.
+ $callsub . ": ";
+ } : '',
+ @_,
+ );
+ if(DEBUG) { print $out } else { print STDERR $out }
+ }
+ return;
+}
+
+#..........................................................................
+
+sub usage {
+ my $self = shift;
+ warn "@_\n" if @_;
+
+ # Erase evidence of previous errors (if any), so exit status is simple.
+ $! = 0;
+
+ die <<EOF;
+perldoc [options] PageName|ModuleName|ProgramName...
+perldoc [options] -f BuiltinFunction
+perldoc [options] -q FAQRegex
+
+Options:
+ -h Display this help message
+ -V report version
+ -r Recursive search (slow)
+ -i Ignore case
+ -t Display pod using pod2text instead of pod2man and nroff
+ (-t is the default on win32 unless -n is specified)
+ -u Display unformatted pod text
+ -m Display module's file in its entirety
+ -n Specify replacement for nroff
+ -l Display the module's file name
+ -F Arguments are file names, not modules
+ -v Verbosely describe what's going on
+ -T Send output to STDOUT without any pager
+ -d output_filename_to_send_to
+ -o output_format_name
+ -M FormatterModuleNameToUse
+ -w formatter_option:option_value
+ -X use index if present (looks for pod.idx at $Config{archlib})
+ -q Search the text of questions (not answers) in perlfaq[1-9]
+
+PageName|ModuleName...
+ is the name of a piece of documentation that you want to look at. You
+ may either give a descriptive name of the page (as in the case of
+ `perlfunc') the name of a module, either like `Term::Info' or like
+ `Term/Info', or the name of a program, like `perldoc'.
+
+BuiltinFunction
+ is the name of a perl function. Will extract documentation from
+ `perlfunc'.
+
+FAQRegex
+ is a regex. Will search perlfaq[1-9] for and extract any
+ questions that match.
+
+Any switches in the PERLDOC environment variable will be used before the
+command line arguments. The optional pod index file contains a list of
+filenames, one per line.
+ [Perldoc v$VERSION]
+EOF
+
+}
+
+#..........................................................................
+
+sub usage_brief {
+ my $me = $0; # Editing $0 is unportable
+
+ $me =~ s,.*[/\\],,; # get basename
+
+ die <<"EOUSAGE";
+Usage: $me [-h] [-V] [-r] [-i] [-v] [-t] [-u] [-m] [-n nroffer_program] [-l] [-T] [-d output_filename] [-o output_format] [-M FormatterModuleNameToUse] [-w formatter_option:option_value] [-F] [-X] PageName|ModuleName|ProgramName
+ $me -f PerlFunc
+ $me -q FAQKeywords
+
+The -h option prints more help. Also try "perldoc perldoc" to get
+acquainted with the system. [Perldoc v$VERSION]
+EOUSAGE
+
+}
+
+#..........................................................................
+
+sub pagers { @{ shift->{'pagers'} } }
+
+#..........................................................................
+
+sub _elem { # handy scalar meta-accessor: shift->_elem("foo", @_)
+ if(@_ > 2) { return $_[0]{ $_[1] } = $_[2] }
+ else { return $_[0]{ $_[1] } }
+}
+#..........................................................................
+###########################################################################
+#
+# Init formatter switches, and start it off with __bindir and all that
+# other stuff that ToMan.pm needs.
+#
+
+sub init {
+ my $self = shift;
+
+ # Make sure creat()s are neither too much nor too little
+ eval { umask(0077) }; # doubtless someone has no mask
+
+ $self->{'args'} ||= \@ARGV;
+ $self->{'found'} ||= [];
+ $self->{'temp_file_list'} ||= [];
+
+
+ $self->{'target'} = undef;
+
+ $self->init_formatter_class_list;
+
+ $self->{'pagers' } = [@Pagers] unless exists $self->{'pagers'};
+ $self->{'bindir' } = $Bindir unless exists $self->{'bindir'};
+ $self->{'pod2man'} = $Pod2man unless exists $self->{'pod2man'};
+
+ push @{ $self->{'formatter_switches'} = [] }, (
+ # Yeah, we could use a hashref, but maybe there's some class where options
+ # have to be ordered; so we'll use an arrayref.
+
+ [ '__bindir' => $self->{'bindir' } ],
+ [ '__pod2man' => $self->{'pod2man'} ],
+ );
+
+ DEBUG > 3 and printf "Formatter switches now: [%s]\n",
+ join ' ', map "[@$_]", @{ $self->{'formatter_switches'} };
+
+ return;
+}
+
+#..........................................................................
+
+sub init_formatter_class_list {
+ my $self = shift;
+ $self->{'formatter_classes'} ||= [];
+
+ # Remember, no switches have been read yet, when
+ # we've started this routine.
+
+ $self->opt_M_with('Pod::Perldoc::ToPod'); # the always-there fallthru
+ $self->opt_o_with('text');
+ $self->opt_o_with('man') unless IS_MSWin32 || IS_Dos
+ || !($ENV{TERM} && (
+ ($ENV{TERM} || '') !~ /dumb|emacs|none|unknown/i
+ ));
+
+ return;
+}
+
+#..........................................................................
+
+sub process {
+ # if this ever returns, its retval will be used for exit(RETVAL)
+
+ my $self = shift;
+ DEBUG > 1 and print " Beginning process.\n";
+ DEBUG > 1 and print " Args: @{$self->{'args'}}\n\n";
+ if(DEBUG > 3) {
+ print "Object contents:\n";
+ my @x = %$self;
+ while(@x) {
+ $x[1] = '<undef>' unless defined $x[1];
+ $x[1] = "@{$x[1]}" if ref( $x[1] ) eq 'ARRAY';
+ print " [$x[0]] => [$x[1]]\n";
+ splice @x,0,2;
+ }
+ print "\n";
+ }
+
+ # TODO: make it deal with being invoked as various different things
+ # such as perlfaq".
+
+ return $self->usage_brief unless @{ $self->{'args'} };
+ $self->pagers_guessing;
+ $self->options_reading;
+ $self->aside(sprintf "$0 => %s v%s\n", ref($self), $self->VERSION);
+ $self->drop_privs_maybe;
+ $self->options_processing;
+
+ # Hm, we have @pages and @found, but we only really act on one
+ # file per call, with the exception of the opt_q hack, and with
+ # -l things
+
+ $self->aside("\n");
+
+ my @pages;
+ $self->{'pages'} = \@pages;
+ if( $self->opt_f) { @pages = ("perlfunc") }
+ elsif( $self->opt_q) { @pages = ("perlfaq1" .. "perlfaq9") }
+ else { @pages = @{$self->{'args'}};
+ # @pages = __FILE__
+ # if @pages == 1 and $pages[0] eq 'perldoc';
+ }
+
+ return $self->usage_brief unless @pages;
+
+ $self->find_good_formatter_class();
+ $self->formatter_sanity_check();
+
+ $self->maybe_diddle_INC();
+ # for when we're apparently in a module or extension directory
+
+ my @found = $self->grand_search_init(\@pages);
+ exit (IS_VMS ? 98962 : 1) unless @found;
+
+ if ($self->opt_l) {
+ DEBUG and print "We're in -l mode, so byebye after this:\n";
+ print join("\n", @found), "\n";
+ return;
+ }
+
+ $self->tweak_found_pathnames(\@found);
+ $self->assert_closing_stdout;
+ return $self->page_module_file(@found) if $self->opt_m;
+ DEBUG > 2 and print "Found: [@found]\n";
+
+ return $self->render_and_page(\@found);
+}
+
+#..........................................................................
+{
+
+my( %class_seen, %class_loaded );
+sub find_good_formatter_class {
+ my $self = $_[0];
+ my @class_list = @{ $self->{'formatter_classes'} || [] };
+ die "WHAT? Nothing in the formatter class list!?" unless @class_list;
+
+ my $good_class_found;
+ foreach my $c (@class_list) {
+ DEBUG > 4 and print "Trying to load $c...\n";
+ if($class_loaded{$c}) {
+ DEBUG > 4 and print "OK, the already-loaded $c it is!\n";
+ $good_class_found = $c;
+ last;
+ }
+
+ if($class_seen{$c}) {
+ DEBUG > 4 and print
+ "I've tried $c before, and it's no good. Skipping.\n";
+ next;
+ }
+
+ $class_seen{$c} = 1;
+
+ if( $c->can('parse_from_file') ) {
+ DEBUG > 4 and print
+ "Interesting, the formatter class $c is already loaded!\n";
+
+ } elsif(
+ (IS_VMS or IS_MSWin32 or IS_Dos or IS_OS2)
+ # the alway case-insensitive fs's
+ and $class_seen{lc("~$c")}++
+ ) {
+ DEBUG > 4 and print
+ "We already used something quite like \"\L$c\E\", so no point using $c\n";
+ # This avoids redefining the package.
+ } else {
+ DEBUG > 4 and print "Trying to eval 'require $c'...\n";
+
+ local $^W = $^W;
+ if(DEBUG() or $self->opt_v) {
+ # feh, let 'em see it
+ } else {
+ $^W = 0;
+ # The average user just has no reason to be seeing
+ # $^W-suppressable warnings from the the require!
+ }
+
+ eval "require $c";
+ if($@) {
+ DEBUG > 4 and print "Couldn't load $c: $!\n";
+ next;
+ }
+ }
+
+ if( $c->can('parse_from_file') ) {
+ DEBUG > 4 and print "Settling on $c\n";
+ my $v = $c->VERSION;
+ $v = ( defined $v and length $v ) ? " version $v" : '';
+ $self->aside("Formatter class $c$v successfully loaded!\n");
+ $good_class_found = $c;
+ last;
+ } else {
+ DEBUG > 4 and print "Class $c isn't a formatter?! Skipping.\n";
+ }
+ }
+
+ die "Can't find any loadable formatter class in @class_list?!\nAborting"
+ unless $good_class_found;
+
+ $self->{'formatter_class'} = $good_class_found;
+ $self->aside("Will format with the class $good_class_found\n");
+
+ return;
+}
+
+}
+#..........................................................................
+
+sub formatter_sanity_check {
+ my $self = shift;
+ my $formatter_class = $self->{'formatter_class'}
+ || die "NO FORMATTER CLASS YET!?";
+
+ if(!$self->opt_T # so -T can FORCE sending to STDOUT
+ and $formatter_class->can('is_pageable')
+ and !$formatter_class->is_pageable
+ and !$formatter_class->can('page_for_perldoc')
+ ) {
+ my $ext =
+ ($formatter_class->can('output_extension')
+ && $formatter_class->output_extension
+ ) || '';
+ $ext = ".$ext" if length $ext;
+
+ die
+ "When using Perldoc to format with $formatter_class, you have to\n"
+ . "specify -T or -dsomefile$ext\n"
+ . "See `perldoc perldoc' for more information on those switches.\n"
+ ;
+ }
+}
+
+#..........................................................................
+
+sub render_and_page {
+ my($self, $found_list) = @_;
+
+ $self->maybe_generate_dynamic_pod($found_list);
+
+ my($out, $formatter) = $self->render_findings($found_list);
+
+ if($self->opt_d) {
+ printf "Perldoc (%s) output saved to %s\n",
+ $self->{'formatter_class'} || ref($self),
+ $out;
+ print "But notice that it's 0 bytes long!\n" unless -s $out;
+
+
+ } elsif( # Allow the formatter to "page" itself, if it wants.
+ $formatter->can('page_for_perldoc')
+ and do {
+ $self->aside("Going to call $formatter\->page_for_perldoc(\"$out\")\n");
+ if( $formatter->page_for_perldoc($out, $self) ) {
+ $self->aside("page_for_perldoc returned true, so NOT paging with $self.\n");
+ 1;
+ } else {
+ $self->aside("page_for_perldoc returned false, so paging with $self instead.\n");
+ '';
+ }
+ }
+ ) {
+ # Do nothing, since the formatter has "paged" it for itself.
+
+ } else {
+ # Page it normally (internally)
+
+ if( -s $out ) { # Usual case:
+ $self->page($out, $self->{'output_to_stdout'}, $self->pagers);
+
+ } else {
+ # Odd case:
+ $self->aside("Skipping $out (from $$found_list[0] "
+ . "via $$self{'formatter_class'}) as it is 0-length.\n");
+
+ push @{ $self->{'temp_file_list'} }, $out;
+ $self->unlink_if_temp_file($out);
+ }
+ }
+
+ $self->after_rendering(); # any extra cleanup or whatever
+
+ return;
+}
+
+#..........................................................................
+
+sub options_reading {
+ my $self = shift;
+
+ if( defined $ENV{"PERLDOC"} and length $ENV{"PERLDOC"} ) {
+ require Text::ParseWords;
+ $self->aside("Noting env PERLDOC setting of $ENV{'PERLDOC'}\n");
+ # Yes, appends to the beginning
+ unshift @{ $self->{'args'} },
+ Text::ParseWords::shellwords( $ENV{"PERLDOC"} )
+ ;
+ DEBUG > 1 and print " Args now: @{$self->{'args'}}\n\n";
+ } else {
+ DEBUG > 1 and print " Okay, no PERLDOC setting in ENV.\n";
+ }
+
+ DEBUG > 1
+ and print " Args right before switch processing: @{$self->{'args'}}\n";
+
+ Pod::Perldoc::GetOptsOO::getopts( $self, $self->{'args'}, 'YES' )
+ or return $self->usage;
+
+ DEBUG > 1
+ and print " Args after switch processing: @{$self->{'args'}}\n";
+
+ return $self->usage if $self->opt_h;
+
+ return;
+}
+
+#..........................................................................
+
+sub options_processing {
+ my $self = shift;
+
+ if ($self->opt_X) {
+ my $podidx = "$Config{'archlib'}/pod.idx";
+ $podidx = "" unless -f $podidx && -r _ && -M _ <= 7;
+ $self->{'podidx'} = $podidx;
+ }
+
+ $self->{'output_to_stdout'} = 1 if $self->opt_T or ! -t STDOUT;
+
+ $self->options_sanity;
+
+ $self->opt_n("nroff") unless $self->opt_n;
+ $self->add_formatter_option( '__nroffer' => $self->opt_n );
+
+ return;
+}
+
+#..........................................................................
+
+sub options_sanity {
+ my $self = shift;
+
+ # The opts-counting stuff interacts quite badly with
+ # the $ENV{"PERLDOC"} stuff. I.e., if I have $ENV{"PERLDOC"}
+ # set to -t, and I specify -u on the command line, I don't want
+ # to be hectored at that -u and -t don't make sense together.
+
+ #my $opts = grep $_ && 1, # yes, the count of the set ones
+ # $self->opt_t, $self->opt_u, $self->opt_m, $self->opt_l
+ #;
+ #
+ #$self->usage("only one of -t, -u, -m or -l") if $opts > 1;
+
+
+ # Any sanity-checking need doing here?
+
+ return;
+}
+
+#..........................................................................
+
+sub grand_search_init {
+ my($self, $pages, @found) = @_;
+
+ foreach (@$pages) {
+ if ($self->{'podidx'} && open(PODIDX, $self->{'podidx'})) {
+ my $searchfor = catfile split '::', $_;
+ $self->aside( "Searching for '$searchfor' in $self->{'podidx'}\n" );
+ local $_;
+ while (<PODIDX>) {
+ chomp;
+ push(@found, $_) if m,/$searchfor(?:\.(?:pod|pm))?\z,i;
+ }
+ close(PODIDX) or die "Can't close $$self{'podidx'}: $!";
+ next;
+ }
+
+ $self->aside( "Searching for $_\n" );
+
+ if ($self->opt_F) {
+ next unless -r;
+ push @found, $_ if $self->opt_m or $self->containspod($_);
+ next;
+ }
+
+ # We must look both in @INC for library modules and in $bindir
+ # for executables, like h2xs or perldoc itself.
+
+ my @searchdirs = ($self->{'bindir'}, @INC);
+ unless ($self->opt_m) {
+ if (IS_VMS) {
+ my($i,$trn);
+ for ($i = 0; $trn = $ENV{'DCL$PATH;'.$i}; $i++) {
+ push(@searchdirs,$trn);
+ }
+ push(@searchdirs,'perl_root:[lib.pod]') # installed pods
+ }
+ else {
+ push(@searchdirs, grep(-d, split($Config{path_sep},
+ $ENV{'PATH'})));
+ }
+ }
+ my @files = $self->searchfor(0,$_,@searchdirs);
+ if (@files) {
+ $self->aside( "Found as @files\n" );
+ }
+ else {
+ # no match, try recursive search
+ @searchdirs = grep(!/^\.\z/s,@INC);
+ @files= $self->searchfor(1,$_,@searchdirs) if $self->opt_r;
+ if (@files) {
+ $self->aside( "Loosely found as @files\n" );
+ }
+ else {
+ print STDERR "No " .
+ ($self->opt_m ? "module" : "documentation") . " found for \"$_\".\n";
+ if ( @{ $self->{'found'} } ) {
+ print STDERR "However, try\n";
+ for my $dir (@{ $self->{'found'} }) {
+ opendir(DIR, $dir) or die "opendir $dir: $!";
+ while (my $file = readdir(DIR)) {
+ next if ($file =~ /^\./s);
+ $file =~ s/\.(pm|pod)\z//; # XXX: badfs
+ print STDERR "\tperldoc $_\::$file\n";
+ }
+ closedir(DIR) or die "closedir $dir: $!";
+ }
+ }
+ }
+ }
+ push(@found,@files);
+ }
+ return @found;
+}
+
+#..........................................................................
+
+sub maybe_generate_dynamic_pod {
+ my($self, $found_things) = @_;
+ my @dynamic_pod;
+
+ $self->search_perlfunc($found_things, \@dynamic_pod) if $self->opt_f;
+
+ $self->search_perlfaqs($found_things, \@dynamic_pod) if $self->opt_q;
+
+ if( ! $self->opt_f and ! $self->opt_q ) {
+ DEBUG > 4 and print "That's a non-dynamic pod search.\n";
+ } elsif ( @dynamic_pod ) {
+ $self->aside("Hm, I found some Pod from that search!\n");
+ my ($buffd, $buffer) = $self->new_tempfile('pod', 'dyn');
+
+ push @{ $self->{'temp_file_list'} }, $buffer;
+ # I.e., it MIGHT be deleted at the end.
+
+ my $in_list = $self->opt_f;
+
+ print $buffd "=over 8\n\n" if $in_list;
+ print $buffd @dynamic_pod or die "Can't print $buffer: $!";
+ print $buffd "=back\n" if $in_list;
+
+ close $buffd or die "Can't close $buffer: $!";
+
+ @$found_things = $buffer;
+ # Yes, so found_things never has more than one thing in
+ # it, by time we leave here
+
+ $self->add_formatter_option('__filter_nroff' => 1);
+
+ } else {
+ @$found_things = ();
+ $self->aside("I found no Pod from that search!\n");
+ }
+
+ return;
+}
+
+#..........................................................................
+
+sub add_formatter_option { # $self->add_formatter_option('key' => 'value');
+ my $self = shift;
+ push @{ $self->{'formatter_switches'} }, [ @_ ] if @_;
+
+ DEBUG > 3 and printf "Formatter switches now: [%s]\n",
+ join ' ', map "[@$_]", @{ $self->{'formatter_switches'} };
+
+ return;
+}
+
+#..........................................................................
+
+sub search_perlfunc {
+ my($self, $found_things, $pod) = @_;
+
+ DEBUG > 2 and print "Search: @$found_things\n";
+
+ my $perlfunc = shift @$found_things;
+ open(PFUNC, "<", $perlfunc) # "Funk is its own reward"
+ or die("Can't open $perlfunc: $!");
+
+ # Functions like -r, -e, etc. are listed under `-X'.
+ my $search_re = ($self->opt_f =~ /^-[rwxoRWXOeszfdlpSbctugkTBMAC]$/)
+ ? '(?:I<)?-X' : quotemeta($self->opt_f) ;
+
+ DEBUG > 2 and
+ print "Going to perlfunc-scan for $search_re in $perlfunc\n";
+
+ # Skip introduction
+ local $_;
+ while (<PFUNC>) {
+ last if /^=head2 Alphabetical Listing of Perl Functions/;
+ }
+
+ # Look for our function
+ my $found = 0;
+ my $inlist = 0;
+ while (<PFUNC>) { # "The Mothership Connection is here!"
+ if ( m/^=item\s+$search_re\b/ ) {
+ $found = 1;
+ }
+ elsif (/^=item/) {
+ last if $found > 1 and not $inlist;
+ }
+ next unless $found;
+ if (/^=over/) {
+ ++$inlist;
+ }
+ elsif (/^=back/) {
+ --$inlist;
+ }
+ push @$pod, $_;
+ ++$found if /^\w/; # found descriptive text
+ }
+ if (!@$pod) {
+ die sprintf
+ "No documentation for perl function `%s' found\n",
+ $self->opt_f
+ ;
+ }
+ close PFUNC or die "Can't open $perlfunc: $!";
+
+ return;
+}
+
+#..........................................................................
+
+sub search_perlfaqs {
+ my( $self, $found_things, $pod) = @_;
+
+ my $found = 0;
+ my %found_in;
+ my $search_key = $self->opt_q;
+
+ my $rx = eval { qr/$search_key/ }
+ or die <<EOD;
+Invalid regular expression '$search_key' given as -q pattern:
+$@
+Did you mean \\Q$search_key ?
+
+EOD
+
+ local $_;
+ foreach my $file (@$found_things) {
+ die "invalid file spec: $!" if $file =~ /[<>|]/;
+ open(INFAQ, "<", $file) # XXX 5.6ism
+ or die "Can't read-open $file: $!\nAborting";
+ while (<INFAQ>) {
+ if ( m/^=head2\s+.*(?:$search_key)/i ) {
+ $found = 1;
+ push @$pod, "=head1 Found in $file\n\n" unless $found_in{$file}++;
+ }
+ elsif (/^=head[12]/) {
+ $found = 0;
+ }
+ next unless $found;
+ push @$pod, $_;
+ }
+ close(INFAQ);
+ }
+ die("No documentation for perl FAQ keyword `$search_key' found\n")
+ unless @$pod;
+
+ return;
+}
+
+
+#..........................................................................
+
+sub render_findings {
+ # Return the filename to open
+
+ my($self, $found_things) = @_;
+
+ my $formatter_class = $self->{'formatter_class'}
+ || die "No formatter class set!?";
+ my $formatter = $formatter_class->can('new')
+ ? $formatter_class->new
+ : $formatter_class
+ ;
+
+ if(! @$found_things) {
+ die "Nothing found?!";
+ # should have been caught before here
+ } elsif(@$found_things > 1) {
+ warn join '',
+ "Perldoc is only really meant for reading one document at a time.\n",
+ "So these parameters are being ignored: ",
+ join(' ', @$found_things[1 .. $#$found_things] ),
+ "\n"
+ }
+
+ my $file = $found_things->[0];
+
+ DEBUG > 3 and printf "Formatter switches now: [%s]\n",
+ join ' ', map "[@$_]", @{ $self->{'formatter_switches'} };
+
+ # Set formatter options:
+ if( ref $formatter ) {
+ foreach my $f (@{ $self->{'formatter_switches'} || [] }) {
+ my($switch, $value, $silent_fail) = @$f;
+ if( $formatter->can($switch) ) {
+ eval { $formatter->$switch( defined($value) ? $value : () ) };
+ warn "Got an error when setting $formatter_class\->$switch:\n$@\n"
+ if $@;
+ } else {
+ if( $silent_fail or $switch =~ m/^__/s ) {
+ DEBUG > 2 and print "Formatter $formatter_class doesn't support $switch\n";
+ } else {
+ warn "$formatter_class doesn't recognize the $switch switch.\n";
+ }
+ }
+ }
+ }
+
+ $self->{'output_is_binary'} =
+ $formatter->can('write_with_binmode') && $formatter->write_with_binmode;
+
+ my ($out_fh, $out) = $self->new_output_file(
+ ( $formatter->can('output_extension') && $formatter->output_extension )
+ || undef,
+ $self->useful_filename_bit,
+ );
+
+ # Now, finally, do the formatting!
+ {
+ local $^W = $^W;
+ if(DEBUG() or $self->opt_v) {
+ # feh, let 'em see it
+ } else {
+ $^W = 0;
+ # The average user just has no reason to be seeing
+ # $^W-suppressable warnings from the formatting!
+ }
+
+ eval { $formatter->parse_from_file( $file, $out_fh ) };
+ }
+
+ warn "Error while formatting with $formatter_class:\n $@\n" if $@;
+ DEBUG > 2 and print "Back from formatting with $formatter_class\n";
+
+ close $out_fh
+ or warn "Can't close $out: $!\n(Did $formatter already close it?)";
+ sleep 0; sleep 0; sleep 0;
+ # Give the system a few timeslices to meditate on the fact
+ # that the output file does in fact exist and is closed.
+
+ $self->unlink_if_temp_file($file);
+
+ unless( -s $out ) {
+ if( $formatter->can( 'if_zero_length' ) ) {
+ # Basically this is just a hook for Pod::Simple::Checker; since
+ # what other class could /happily/ format an input file with Pod
+ # as a 0-length output file?
+ $formatter->if_zero_length( $file, $out, $out_fh );
+ } else {
+ warn "Got a 0-length file from $$found_things[0] via $formatter_class!?\n"
+ }
+ }
+
+ DEBUG and print "Finished writing to $out.\n";
+ return($out, $formatter) if wantarray;
+ return $out;
+}
+
+#..........................................................................
+
+sub unlink_if_temp_file {
+ # Unlink the specified file IFF it's in the list of temp files.
+ # Really only used in the case of -f / -q things when we can
+ # throw away the dynamically generated source pod file once
+ # we've formatted it.
+ #
+ my($self, $file) = @_;
+ return unless defined $file and length $file;
+
+ my $temp_file_list = $self->{'temp_file_list'} || return;
+ if(grep $_ eq $file, @$temp_file_list) {
+ $self->aside("Unlinking $file\n");
+ unlink($file) or warn "Odd, couldn't unlink $file: $!";
+ } else {
+ DEBUG > 1 and print "$file isn't a temp file, so not unlinking.\n";
+ }
+ return;
+}
+
+#..........................................................................
+
+sub MSWin_temp_cleanup {
+
+ # Nothing particularly MSWin-specific in here, but I don't know if any
+ # other OS needs its temp dir policed like MSWin does!
+
+ my $self = shift;
+
+ my $tempdir = $ENV{'TEMP'};
+ return unless defined $tempdir and length $tempdir
+ and -e $tempdir and -d _ and -w _;
+
+ $self->aside(
+ "Considering whether any old files of mine in $tempdir need unlinking.\n"
+ );
+
+ opendir(TMPDIR, $tempdir) || return;
+ my @to_unlink;
+
+ my $limit = time() - $Temp_File_Lifetime;
+
+ DEBUG > 5 and printf "Looking for things pre-dating %s (%x)\n",
+ ($limit) x 2;
+
+ my $filespec;
+
+ while(defined($filespec = readdir(TMPDIR))) {
+ if(
+ $filespec =~ m{^perldoc_[a-zA-Z0-9]+_T([a-fA-F0-9]{7,})_[a-fA-F0-9]{3,}}s
+ ) {
+ if( hex($1) < $limit ) {
+ push @to_unlink, "$tempdir/$filespec";
+ $self->aside( "Will unlink my old temp file $to_unlink[-1]\n" );
+ } else {
+ DEBUG > 5 and
+ printf " $tempdir/$filespec is too recent (after %x)\n", $limit;
+ }
+ } else {
+ DEBUG > 5 and
+ print " $tempdir/$filespec doesn't look like a perldoc temp file.\n";
+ }
+ }
+ closedir(TMPDIR);
+ $self->aside(sprintf "Unlinked %s items of mine in %s\n",
+ scalar(unlink(@to_unlink)),
+ $tempdir
+ );
+ return;
+}
+
+# . . . . . . . . . . . . . . . . . . . . . . . . .
+
+sub MSWin_perldoc_tempfile {
+ my($self, $suffix, $infix) = @_;
+
+ my $tempdir = $ENV{'TEMP'};
+ return unless defined $tempdir and length $tempdir
+ and -e $tempdir and -d _ and -w _;
+
+ my $spec;
+
+ do {
+ $spec = sprintf "%s\\perldoc_%s_T%x_%x%02x.%s", # used also in MSWin_temp_cleanup
+ # Yes, we embed the create-time in the filename!
+ $tempdir,
+ $infix || 'x',
+ time(),
+ $$,
+ defined( &Win32::GetTickCount )
+ ? (Win32::GetTickCount() & 0xff)
+ : int(rand 256)
+ # Under MSWin, $$ values get reused quickly! So if we ran
+ # perldoc foo and then perldoc bar before there was time for
+ # time() to increment time."_$$" would likely be the same
+ # for each process! So we tack on the tick count's lower
+ # bits (or, in a pinch, rand)
+ ,
+ $suffix || 'txt';
+ ;
+ } while( -e $spec );
+
+ my $counter = 0;
+
+ while($counter < 50) {
+ my $fh;
+ # If we are running before perl5.6.0, we can't autovivify
+ if ($] < 5.006) {
+ require Symbol;
+ $fh = Symbol::gensym();
+ }
+ DEBUG > 3 and print "About to try making temp file $spec\n";
+ return($fh, $spec) if open($fh, ">", $spec); # XXX 5.6ism
+ $self->aside("Can't create temp file $spec: $!\n");
+ }
+
+ $self->aside("Giving up on making a temp file!\n");
+ die "Can't make a tempfile!?";
+}
+
+#..........................................................................
+
+
+sub after_rendering {
+ my $self = $_[0];
+ $self->after_rendering_VMS if IS_VMS;
+ $self->after_rendering_MSWin32 if IS_MSWin32;
+ $self->after_rendering_Dos if IS_Dos;
+ $self->after_rendering_OS2 if IS_OS2;
+ return;
+}
+
+sub after_rendering_VMS { return }
+sub after_rendering_Dos { return }
+sub after_rendering_OS2 { return }
+
+sub after_rendering_MSWin32 {
+ shift->MSWin_temp_cleanup() if $Temp_Files_Created;
+}
+
+#..........................................................................
+# : : : : : : : : :
+#..........................................................................
+
+
+sub minus_f_nocase { # i.e., do like -f, but without regard to case
+
+ my($self, $dir, $file) = @_;
+ my $path = catfile($dir,$file);
+ return $path if -f $path and -r _;
+
+ if(!$self->opt_i
+ or IS_VMS or IS_MSWin32
+ or IS_Dos or IS_OS2
+ ) {
+ # On a case-forgiving file system, or if case is important,
+ # that is it, all we can do.
+ warn "Ignored $path: unreadable\n" if -f _;
+ return '';
+ }
+
+ local *DIR;
+ my @p = ($dir);
+ my($p,$cip);
+ foreach $p (splitdir $file){
+ my $try = catfile @p, $p;
+ $self->aside("Scrutinizing $try...\n");
+ stat $try;
+ if (-d _) {
+ push @p, $p;
+ if ( $p eq $self->{'target'} ) {
+ my $tmp_path = catfile @p;
+ my $path_f = 0;
+ for (@{ $self->{'found'} }) {
+ $path_f = 1 if $_ eq $tmp_path;
+ }
+ push (@{ $self->{'found'} }, $tmp_path) unless $path_f;
+ $self->aside( "Found as $tmp_path but directory\n" );
+ }
+ }
+ elsif (-f _ && -r _) {
+ return $try;
+ }
+ elsif (-f _) {
+ warn "Ignored $try: unreadable\n";
+ }
+ elsif (-d catdir(@p)) { # at least we see the containing directory!
+ my $found = 0;
+ my $lcp = lc $p;
+ my $p_dirspec = catdir(@p);
+ opendir DIR, $p_dirspec or die "opendir $p_dirspec: $!";
+ while(defined( $cip = readdir(DIR) )) {
+ if (lc $cip eq $lcp){
+ $found++;
+ last; # XXX stop at the first? what if there's others?
+ }
+ }
+ closedir DIR or die "closedir $p_dirspec: $!";
+ return "" unless $found;
+
+ push @p, $cip;
+ my $p_filespec = catfile(@p);
+ return $p_filespec if -f $p_filespec and -r _;
+ warn "Ignored $p_filespec: unreadable\n" if -f _;
+ }
+ }
+ return "";
+}
+
+#..........................................................................
+
+sub pagers_guessing {
+ my $self = shift;
+
+ my @pagers;
+ push @pagers, $self->pagers;
+ $self->{'pagers'} = \@pagers;
+
+ if (IS_MSWin32) {
+ push @pagers, qw( more< less notepad );
+ unshift @pagers, $ENV{PAGER} if $ENV{PAGER};
+ }
+ elsif (IS_VMS) {
+ push @pagers, qw( most more less type/page );
+ }
+ elsif (IS_Dos) {
+ push @pagers, qw( less.exe more.com< );
+ unshift @pagers, $ENV{PAGER} if $ENV{PAGER};
+ }
+ else {
+ if (IS_OS2) {
+ unshift @pagers, 'less', 'cmd /c more <';
+ }
+ push @pagers, qw( more less pg view cat );
+ unshift @pagers, $ENV{PAGER} if $ENV{PAGER};
+ }
+
+ if (IS_Cygwin) {
+ if (($pagers[0] eq 'less') || ($pagers[0] eq '/usr/bin/less')) {
+ unshift @pagers, '/usr/bin/less -isrR';
+ }
+ }
+
+ unshift @pagers, $ENV{PERLDOC_PAGER} if $ENV{PERLDOC_PAGER};
+
+ return;
+}
+
+#..........................................................................
+
+sub page_module_file {
+ my($self, @found) = @_;
+
+ # Security note:
+ # Don't ever just pass this off to anything like MSWin's "start.exe",
+ # since we might be calling on a .pl file, and we wouldn't want that
+ # to actually /execute/ the file that we just want to page thru!
+ # Also a consideration if one were to use a web browser as a pager;
+ # doing so could trigger the browser's MIME mapping for whatever
+ # it thinks .pm/.pl/whatever is. Probably just a (useless and
+ # annoying) "Save as..." dialog, but potentially executing the file
+ # in question -- particularly in the case of MSIE and it's, ahem,
+ # occasionally hazy distinction between OS-local extension
+ # associations, and browser-specific MIME mappings.
+
+ if ($self->{'output_to_stdout'}) {
+ $self->aside("Sending unpaged output to STDOUT.\n");
+ local $_;
+ my $any_error = 0;
+ foreach my $output (@found) {
+ unless( open(TMP, "<", $output) ) { # XXX 5.6ism
+ warn("Can't open $output: $!");
+ $any_error = 1;
+ next;
+ }
+ while (<TMP>) {
+ print or die "Can't print to stdout: $!";
+ }
+ close TMP or die "Can't close while $output: $!";
+ $self->unlink_if_temp_file($output);
+ }
+ return $any_error; # successful
+ }
+
+ foreach my $pager ( $self->pagers ) {
+ $self->aside("About to try calling $pager @found\n");
+ if (system($pager, @found) == 0) {
+ $self->aside("Yay, it worked.\n");
+ return 0;
+ }
+ $self->aside("That didn't work.\n");
+
+ # Odd -- when it fails, under Win32, this seems to neither
+ # return with a fail nor return with a success!!
+ # That's discouraging!
+ }
+
+ $self->aside(
+ sprintf "Can't manage to find a way to page [%s] via pagers [%s]\n",
+ join(' ', @found),
+ join(' ', $self->pagers),
+ );
+
+ if (IS_VMS) {
+ DEBUG > 1 and print "Bailing out in a VMSish way.\n";
+ eval q{
+ use vmsish qw(status exit);
+ exit $?;
+ 1;
+ } or die;
+ }
+
+ return 1;
+ # i.e., an UNSUCCESSFUL return value!
+}
+
+#..........................................................................
+
+sub check_file {
+ my($self, $dir, $file) = @_;
+
+ unless( ref $self ) {
+ # Should never get called:
+ $Carp::Verbose = 1;
+ require Carp;
+ Carp::croak( join '',
+ "Crazy ", __PACKAGE__, " error:\n",
+ "check_file must be an object_method!\n",
+ "Aborting"
+ );
+ }
+
+ if(length $dir and not -d $dir) {
+ DEBUG > 3 and print " No dir $dir -- skipping.\n";
+ return "";
+ }
+
+ if ($self->opt_m) {
+ return $self->minus_f_nocase($dir,$file);
+ }
+
+ else {
+ my $path = $self->minus_f_nocase($dir,$file);
+ if( length $path and $self->containspod($path) ) {
+ DEBUG > 3 and print
+ " The file $path indeed looks promising!\n";
+ return $path;
+ }
+ }
+ DEBUG > 3 and print " No good: $file in $dir\n";
+
+ return "";
+}
+
+#..........................................................................
+
+sub containspod {
+ my($self, $file, $readit) = @_;
+ return 1 if !$readit && $file =~ /\.pod\z/i;
+
+
+ # Under cygwin the /usr/bin/perl is legal executable, but
+ # you cannot open a file with that name. It must be spelled
+ # out as "/usr/bin/perl.exe".
+ #
+ # The following if-case under cygwin prevents error
+ #
+ # $ perldoc perl
+ # Cannot open /usr/bin/perl: no such file or directory
+ #
+ # This would work though
+ #
+ # $ perldoc perl.pod
+
+ if ( IS_Cygwin and -x $file and -f "$file.exe" )
+ {
+ warn "Cygwin $file.exe search skipped\n" if DEBUG or $self->opt_v;
+ return 0;
+ }
+
+ local($_);
+ open(TEST,"<", $file) or die "Can't open $file: $!"; # XXX 5.6ism
+ while (<TEST>) {
+ if (/^=head/) {
+ close(TEST) or die "Can't close $file: $!";
+ return 1;
+ }
+ }
+ close(TEST) or die "Can't close $file: $!";
+ return 0;
+}
+
+#..........................................................................
+
+sub maybe_diddle_INC {
+ my $self = shift;
+
+ # Does this look like a module or extension directory?
+
+ if (-f "Makefile.PL") {
+
+ # Add "." and "lib" to @INC (if they exist)
+ eval q{ use lib qw(. lib); 1; } or die;
+
+ # don't add if superuser
+ if ($< && $> && -f "blib") { # don't be looking too hard now!
+ eval q{ use blib; 1 };
+ warn $@ if $@ && $self->opt_v;
+ }
+ }
+
+ return;
+}
+
+#..........................................................................
+
+sub new_output_file {
+ my $self = shift;
+ my $outspec = $self->opt_d; # Yes, -d overrides all else!
+ # So don't call this twice per format-job!
+
+ return $self->new_tempfile(@_) unless defined $outspec and length $outspec;
+
+ # Otherwise open a write-handle on opt_d!f
+
+ my $fh;
+ # If we are running before perl5.6.0, we can't autovivify
+ if ($] < 5.006) {
+ require Symbol;
+ $fh = Symbol::gensym();
+ }
+ DEBUG > 3 and print "About to try writing to specified output file $outspec\n";
+ die "Can't write-open $outspec: $!"
+ unless open($fh, ">", $outspec); # XXX 5.6ism
+
+ DEBUG > 3 and print "Successfully opened $outspec\n";
+ binmode($fh) if $self->{'output_is_binary'};
+ return($fh, $outspec);
+}
+
+#..........................................................................
+
+sub useful_filename_bit {
+ # This tries to provide a meaningful bit of text to do with the query,
+ # such as can be used in naming the file -- since if we're going to be
+ # opening windows on temp files (as a "pager" may well do!) then it's
+ # better if the temp file's name (which may well be used as the window
+ # title) isn't ALL just random garbage!
+ # In other words "perldoc_LWPSimple_2371981429" is a better temp file
+ # name than "perldoc_2371981429". So this routine is what tries to
+ # provide the "LWPSimple" bit.
+ #
+ my $self = shift;
+ my $pages = $self->{'pages'} || return undef;
+ return undef unless @$pages;
+
+ my $chunk = $pages->[0];
+ return undef unless defined $chunk;
+ $chunk =~ s/:://g;
+ $chunk =~ s/\.\w+$//g; # strip any extension
+ if( $chunk =~ m/([^\#\\:\/\$]+)$/s ) { # get basename, if it's a file
+ $chunk = $1;
+ } else {
+ return undef;
+ }
+ $chunk =~ s/[^a-zA-Z0-9]+//g; # leave ONLY a-zA-Z0-9 things!
+ $chunk = substr($chunk, -10) if length($chunk) > 10;
+ return $chunk;
+}
+
+#..........................................................................
+
+sub new_tempfile { # $self->new_tempfile( [$suffix, [$infix] ] )
+ my $self = shift;
+
+ ++$Temp_Files_Created;
+
+ if( IS_MSWin32 ) {
+ my @out = $self->MSWin_perldoc_tempfile(@_);
+ return @out if @out;
+ # otherwise fall thru to the normal stuff below...
+ }
+
+ require File::Temp;
+ return File::Temp::tempfile(UNLINK => 1);
+}
+
+#..........................................................................
+
+sub page { # apply a pager to the output file
+ my ($self, $output, $output_to_stdout, @pagers) = @_;
+ if ($output_to_stdout) {
+ $self->aside("Sending unpaged output to STDOUT.\n");
+ open(TMP, "<", $output) or die "Can't open $output: $!"; # XXX 5.6ism
+ local $_;
+ while (<TMP>) {
+ print or die "Can't print to stdout: $!";
+ }
+ close TMP or die "Can't close while $output: $!";
+ $self->unlink_if_temp_file($output);
+ } else {
+ # On VMS, quoting prevents logical expansion, and temp files with no
+ # extension get the wrong default extension (such as .LIS for TYPE)
+
+ $output = VMS::Filespec::rmsexpand($output, '.') if IS_VMS;
+
+ $output =~ s{/}{\\}g if IS_MSWin32 || IS_Dos;
+ # Altho "/" under MSWin is in theory good as a pathsep,
+ # many many corners of the OS don't like it. So we
+ # have to force it to be "\" to make everyone happy.
+
+ foreach my $pager (@pagers) {
+ $self->aside("About to try calling $pager $output\n");
+ if (IS_VMS) {
+ last if system("$pager $output") == 0;
+ } else {
+ last if system("$pager \"$output\"") == 0;
+ }
+ }
+ }
+ return;
+}
+
+#..........................................................................
+
+sub searchfor {
+ my($self, $recurse,$s,@dirs) = @_;
+ $s =~ s!::!/!g;
+ $s = VMS::Filespec::unixify($s) if IS_VMS;
+ return $s if -f $s && $self->containspod($s);
+ $self->aside( "Looking for $s in @dirs\n" );
+ my $ret;
+ my $i;
+ my $dir;
+ $self->{'target'} = (splitdir $s)[-1]; # XXX: why not use File::Basename?
+ for ($i=0; $i<@dirs; $i++) {
+ $dir = $dirs[$i];
+ next unless -d $dir; # some dirs in @INC are optional
+ ($dir = VMS::Filespec::unixpath($dir)) =~ s!/\z!! if IS_VMS;
+ if ( (! $self->opt_m && ( $ret = $self->check_file($dir,"$s.pod")))
+ or ( $ret = $self->check_file($dir,"$s.pm"))
+ or ( $ret = $self->check_file($dir,$s))
+ or ( IS_VMS and
+ $ret = $self->check_file($dir,"$s.com"))
+ or ( IS_OS2 and
+ $ret = $self->check_file($dir,"$s.cmd"))
+ or ( (IS_MSWin32 or IS_Dos or IS_OS2) and
+ $ret = $self->check_file($dir,"$s.bat"))
+ or ( $ret = $self->check_file("$dir/pod","$s.pod"))
+ or ( $ret = $self->check_file("$dir/pod",$s))
+ or ( $ret = $self->check_file("$dir/pods","$s.pod"))
+ or ( $ret = $self->check_file("$dir/pods",$s))
+ ) {
+ DEBUG > 1 and print " Found $ret\n";
+ return $ret;
+ }
+
+ if ($recurse) {
+ opendir(D,$dir) or die "Can't opendir $dir: $!";
+ my @newdirs = map catfile($dir, $_), grep {
+ not /^\.\.?\z/s and
+ not /^auto\z/s and # save time! don't search auto dirs
+ -d catfile($dir, $_)
+ } readdir D;
+ closedir(D) or die "Can't closedir $dir: $!";
+ next unless @newdirs;
+ # what a wicked map!
+ @newdirs = map((s/\.dir\z//,$_)[1],@newdirs) if IS_VMS;
+ $self->aside( "Also looking in @newdirs\n" );
+ push(@dirs,@newdirs);
+ }
+ }
+ return ();
+}
+
+#..........................................................................
+{
+ my $already_asserted;
+ sub assert_closing_stdout {
+ my $self = shift;
+
+ return if $already_asserted;
+
+ eval q~ END { close(STDOUT) || die "Can't close STDOUT: $!" } ~;
+ # What for? to let the pager know that nothing more will come?
+
+ die $@ if $@;
+ $already_asserted = 1;
+ return;
+ }
+}
+
+#..........................................................................
+
+sub tweak_found_pathnames {
+ my($self, $found) = @_;
+ if (IS_MSWin32) {
+ foreach (@$found) { s,/,\\,g }
+ }
+ return;
+}
+
+#..........................................................................
+# : : : : : : : : :
+#..........................................................................
+
+sub am_taint_checking {
+ my $self = shift;
+ die "NO ENVIRONMENT?!?!" unless keys %ENV; # reset iterator along the way
+ my($k,$v) = each %ENV;
+ return is_tainted($v);
+}
+
+#..........................................................................
+
+sub is_tainted { # just a function
+ my $arg = shift;
+ my $nada = substr($arg, 0, 0); # zero-length!
+ local $@; # preserve the caller's version of $@
+ eval { eval "# $nada" };
+ return length($@) != 0;
+}
+
+#..........................................................................
+
+sub drop_privs_maybe {
+ my $self = shift;
+
+ # Attempt to drop privs if we should be tainting and aren't
+ if (!(IS_VMS || IS_MSWin32 || IS_Dos
+ || IS_OS2
+ )
+ && ($> == 0 || $< == 0)
+ && !$self->am_taint_checking()
+ ) {
+ my $id = eval { getpwnam("nobody") };
+ $id = eval { getpwnam("nouser") } unless defined $id;
+ $id = -2 unless defined $id;
+ #
+ # According to Stevens' APUE and various
+ # (BSD, Solaris, HP-UX) man pages, setting
+ # the real uid first and effective uid second
+ # is the way to go if one wants to drop privileges,
+ # because if one changes into an effective uid of
+ # non-zero, one cannot change the real uid any more.
+ #
+ # Actually, it gets even messier. There is
+ # a third uid, called the saved uid, and as
+ # long as that is zero, one can get back to
+ # uid of zero. Setting the real-effective *twice*
+ # helps in *most* systems (FreeBSD and Solaris)
+ # but apparently in HP-UX even this doesn't help:
+ # the saved uid stays zero (apparently the only way
+ # in HP-UX to change saved uid is to call setuid()
+ # when the effective uid is zero).
+ #
+ eval {
+ $< = $id; # real uid
+ $> = $id; # effective uid
+ $< = $id; # real uid
+ $> = $id; # effective uid
+ };
+ if( !$@ && $< && $> ) {
+ DEBUG and print "OK, I dropped privileges.\n";
+ } elsif( $self->opt_U ) {
+ DEBUG and print "Couldn't drop privileges, but in -U mode, so feh."
+ } else {
+ DEBUG and print "Hm, couldn't drop privileges. Ah well.\n";
+ # We used to die here; but that seemed pointless.
+ }
+ }
+ return;
+}
+
+#..........................................................................
+
+1;
+
+__END__
+
+# See "perldoc perldoc" for basic details.
+#
+# Perldoc -- look up a piece of documentation in .pod format that
+# is embedded in the perl installation tree.
+#
+#~~~~~~
+#
+# See ChangeLog in CPAN dist for Pod::Perldoc for later notes.
+#
+# Version 3.01: Sun Nov 10 21:38:09 MST 2002
+# Sean M. Burke <sburke@cpan.org>
+# Massive refactoring and code-tidying.
+# Now it's a module(-family)!
+# Formatter-specific stuff pulled out into Pod::Perldoc::To(Whatever).pm
+# Added -T, -d, -o, -M, -w.
+# Added some improved MSWin funk.
+#
+#~~~~~~
+#
+# Version 2.05: Sat Oct 12 16:09:00 CEST 2002
+# Hugo van der Sanden <hv@crypt.org>
+# Made -U the default, based on patch from Simon Cozens
+# Version 2.04: Sun Aug 18 13:27:12 BST 2002
+# Randy W. Sims <RandyS@ThePierianSpring.org>
+# allow -n to enable nroff under Win32
+# Version 2.03: Sun Apr 23 16:56:34 BST 2000
+# Hugo van der Sanden <hv@crypt.org>
+# don't die when 'use blib' fails
+# Version 2.02: Mon Mar 13 18:03:04 MST 2000
+# Tom Christiansen <tchrist@perl.com>
+# Added -U insecurity option
+# Version 2.01: Sat Mar 11 15:22:33 MST 2000
+# Tom Christiansen <tchrist@perl.com>, querulously.
+# Security and correctness patches.
+# What a twisted bit of distasteful spaghetti code.
+# Version 2.0: ????
+#
+#~~~~~~
+#
+# Version 1.15: Tue Aug 24 01:50:20 EST 1999
+# Charles Wilson <cwilson@ece.gatech.edu>
+# changed /pod/ directory to /pods/ for cygwin
+# to support cygwin/win32
+# Version 1.14: Wed Jul 15 01:50:20 EST 1998
+# Robin Barker <rmb1@cise.npl.co.uk>
+# -strict, -w cleanups
+# Version 1.13: Fri Feb 27 16:20:50 EST 1997
+# Gurusamy Sarathy <gsar@activestate.com>
+# -doc tweaks for -F and -X options
+# Version 1.12: Sat Apr 12 22:41:09 EST 1997
+# Gurusamy Sarathy <gsar@activestate.com>
+# -various fixes for win32
+# Version 1.11: Tue Dec 26 09:54:33 EST 1995
+# Kenneth Albanowski <kjahds@kjahds.com>
+# -added Charles Bailey's further VMS patches, and -u switch
+# -added -t switch, with pod2text support
+#
+# Version 1.10: Thu Nov 9 07:23:47 EST 1995
+# Kenneth Albanowski <kjahds@kjahds.com>
+# -added VMS support
+# -added better error recognition (on no found pages, just exit. On
+# missing nroff/pod2man, just display raw pod.)
+# -added recursive/case-insensitive matching (thanks, Andreas). This
+# slows things down a bit, unfortunately. Give a precise name, and
+# it'll run faster.
+#
+# Version 1.01: Tue May 30 14:47:34 EDT 1995
+# Andy Dougherty <doughera@lafcol.lafayette.edu>
+# -added pod documentation.
+# -added PATH searching.
+# -added searching pod/ subdirectory (mainly to pick up perlfunc.pod
+# and friends.
+#
+#~~~~~~~
+#
+# TODO:
+#
+# Cache the directories read during sloppy match
+# (To disk, or just in-memory?)
+#
+# Backport this to perl 5.005?
+#
+# Implement at least part of the "perlman" interface described
+# in Programming Perl 3e?
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc/BaseTo.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc/BaseTo.pm
new file mode 100644
index 00000000000..6ca2a8c7e54
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc/BaseTo.pm
@@ -0,0 +1,28 @@
+
+require 5;
+package Pod::Perldoc::BaseTo;
+use strict;
+use warnings;
+
+sub is_pageable { '' }
+sub write_with_binmode { 1 }
+
+sub output_extension { 'txt' } # override in subclass!
+
+# sub new { my $self = shift; ... }
+# sub parse_from_file( my($class, $in, $out) = ...; ... }
+
+#sub new { return bless {}, ref($_[0]) || $_[0] }
+
+sub _perldoc_elem {
+ my($self, $name) = splice @_,0,2;
+ if(@_) {
+ $self->{$name} = $_[0];
+ } else {
+ $self->{$name};
+ }
+}
+
+
+1;
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc/GetOptsOO.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc/GetOptsOO.pm
new file mode 100644
index 00000000000..b29aeb10906
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc/GetOptsOO.pm
@@ -0,0 +1,106 @@
+
+require 5;
+package Pod::Perldoc::GetOptsOO;
+use strict;
+
+# Rather like Getopt::Std's getopts
+# Call Pod::Perldoc::GetOptsOO::getopts($object, \@ARGV, $truth)
+# Given -n, if there's a opt_n_with, it'll call $object->opt_n_with( ARGUMENT )
+# (e.g., "-n foo" => $object->opt_n_with('foo'). Ditto "-nfoo")
+# Otherwise (given -n) if there's an opt_n, we'll call it $object->opt_n($truth)
+# (Truth defaults to 1)
+# Otherwise we try calling $object->handle_unknown_option('n')
+# (and we increment the error count by the return value of it)
+# If there's no handle_unknown_option, then we just warn, and then increment
+# the error counter
+#
+# The return value of Pod::Perldoc::GetOptsOO::getopts is true if no errors,
+# otherwise it's false.
+#
+## sburke@cpan.org 2002-10-31
+
+BEGIN { # Make a DEBUG constant ASAP
+ *DEBUG = defined( &Pod::Perldoc::DEBUG )
+ ? \&Pod::Perldoc::DEBUG
+ : sub(){10};
+}
+
+
+sub getopts {
+ my($target, $args, $truth) = @_;
+
+ $args ||= \@ARGV;
+
+ $target->aside(
+ "Starting switch processing. Scanning arguments [@$args]\n"
+ ) if $target->can('aside');
+
+ return unless @$args;
+
+ $truth = 1 unless @_ > 2;
+
+ DEBUG > 3 and print " Truth is $truth\n";
+
+
+ my $error_count = 0;
+
+ while( @$args and ($_ = $args->[0]) =~ m/^-(.)(.*)/s ) {
+ my($first,$rest) = ($1,$2);
+ if ($_ eq '--') { # early exit if "--"
+ shift @$args;
+ last;
+ }
+ my $method = "opt_${first}_with";
+ if( $target->can($method) ) { # it's argumental
+ if($rest eq '') { # like -f bar
+ shift @$args;
+ warn "Option $first needs a following argument!\n" unless @$args;
+ $rest = shift @$args;
+ } else { # like -fbar (== -f bar)
+ shift @$args;
+ }
+
+ DEBUG > 3 and print " $method => $rest\n";
+ $target->$method( $rest );
+
+ # Otherwise, it's not argumental...
+ } else {
+
+ if( $target->can( $method = "opt_$first" ) ) {
+ DEBUG > 3 and print " $method is true ($truth)\n";
+ $target->$method( $truth );
+
+ # Otherwise it's an unknown option...
+
+ } elsif( $target->can('handle_unknown_option') ) {
+ DEBUG > 3
+ and print " calling handle_unknown_option('$first')\n";
+
+ $error_count += (
+ $target->handle_unknown_option( $first ) || 0
+ );
+
+ } else {
+ ++$error_count;
+ warn "Unknown option: $first\n";
+ }
+
+ if($rest eq '') { # like -f
+ shift @$args
+ } else { # like -fbar (== -f -bar )
+ DEBUG > 2 and print " Setting args->[0] to \"-$rest\"\n";
+ $args->[0] = "-$rest";
+ }
+ }
+ }
+
+
+ $target->aside(
+ "Ending switch processing. Args are [@$args] with $error_count errors.\n"
+ ) if $target->can('aside');
+
+ $error_count == 0;
+}
+
+1;
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToChecker.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToChecker.pm
new file mode 100644
index 00000000000..c60290d6502
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToChecker.pm
@@ -0,0 +1,72 @@
+
+require 5;
+package Pod::Perldoc::ToChecker;
+use strict;
+use warnings;
+use vars qw(@ISA);
+
+# Pick our superclass...
+#
+eval 'require Pod::Simple::Checker';
+if($@) {
+ require Pod::Checker;
+ @ISA = ('Pod::Checker');
+} else {
+ @ISA = ('Pod::Simple::Checker');
+}
+
+sub is_pageable { 1 }
+sub write_with_binmode { 0 }
+sub output_extension { 'txt' }
+
+sub if_zero_length {
+ my( $self, $file, $tmp, $tmpfd ) = @_;
+ print "No Pod errors in $file\n";
+}
+
+
+1;
+
+__END__
+
+=head1 NAME
+
+Pod::Perldoc::ToChecker - let Perldoc check Pod for errors
+
+=head1 SYNOPSIS
+
+ % perldoc -o checker SomeFile.pod
+ No Pod errors in SomeFile.pod
+ (or an error report)
+
+=head1 DESCRIPTION
+
+This is a "plug-in" class that allows Perldoc to use
+Pod::Simple::Checker as a "formatter" class (or if that is
+not available, then Pod::Checker), to check for errors in a given
+Pod file.
+
+This is actually a Pod::Simple::Checker (or Pod::Checker) subclass, and
+inherits all its options.
+
+=head1 SEE ALSO
+
+L<Pod::Simple::Checker>, L<Pod::Simple>, L<Pod::Checker>, L<Pod::Perldoc>
+
+=head1 COPYRIGHT AND DISCLAIMERS
+
+Copyright (c) 2002 Sean M. Burke. All rights reserved.
+
+This library is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=head1 AUTHOR
+
+Sean M. Burke C<sburke@cpan.org>
+
+=cut
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToMan.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToMan.pm
new file mode 100644
index 00000000000..43191222376
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToMan.pm
@@ -0,0 +1,187 @@
+
+require 5;
+package Pod::Perldoc::ToMan;
+use strict;
+use warnings;
+
+# This class is unlike ToText.pm et al, because we're NOT paging thru
+# the output in our particular format -- we make the output and
+# then we run nroff (or whatever) on it, and then page thru the
+# (plaintext) output of THAT!
+
+use base qw(Pod::Perldoc::BaseTo);
+sub is_pageable { 1 }
+sub write_with_binmode { 0 }
+sub output_extension { 'txt' }
+
+sub __filter_nroff { shift->_perldoc_elem('__filter_nroff' , @_) }
+sub __nroffer { shift->_perldoc_elem('__nroffer' , @_) }
+sub __bindir { shift->_perldoc_elem('__bindir' , @_) }
+sub __pod2man { shift->_perldoc_elem('__pod2man' , @_) }
+sub __output_file { shift->_perldoc_elem('__output_file' , @_) }
+
+sub center { shift->_perldoc_elem('center' , @_) }
+sub date { shift->_perldoc_elem('date' , @_) }
+sub fixed { shift->_perldoc_elem('fixed' , @_) }
+sub fixedbold { shift->_perldoc_elem('fixedbold' , @_) }
+sub fixeditalic { shift->_perldoc_elem('fixeditalic' , @_) }
+sub fixedbolditalic { shift->_perldoc_elem('fixedbolditalic', @_) }
+sub quotes { shift->_perldoc_elem('quotes' , @_) }
+sub release { shift->_perldoc_elem('release' , @_) }
+sub section { shift->_perldoc_elem('section' , @_) }
+
+sub new { return bless {}, ref($_[0]) || $_[0] }
+
+use File::Spec::Functions qw(catfile);
+
+sub parse_from_file {
+ my $self = shift;
+ my($file, $outfh) = @_;
+
+ my $render = $self->{'__nroffer'} || die "no nroffer set!?";
+
+ # turn the switches into CLIs
+ my $switches = join ' ',
+ map qq{"--$_=$self->{$_}"},
+ grep !m/^_/s,
+ keys %$self
+ ;
+
+ my $pod2man =
+ catfile(
+ ($self->{'__bindir'} || die "no bindir set?!" ),
+ ($self->{'__pod2man'} || die "no pod2man set?!" ),
+ )
+ ;
+ unless(-e $pod2man) {
+ # This is rarely needed, I think.
+ $pod2man = $self->{'__pod2man'} || die "no pod2man set?!";
+ die "Can't find a pod2man?! (". $self->{'__pod2man'} .")\nAborting"
+ unless -e $pod2man;
+ }
+
+ my $command = "$pod2man $switches --lax $file | $render -man";
+ # no temp file, just a pipe!
+
+ # Thanks to Brendan O'Dea for contributing the following block
+ if(Pod::Perldoc::IS_Linux and -t STDOUT
+ and my ($cols) = `stty -a` =~ m/\bcolumns\s+(\d+)/
+ ) {
+ my $c = $cols * 39 / 40;
+ $cols = $c > $cols - 2 ? $c : $cols -2;
+ $command .= ' -rLL=' . (int $c) . 'n' if $cols > 80;
+ }
+
+ if(Pod::Perldoc::IS_Cygwin) {
+ $command .= ' -c';
+ }
+
+ # I hear persistent reports that adding a -c switch to $render
+ # solves many people's problems. But I also hear that some mans
+ # don't have a -c switch, so that unconditionally adding it here
+ # would presumably be a Bad Thing -- sburke@cpan.org
+
+ $command .= " | col -x" if Pod::Perldoc::IS_HPUX;
+
+ defined(&Pod::Perldoc::DEBUG)
+ and Pod::Perldoc::DEBUG()
+ and print "About to run $command\n";
+ ;
+
+ my $rslt = `$command`;
+
+ my $err;
+
+ if( $self->{'__filter_nroff'} ) {
+ defined(&Pod::Perldoc::DEBUG)
+ and &Pod::Perldoc::DEBUG()
+ and print "filter_nroff is set, so filtering...\n";
+ $rslt = $self->___Do_filter_nroff($rslt);
+ } else {
+ defined(&Pod::Perldoc::DEBUG)
+ and Pod::Perldoc::DEBUG()
+ and print "filter_nroff isn't set, so not filtering.\n";
+ }
+
+ if (($err = $?)) {
+ defined(&Pod::Perldoc::DEBUG)
+ and Pod::Perldoc::DEBUG()
+ and print "Nonzero exit ($?) while running $command.\n",
+ "Falling back to Pod::Perldoc::ToPod\n ",
+ ;
+ # A desperate fallthru:
+ require Pod::Perldoc::ToPod;
+ return Pod::Perldoc::ToPod->new->parse_from_file(@_);
+
+ } else {
+ print $outfh $rslt
+ or die "Can't print to $$self{__output_file}: $!";
+ }
+
+ return;
+}
+
+
+sub ___Do_filter_nroff {
+ my $self = shift;
+ my @data = split /\n{2,}/, shift;
+
+ shift @data while @data and $data[0] !~ /\S/; # Go to header
+ shift @data if @data and $data[0] =~ /Contributed\s+Perl/; # Skip header
+ pop @data if @data and $data[-1] =~ /^\w/; # Skip footer, like
+ # 28/Jan/99 perl 5.005, patch 53 1
+ join "\n\n", @data;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Pod::Perldoc::ToMan - let Perldoc render Pod as man pages
+
+=head1 SYNOPSIS
+
+ perldoc -o man Some::Modulename
+
+=head1 DESCRIPTION
+
+This is a "plug-in" class that allows Perldoc to use
+Pod::Man and C<nroff> for reading Pod pages.
+
+The following options are supported: center, date, fixed, fixedbold,
+fixeditalic, fixedbolditalic, quotes, release, section
+
+(Those options are explained in L<Pod::Man>.)
+
+For example:
+
+ perldoc -o man -w center:Pod Some::Modulename
+
+=head1 CAVEAT
+
+This module may change to use a different pod-to-nroff formatter class
+in the future, and this may change what options are supported.
+
+=head1 SEE ALSO
+
+L<Pod::Man>, L<Pod::Perldoc>, L<Pod::Perldoc::ToNroff>
+
+=head1 COPYRIGHT AND DISCLAIMERS
+
+Copyright (c) 2002,3,4 Sean M. Burke. All rights reserved.
+
+This library is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=head1 AUTHOR
+
+Sean M. Burke C<sburke@cpan.org>
+
+=cut
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToNroff.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToNroff.pm
new file mode 100644
index 00000000000..d0568605068
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToNroff.pm
@@ -0,0 +1,100 @@
+
+require 5;
+package Pod::Perldoc::ToNroff;
+use strict;
+use warnings;
+
+# This is unlike ToMan.pm in that it emits the raw nroff source!
+
+use base qw(Pod::Perldoc::BaseTo);
+
+sub is_pageable { 1 } # well, if you ask for it...
+sub write_with_binmode { 0 }
+sub output_extension { 'man' }
+
+use Pod::Man ();
+
+sub center { shift->_perldoc_elem('center' , @_) }
+sub date { shift->_perldoc_elem('date' , @_) }
+sub fixed { shift->_perldoc_elem('fixed' , @_) }
+sub fixedbold { shift->_perldoc_elem('fixedbold' , @_) }
+sub fixeditalic { shift->_perldoc_elem('fixeditalic' , @_) }
+sub fixedbolditalic { shift->_perldoc_elem('fixedbolditalic', @_) }
+sub quotes { shift->_perldoc_elem('quotes' , @_) }
+sub release { shift->_perldoc_elem('release' , @_) }
+sub section { shift->_perldoc_elem('section' , @_) }
+
+sub new { return bless {}, ref($_[0]) || $_[0] }
+
+sub parse_from_file {
+ my $self = shift;
+ my $file = $_[0];
+
+ my @options =
+ map {; $_, $self->{$_} }
+ grep !m/^_/s,
+ keys %$self
+ ;
+
+ defined(&Pod::Perldoc::DEBUG)
+ and Pod::Perldoc::DEBUG()
+ and print "About to call new Pod::Man ",
+ $Pod::Man::VERSION ? "(v$Pod::Man::VERSION) " : '',
+ "with options: ",
+ @options ? "[@options]" : "(nil)", "\n";
+ ;
+
+ Pod::Man->new(@options)->parse_from_file(@_);
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Pod::Perldoc::ToNroff - let Perldoc convert Pod to nroff
+
+=head1 SYNOPSIS
+
+ perldoc -o nroff -d something.3 Some::Modulename
+
+=head1 DESCRIPTION
+
+This is a "plug-in" class that allows Perldoc to use
+Pod::Man as a formatter class.
+
+The following options are supported: center, date, fixed, fixedbold,
+fixeditalic, fixedbolditalic, quotes, release, section
+
+Those options are explained in L<Pod::Man>.
+
+For example:
+
+ perldoc -o nroff -w center:Pod -d something.3 Some::Modulename
+
+=head1 CAVEAT
+
+This module may change to use a different pod-to-nroff formatter class
+in the future, and this may change what options are supported.
+
+=head1 SEE ALSO
+
+L<Pod::Man>, L<Pod::Perldoc>, L<Pod::Perldoc::ToMan>
+
+=head1 COPYRIGHT AND DISCLAIMERS
+
+Copyright (c) 2002 Sean M. Burke. All rights reserved.
+
+This library is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=head1 AUTHOR
+
+Sean M. Burke C<sburke@cpan.org>
+
+=cut
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToPod.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToPod.pm
new file mode 100644
index 00000000000..bccbfcadbd6
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToPod.pm
@@ -0,0 +1,90 @@
+
+# This class is just a hack to act as a "formatter" for
+# actually unformatted Pod.
+#
+# Note that this isn't the same as just passing thru whatever
+# we're given -- we pass thru only the pod source, and suppress
+# the Perl code (or whatever non-pod stuff is in the source file).
+
+
+require 5;
+package Pod::Perldoc::ToPod;
+use strict;
+use warnings;
+
+use base qw(Pod::Perldoc::BaseTo);
+sub is_pageable { 1 }
+sub write_with_binmode { 0 }
+sub output_extension { 'pod' }
+
+sub new { return bless {}, ref($_[0]) || $_[0] }
+
+sub parse_from_file {
+ my( $self, $in, $outfh ) = @_;
+
+ open(IN, "<", $in) or die "Can't read-open $in: $!\nAborting";
+
+ my $cut_mode = 1;
+
+ # A hack for finding things between =foo and =cut, inclusive
+ local $_;
+ while (<IN>) {
+ if( m/^=(\w+)/s ) {
+ if($cut_mode = ($1 eq 'cut')) {
+ print $outfh "\n=cut\n\n";
+ # Pass thru the =cut line with some harmless
+ # (and occasionally helpful) padding
+ }
+ }
+ next if $cut_mode;
+ print $outfh $_ or die "Can't print to $outfh: $!";
+ }
+
+ close IN or die "Can't close $in: $!";
+ return;
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Pod::Perldoc::ToPod - let Perldoc render Pod as ... Pod!
+
+=head1 SYNOPSIS
+
+ perldoc -opod Some::Modulename
+
+(That's currently the same as the following:)
+
+ perldoc -u Some::Modulename
+
+=head1 DESCRIPTION
+
+This is a "plug-in" class that allows Perldoc to display Pod source as
+itself! Pretty Zen, huh?
+
+Currently this class works by just filtering out the non-Pod stuff from
+a given input file.
+
+=head1 SEE ALSO
+
+L<Pod::Perldoc>
+
+=head1 COPYRIGHT AND DISCLAIMERS
+
+Copyright (c) 2002 Sean M. Burke. All rights reserved.
+
+This library is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=head1 AUTHOR
+
+Sean M. Burke C<sburke@cpan.org>
+
+=cut
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToRtf.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToRtf.pm
new file mode 100644
index 00000000000..25e609e313a
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToRtf.pm
@@ -0,0 +1,85 @@
+
+require 5;
+package Pod::Perldoc::ToRtf;
+use strict;
+use warnings;
+use vars qw($VERSION);
+
+use base qw( Pod::Simple::RTF );
+
+$VERSION # so that ->VERSION is happy
+# stop CPAN from seeing this
+ =
+$Pod::Simple::RTF::VERSION;
+
+
+sub is_pageable { 0 }
+sub write_with_binmode { 0 }
+sub output_extension { 'rtf' }
+
+sub page_for_perldoc {
+ my($self, $tempfile, $perldoc) = @_;
+ return unless $perldoc->IS_MSWin32;
+
+ my $rtf_pager = $ENV{'RTFREADER'} || 'write.exe';
+
+ $perldoc->aside( "About to launch <\"$rtf_pager\" \"$tempfile\">\n" );
+
+ return 1 if system( qq{"$rtf_pager"}, qq{"$tempfile"} ) == 0;
+ return 0;
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Pod::Perldoc::ToRtf - let Perldoc render Pod as RTF
+
+=head1 SYNOPSIS
+
+ perldoc -o rtf Some::Modulename
+
+=head1 DESCRIPTION
+
+This is a "plug-in" class that allows Perldoc to use
+Pod::Simple::RTF as a formatter class.
+
+This is actually a Pod::Simple::RTF subclass, and inherits
+all its options.
+
+You have to have Pod::Simple::RTF installed (from the Pod::Simple dist),
+or this module won't work.
+
+If Perldoc is running under MSWin and uses this class as a formatter,
+the output will be opened with F<write.exe> or whatever program is
+specified in the environment variable C<RTFREADER>. For example, to
+specify that RTF files should be opened the same as they are when you
+double-click them, you would do C<set RTFREADER=start.exe> in your
+F<autoexec.bat>.
+
+Handy tip: put C<set PERLDOC=-ortf> in your F<autoexec.bat>
+and that will set this class as the default formatter to run when
+you do C<perldoc whatever>.
+
+=head1 SEE ALSO
+
+L<Pod::Simple::RTF>, L<Pod::Simple>, L<Pod::Perldoc>
+
+=head1 COPYRIGHT AND DISCLAIMERS
+
+Copyright (c) 2002 Sean M. Burke. All rights reserved.
+
+This library is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=head1 AUTHOR
+
+Sean M. Burke C<sburke@cpan.org>
+
+=cut
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToText.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToText.pm
new file mode 100644
index 00000000000..2eb9e0644ac
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToText.pm
@@ -0,0 +1,91 @@
+
+require 5;
+package Pod::Perldoc::ToText;
+use strict;
+use warnings;
+
+use base qw(Pod::Perldoc::BaseTo);
+
+sub is_pageable { 1 }
+sub write_with_binmode { 0 }
+sub output_extension { 'txt' }
+
+use Pod::Text ();
+
+sub alt { shift->_perldoc_elem('alt' , @_) }
+sub indent { shift->_perldoc_elem('indent' , @_) }
+sub loose { shift->_perldoc_elem('loose' , @_) }
+sub quotes { shift->_perldoc_elem('quotes' , @_) }
+sub sentence { shift->_perldoc_elem('sentence', @_) }
+sub width { shift->_perldoc_elem('width' , @_) }
+
+sub new { return bless {}, ref($_[0]) || $_[0] }
+
+sub parse_from_file {
+ my $self = shift;
+
+ my @options =
+ map {; $_, $self->{$_} }
+ grep !m/^_/s,
+ keys %$self
+ ;
+
+ defined(&Pod::Perldoc::DEBUG)
+ and Pod::Perldoc::DEBUG()
+ and print "About to call new Pod::Text ",
+ $Pod::Text::VERSION ? "(v$Pod::Text::VERSION) " : '',
+ "with options: ",
+ @options ? "[@options]" : "(nil)", "\n";
+ ;
+
+ Pod::Text->new(@options)->parse_from_file(@_);
+}
+
+1;
+
+=head1 NAME
+
+Pod::Perldoc::ToText - let Perldoc render Pod as plaintext
+
+=head1 SYNOPSIS
+
+ perldoc -o text Some::Modulename
+
+=head1 DESCRIPTION
+
+This is a "plug-in" class that allows Perldoc to use
+Pod::Text as a formatter class.
+
+It supports the following options, which are explained in
+L<Pod::Text>: alt, indent, loose, quotes, sentence, width
+
+For example:
+
+ perldoc -o text -w indent:5 Some::Modulename
+
+=head1 CAVEAT
+
+This module may change to use a different text formatter class in the
+future, and this may change what options are supported.
+
+=head1 SEE ALSO
+
+L<Pod::Text>, L<Pod::Perldoc>
+
+=head1 COPYRIGHT AND DISCLAIMERS
+
+Copyright (c) 2002 Sean M. Burke. All rights reserved.
+
+This library is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=head1 AUTHOR
+
+Sean M. Burke C<sburke@cpan.org>
+
+=cut
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToTk.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToTk.pm
new file mode 100644
index 00000000000..39459629503
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToTk.pm
@@ -0,0 +1,129 @@
+
+require 5;
+package Pod::Perldoc::ToTk;
+use strict;
+use warnings;
+
+use base qw(Pod::Perldoc::BaseTo);
+
+sub is_pageable { 1 }
+sub write_with_binmode { 0 }
+sub output_extension { 'txt' } # doesn't matter
+sub if_zero_length { } # because it will be 0-length!
+sub new { return bless {}, ref($_[0]) || $_[0] }
+
+# TODO: document these and their meanings...
+sub tree { shift->_perldoc_elem('tree' , @_) }
+sub tk_opt { shift->_perldoc_elem('tk_opt' , @_) }
+sub forky { shift->_perldoc_elem('forky' , @_) }
+
+use Pod::Perldoc ();
+use File::Spec::Functions qw(catfile);
+
+use Tk;
+die join '', __PACKAGE__, " doesn't work nice with Tk.pm verison $Tk::VERSION"
+ if $Tk::VERSION eq '800.003';
+
+BEGIN { eval { require Tk::FcyEntry; }; };
+use Tk::Pod;
+
+# The following was adapted from "tkpod" in the Tk-Pod dist.
+
+sub parse_from_file {
+
+ my($self, $Input_File) = @_;
+ if($self->{'forky'}) {
+ return if fork; # i.e., parent process returns
+ }
+
+ $Input_File =~ s{\\}{/}g
+ if Pod::Perldoc::IS_MSWin32 or Pod::Perldoc::IS_Dos
+ # and maybe OS/2
+ ;
+
+ my($tk_opt, $tree);
+ $tree = $self->{'tree' };
+ $tk_opt = $self->{'tk_opt'};
+
+ #require Tk::ErrorDialog;
+
+ # Add 'Tk' subdirectories to search path so, e.g.,
+ # 'Scrolled' will find doc in 'Tk/Scrolled'
+
+ if( $tk_opt ) {
+ push @INC, grep -d $_, map catfile($_,'Tk'), @INC;
+ }
+
+ my $mw = MainWindow->new();
+ #eval 'use blib "/home/e/eserte/src/perl/Tk-App";require Tk::App::Debug';
+ $mw->withdraw;
+
+ # CDE use Font Settings if available
+ my $ufont = $mw->optionGet('userFont','UserFont'); # fixed width
+ my $sfont = $mw->optionGet('systemFont','SystemFont'); # proportional
+ if (defined($ufont) and defined($sfont)) {
+ foreach ($ufont, $sfont) { s/:$//; };
+ $mw->optionAdd('*Font', $sfont);
+ $mw->optionAdd('*Entry.Font', $ufont);
+ $mw->optionAdd('*Text.Font', $ufont);
+ }
+
+ $mw->optionAdd('*Menu.tearOff', $Tk::platform ne 'MSWin32' ? 1 : 0);
+
+ $mw->Pod(
+ '-file' => $Input_File,
+ (($Tk::Pod::VERSION >= 4) ? ('-tree' => $tree) : ())
+ )->focusNext;
+
+ # xxx dirty but it works. A simple $mw->destroy if $mw->children
+ # does not work because Tk::ErrorDialogs could be created.
+ # (they are withdrawn after Ok instead of destory'ed I guess)
+
+ if ($mw->children) {
+ $mw->repeat(1000, sub {
+ # ErrorDialog is withdrawn not deleted :-(
+ foreach ($mw->children) {
+ return if "$_" =~ /^Tk::Pod/ # ->isa('Tk::Pod')
+ }
+ $mw->destroy;
+ });
+ } else {
+ $mw->destroy;
+ }
+ #$mw->WidgetDump;
+ MainLoop();
+
+ exit if $self->{'forky'}; # we were the child! so exit now!
+ return;
+}
+
+1;
+__END__
+
+
+=head1 NAME
+
+Pod::Perldoc::ToTk - let Perldoc use Tk::Pod to render Pod
+
+=head1 SYNOPSIS
+
+ perldoc -o tk Some::Modulename &
+
+=head1 DESCRIPTION
+
+This is a "plug-in" class that allows Perldoc to use
+Tk::Pod as a formatter class.
+
+You have to have installed Tk::Pod first, or this class won't load.
+
+=head1 SEE ALSO
+
+L<Tk::Pod>, L<Pod::Perldoc>
+
+=head1 AUTHOR
+
+Sean M. Burke C<sburke@cpan.org>, with significant portions copied from
+F<tkpod> in the Tk::Pod dist, by Nick Ing-Simmons, Slaven Rezic, et al.
+
+=cut
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToXml.pm b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToXml.pm
new file mode 100644
index 00000000000..dd0d15cc10b
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Perldoc/ToXml.pm
@@ -0,0 +1,63 @@
+
+require 5;
+package Pod::Perldoc::ToXml;
+use strict;
+use warnings;
+use vars qw($VERSION);
+
+use base qw( Pod::Simple::XMLOutStream );
+
+$VERSION # so that ->VERSION is happy
+# stop CPAN from seeing this
+ =
+$Pod::Simple::XMLOutStream::VERSION;
+
+
+sub is_pageable { 0 }
+sub write_with_binmode { 0 }
+sub output_extension { 'xml' }
+
+1;
+__END__
+
+=head1 NAME
+
+Pod::Perldoc::ToXml - let Perldoc render Pod as XML
+
+=head1 SYNOPSIS
+
+ perldoc -o xml -d out.xml Some::Modulename
+
+=head1 DESCRIPTION
+
+This is a "plug-in" class that allows Perldoc to use
+Pod::Simple::XMLOutStream as a formatter class.
+
+This is actually a Pod::Simple::XMLOutStream subclass, and inherits
+all its options.
+
+You have to have installed Pod::Simple::XMLOutStream (from the Pod::Simple
+dist), or this class won't work.
+
+
+=head1 SEE ALSO
+
+L<Pod::Simple::XMLOutStream>, L<Pod::Simple>, L<Pod::Perldoc>
+
+=head1 COPYRIGHT AND DISCLAIMERS
+
+Copyright (c) 2002 Sean M. Burke. All rights reserved.
+
+This library is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=head1 AUTHOR
+
+Sean M. Burke C<sburke@cpan.org>
+
+=cut
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/PlainText.pm b/Master/tlpkg/tlperl/lib/Pod/PlainText.pm
new file mode 100644
index 00000000000..3f5ce90d2ba
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/PlainText.pm
@@ -0,0 +1,705 @@
+# Pod::PlainText -- Convert POD data to formatted ASCII text.
+# $Id: Text.pm,v 2.1 1999/09/20 11:53:33 eagle Exp $
+#
+# Copyright 1999-2000 by Russ Allbery <rra@stanford.edu>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the same terms as Perl itself.
+#
+# This module is intended to be a replacement for Pod::Text, 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.
+
+############################################################################
+# Modules and declarations
+############################################################################
+
+package Pod::PlainText;
+
+require 5.005;
+
+use Carp qw(carp croak);
+use Pod::Select ();
+
+use strict;
+use vars qw(@ISA %ESCAPES $VERSION);
+
+# We inherit from Pod::Select instead of Pod::Parser so that we can be used
+# by Pod::Usage.
+@ISA = qw(Pod::Select);
+
+$VERSION = '2.02';
+
+
+############################################################################
+# Table of supported E<> escapes
+############################################################################
+
+# This table is taken near verbatim from Pod::PlainText in Pod::Parser,
+# which got it near verbatim from the original Pod::Text. It is therefore
+# credited to Tom Christiansen, and I'm glad I didn't have to write it. :)
+%ESCAPES = (
+ 'amp' => '&', # ampersand
+ 'lt' => '<', # left chevron, less-than
+ 'gt' => '>', # right chevron, greater-than
+ 'quot' => '"', # double quote
+
+ "Aacute" => "\xC1", # capital A, acute accent
+ "aacute" => "\xE1", # small a, acute accent
+ "Acirc" => "\xC2", # capital A, circumflex accent
+ "acirc" => "\xE2", # small a, circumflex accent
+ "AElig" => "\xC6", # capital AE diphthong (ligature)
+ "aelig" => "\xE6", # small ae diphthong (ligature)
+ "Agrave" => "\xC0", # capital A, grave accent
+ "agrave" => "\xE0", # small a, grave accent
+ "Aring" => "\xC5", # capital A, ring
+ "aring" => "\xE5", # small a, ring
+ "Atilde" => "\xC3", # capital A, tilde
+ "atilde" => "\xE3", # small a, tilde
+ "Auml" => "\xC4", # capital A, dieresis or umlaut mark
+ "auml" => "\xE4", # small a, dieresis or umlaut mark
+ "Ccedil" => "\xC7", # capital C, cedilla
+ "ccedil" => "\xE7", # small c, cedilla
+ "Eacute" => "\xC9", # capital E, acute accent
+ "eacute" => "\xE9", # small e, acute accent
+ "Ecirc" => "\xCA", # capital E, circumflex accent
+ "ecirc" => "\xEA", # small e, circumflex accent
+ "Egrave" => "\xC8", # capital E, grave accent
+ "egrave" => "\xE8", # small e, grave accent
+ "ETH" => "\xD0", # capital Eth, Icelandic
+ "eth" => "\xF0", # small eth, Icelandic
+ "Euml" => "\xCB", # capital E, dieresis or umlaut mark
+ "euml" => "\xEB", # small e, dieresis or umlaut mark
+ "Iacute" => "\xCD", # capital I, acute accent
+ "iacute" => "\xED", # small i, acute accent
+ "Icirc" => "\xCE", # capital I, circumflex accent
+ "icirc" => "\xEE", # small i, circumflex accent
+ "Igrave" => "\xCD", # capital I, grave accent
+ "igrave" => "\xED", # small i, grave accent
+ "Iuml" => "\xCF", # capital I, dieresis or umlaut mark
+ "iuml" => "\xEF", # small i, dieresis or umlaut mark
+ "Ntilde" => "\xD1", # capital N, tilde
+ "ntilde" => "\xF1", # small n, tilde
+ "Oacute" => "\xD3", # capital O, acute accent
+ "oacute" => "\xF3", # small o, acute accent
+ "Ocirc" => "\xD4", # capital O, circumflex accent
+ "ocirc" => "\xF4", # small o, circumflex accent
+ "Ograve" => "\xD2", # capital O, grave accent
+ "ograve" => "\xF2", # small o, grave accent
+ "Oslash" => "\xD8", # capital O, slash
+ "oslash" => "\xF8", # small o, slash
+ "Otilde" => "\xD5", # capital O, tilde
+ "otilde" => "\xF5", # small o, tilde
+ "Ouml" => "\xD6", # capital O, dieresis or umlaut mark
+ "ouml" => "\xF6", # small o, dieresis or umlaut mark
+ "szlig" => "\xDF", # small sharp s, German (sz ligature)
+ "THORN" => "\xDE", # capital THORN, Icelandic
+ "thorn" => "\xFE", # small thorn, Icelandic
+ "Uacute" => "\xDA", # capital U, acute accent
+ "uacute" => "\xFA", # small u, acute accent
+ "Ucirc" => "\xDB", # capital U, circumflex accent
+ "ucirc" => "\xFB", # small u, circumflex accent
+ "Ugrave" => "\xD9", # capital U, grave accent
+ "ugrave" => "\xF9", # small u, grave accent
+ "Uuml" => "\xDC", # capital U, dieresis or umlaut mark
+ "uuml" => "\xFC", # small u, dieresis or umlaut mark
+ "Yacute" => "\xDD", # capital Y, acute accent
+ "yacute" => "\xFD", # small y, acute accent
+ "yuml" => "\xFF", # small y, dieresis or umlaut mark
+
+ "lchevron" => "\xAB", # left chevron (double less than)
+ "rchevron" => "\xBB", # right chevron (double greater than)
+);
+
+
+############################################################################
+# Initialization
+############################################################################
+
+# Initialize the object. Must be sure to call our parent initializer.
+sub initialize {
+ my $self = shift;
+
+ $$self{alt} = 0 unless defined $$self{alt};
+ $$self{indent} = 4 unless defined $$self{indent};
+ $$self{loose} = 0 unless defined $$self{loose};
+ $$self{sentence} = 0 unless defined $$self{sentence};
+ $$self{width} = 76 unless defined $$self{width};
+
+ $$self{INDENTS} = []; # Stack of indentations.
+ $$self{MARGIN} = $$self{indent}; # Current left margin in spaces.
+
+ $self->SUPER::initialize;
+}
+
+
+############################################################################
+# Core overrides
+############################################################################
+
+# Called for each command paragraph. Gets the command, the associated
+# paragraph, the line number, and a Pod::Paragraph object. Just dispatches
+# the command to a method named the same as the command. =cut is handled
+# internally by Pod::Parser.
+sub command {
+ my $self = shift;
+ my $command = shift;
+ return if $command eq 'pod';
+ return if ($$self{EXCLUDE} && $command ne 'end');
+ $self->item ("\n") if defined $$self{ITEM};
+ $command = 'cmd_' . $command;
+ $self->$command (@_);
+}
+
+# Called for a verbatim paragraph. Gets the paragraph, the line number, and
+# a Pod::Paragraph object. Just output it verbatim, but with tabs converted
+# to spaces.
+sub verbatim {
+ my $self = shift;
+ return if $$self{EXCLUDE};
+ $self->item if defined $$self{ITEM};
+ local $_ = shift;
+ return if /^\s*$/;
+ s/^(\s*\S+)/(' ' x $$self{MARGIN}) . $1/gme;
+ $self->output ($_);
+}
+
+# Called for a regular text block. Gets the paragraph, the line number, and
+# a Pod::Paragraph object. Perform interpolation and output the results.
+sub textblock {
+ my $self = shift;
+ return if $$self{EXCLUDE};
+ $self->output ($_[0]), return if $$self{VERBATIM};
+ local $_ = shift;
+ my $line = shift;
+
+ # Perform a little magic to collapse multiple L<> references. This is
+ # here mostly for backwards-compatibility. We'll just rewrite the whole
+ # thing into actual text at this part, bypassing the whole internal
+ # sequence parsing thing.
+ s{
+ (
+ L< # A link of the form L</something>.
+ /
+ (
+ [:\w]+ # The item has to be a simple word...
+ (\(\))? # ...or simple function.
+ )
+ >
+ (
+ ,?\s+(and\s+)? # Allow lots of them, conjuncted.
+ L<
+ /
+ (
+ [:\w]+
+ (\(\))?
+ )
+ >
+ )+
+ )
+ } {
+ local $_ = $1;
+ s%L</([^>]+)>%$1%g;
+ my @items = split /(?:,?\s+(?:and\s+)?)/;
+ my $string = "the ";
+ my $i;
+ for ($i = 0; $i < @items; $i++) {
+ $string .= $items[$i];
+ $string .= ", " if @items > 2 && $i != $#items;
+ $string .= " and " if ($i == $#items - 1);
+ }
+ $string .= " entries elsewhere in this document";
+ $string;
+ }gex;
+
+ # Now actually interpolate and output the paragraph.
+ $_ = $self->interpolate ($_, $line);
+ s/\s+$/\n/;
+ if (defined $$self{ITEM}) {
+ $self->item ($_ . "\n");
+ } else {
+ $self->output ($self->reformat ($_ . "\n"));
+ }
+}
+
+# Called for an interior sequence. Gets the command, argument, and a
+# Pod::InteriorSequence object and is expected to return the resulting text.
+# Calls code, bold, italic, file, and link to handle those types of
+# sequences, and handles S<>, E<>, X<>, and Z<> directly.
+sub interior_sequence {
+ my $self = shift;
+ my $command = shift;
+ local $_ = shift;
+ return '' if ($command eq 'X' || $command eq 'Z');
+
+ # Expand escapes into the actual character now, carping if invalid.
+ if ($command eq 'E') {
+ return $ESCAPES{$_} if defined $ESCAPES{$_};
+ carp "Unknown escape: E<$_>";
+ return "E<$_>";
+ }
+
+ # For all the other sequences, empty content produces no output.
+ return if $_ eq '';
+
+ # For S<>, compress all internal whitespace and then map spaces to \01.
+ # When we output the text, we'll map this back.
+ if ($command eq 'S') {
+ s/\s{2,}/ /g;
+ tr/ /\01/;
+ return $_;
+ }
+
+ # Anything else needs to get dispatched to another method.
+ if ($command eq 'B') { return $self->seq_b ($_) }
+ elsif ($command eq 'C') { return $self->seq_c ($_) }
+ elsif ($command eq 'F') { return $self->seq_f ($_) }
+ elsif ($command eq 'I') { return $self->seq_i ($_) }
+ elsif ($command eq 'L') { return $self->seq_l ($_) }
+ else { carp "Unknown sequence $command<$_>" }
+}
+
+# Called for each paragraph that's actually part of the POD. We take
+# advantage of this opportunity to untabify the input.
+sub preprocess_paragraph {
+ my $self = shift;
+ local $_ = shift;
+ 1 while s/^(.*?)(\t+)/$1 . ' ' x (length ($2) * 8 - length ($1) % 8)/me;
+ $_;
+}
+
+
+############################################################################
+# Command paragraphs
+############################################################################
+
+# All command paragraphs take the paragraph and the line number.
+
+# First level heading.
+sub cmd_head1 {
+ my $self = shift;
+ local $_ = shift;
+ s/\s+$//;
+ $_ = $self->interpolate ($_, shift);
+ if ($$self{alt}) {
+ $self->output ("\n==== $_ ====\n\n");
+ } else {
+ $_ .= "\n" if $$self{loose};
+ $self->output ($_ . "\n");
+ }
+}
+
+# Second level heading.
+sub cmd_head2 {
+ my $self = shift;
+ local $_ = shift;
+ s/\s+$//;
+ $_ = $self->interpolate ($_, shift);
+ if ($$self{alt}) {
+ $self->output ("\n== $_ ==\n\n");
+ } else {
+ $self->output (' ' x ($$self{indent} / 2) . $_ . "\n\n");
+ }
+}
+
+# Start a list.
+sub cmd_over {
+ my $self = shift;
+ local $_ = shift;
+ unless (/^[-+]?\d+\s+$/) { $_ = $$self{indent} }
+ push (@{ $$self{INDENTS} }, $$self{MARGIN});
+ $$self{MARGIN} += ($_ + 0);
+}
+
+# End a list.
+sub cmd_back {
+ my $self = shift;
+ $$self{MARGIN} = pop @{ $$self{INDENTS} };
+ unless (defined $$self{MARGIN}) {
+ carp "Unmatched =back";
+ $$self{MARGIN} = $$self{indent};
+ }
+}
+
+# An individual list item.
+sub cmd_item {
+ my $self = shift;
+ if (defined $$self{ITEM}) { $self->item }
+ local $_ = shift;
+ s/\s+$//;
+ $$self{ITEM} = $self->interpolate ($_);
+}
+
+# Begin a block for a particular translator. Setting VERBATIM triggers
+# special handling in textblock().
+sub cmd_begin {
+ my $self = shift;
+ local $_ = shift;
+ my ($kind) = /^(\S+)/ or return;
+ if ($kind eq 'text') {
+ $$self{VERBATIM} = 1;
+ } else {
+ $$self{EXCLUDE} = 1;
+ }
+}
+
+# End a block for a particular translator. We assume that all =begin/=end
+# pairs are properly closed.
+sub cmd_end {
+ my $self = shift;
+ $$self{EXCLUDE} = 0;
+ $$self{VERBATIM} = 0;
+}
+
+# One paragraph for a particular translator. Ignore it unless it's intended
+# for text, in which case we treat it as a verbatim text block.
+sub cmd_for {
+ my $self = shift;
+ local $_ = shift;
+ my $line = shift;
+ return unless s/^text\b[ \t]*\n?//;
+ $self->verbatim ($_, $line);
+}
+
+
+############################################################################
+# Interior sequences
+############################################################################
+
+# The simple formatting ones. These are here mostly so that subclasses can
+# override them and do more complicated things.
+sub seq_b { return $_[0]{alt} ? "``$_[1]''" : $_[1] }
+sub seq_c { return $_[0]{alt} ? "``$_[1]''" : "`$_[1]'" }
+sub seq_f { return $_[0]{alt} ? "\"$_[1]\"" : $_[1] }
+sub seq_i { return '*' . $_[1] . '*' }
+
+# The complicated one. Handle links. Since this is plain text, we can't
+# actually make any real links, so this is all to figure out what text we
+# print out.
+sub seq_l {
+ my $self = shift;
+ local $_ = shift;
+
+ # Smash whitespace in case we were split across multiple lines.
+ s/\s+/ /g;
+
+ # If we were given any explicit text, just output it.
+ if (/^([^|]+)\|/) { return $1 }
+
+ # Okay, leading and trailing whitespace isn't important; get rid of it.
+ s/^\s+//;
+ s/\s+$//;
+
+ # Default to using the whole content of the link entry as a section
+ # name. Note that L<manpage/> forces a manpage interpretation, as does
+ # something looking like L<manpage(section)>. The latter is an
+ # enhancement over the original Pod::Text.
+ my ($manpage, $section) = ('', $_);
+ if (/^(?:https?|ftp|news):/) {
+ # a URL
+ return $_;
+ } elsif (/^"\s*(.*?)\s*"$/) {
+ $section = '"' . $1 . '"';
+ } elsif (m/^[-:.\w]+(?:\(\S+\))?$/) {
+ ($manpage, $section) = ($_, '');
+ } elsif (m%/%) {
+ ($manpage, $section) = split (/\s*\/\s*/, $_, 2);
+ }
+
+ my $text = '';
+ # Now build the actual output text.
+ if (!length $section) {
+ $text = "the $manpage manpage" if length $manpage;
+ } elsif ($section =~ /^[:\w]+(?:\(\))?/) {
+ $text .= 'the ' . $section . ' entry';
+ $text .= (length $manpage) ? " in the $manpage manpage"
+ : " elsewhere in this document";
+ } else {
+ $section =~ s/^\"\s*//;
+ $section =~ s/\s*\"$//;
+ $text .= 'the section on "' . $section . '"';
+ $text .= " in the $manpage manpage" if length $manpage;
+ }
+ $text;
+}
+
+
+############################################################################
+# List handling
+############################################################################
+
+# 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 = shift;
+ local $_ = shift;
+ my $tag = $$self{ITEM};
+ unless (defined $tag) {
+ carp "item called without tag";
+ return;
+ }
+ undef $$self{ITEM};
+ my $indent = $$self{INDENTS}[-1];
+ unless (defined $indent) { $indent = $$self{indent} }
+ my $space = ' ' x $indent;
+ $space =~ s/^ /:/ if $$self{alt};
+ if (!$_ || /^\s+$/ || ($$self{MARGIN} - $indent < length ($tag) + 1)) {
+ my $margin = $$self{MARGIN};
+ $$self{MARGIN} = $indent;
+ my $output = $self->reformat ($tag);
+ $output =~ s/\n*$/\n/;
+ $self->output ($output);
+ $$self{MARGIN} = $margin;
+ $self->output ($self->reformat ($_)) if /\S/;
+ } else {
+ $_ = $self->reformat ($_);
+ s/^ /:/ if ($$self{alt} && $indent > 0);
+ my $tagspace = ' ' x length $tag;
+ s/^($space)$tagspace/$1$tag/ or warn "Bizarre space in item";
+ $self->output ($_);
+ }
+}
+
+
+############################################################################
+# 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{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/;
+ $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{sentence}) {
+ s/ +$//mg;
+ s/\.\n/. \n/g;
+ s/\n/ /g;
+ s/ +/ /g;
+ } else {
+ s/\s+/ /g;
+ }
+ $self->wrap ($_);
+}
+
+# Output text to the output device.
+sub output { $_[1] =~ tr/\01/ /; print { $_[0]->output_handle } $_[1] }
+
+
+############################################################################
+# 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 -<number>.
+ 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::PlainText->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]) {
+ local *IN;
+ unless (open (IN, $_[0])) {
+ croak ("Can't open $_[0] for reading: $!\n");
+ return;
+ }
+ $_[0] = \*IN;
+ return $parser->parse_from_filehandle (@_);
+ } else {
+ return $parser->parse_from_file (@_);
+ }
+}
+
+
+############################################################################
+# Module return value and documentation
+############################################################################
+
+1;
+__END__
+
+=head1 NAME
+
+Pod::PlainText - Convert POD data to formatted ASCII text
+
+=head1 SYNOPSIS
+
+ use Pod::PlainText;
+ my $parser = Pod::PlainText->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::PlainText is a module that can convert documentation in the POD format (the
+preferred language for documenting Perl) into formatted ASCII. 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::Parser, Pod::PlainText supports the same methods and
+interfaces. See L<Pod::Parser> for all the details; briefly, one creates a
+new parser with C<Pod::PlainText-E<gt>new()> and then calls either
+parse_from_filehandle() or parse_from_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 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 sentence
+
+If set to a true value, Pod::PlainText 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 true.
+
+=item width
+
+The column at which to wrap text on the right-hand side. Defaults to 76.
+
+=back
+
+The standard Pod::Parser method parse_from_filehandle() takes up to two
+arguments, the first being the file handle to read POD from and the second
+being the file handle to write the formatted output to. The first defaults
+to STDIN if not given, and the second defaults to STDOUT. The method
+parse_from_file() is almost identical, except that its two arguments are the
+input and output disk files instead. See L<Pod::Parser> for the specific
+details.
+
+=head1 DIAGNOSTICS
+
+=over 4
+
+=item Bizarre space in item
+
+(W) Something has gone wrong in internal C<=item> processing. This message
+indicates a bug in Pod::PlainText; you should never see it.
+
+=item Can't open %s for reading: %s
+
+(F) Pod::PlainText was invoked via the compatibility mode pod2text() interface
+and the input file it was given could not be opened.
+
+=item Unknown escape: %s
+
+(W) The POD source contained an C<EE<lt>E<gt>> escape that Pod::PlainText didn't
+know about.
+
+=item Unknown sequence: %s
+
+(W) The POD source contained a non-standard internal sequence (something of
+the form C<XE<lt>E<gt>>) that Pod::PlainText didn't know about.
+
+=item Unmatched =back
+
+(W) Pod::PlainText encountered a C<=back> command that didn't correspond to an
+C<=over> command.
+
+=back
+
+=head1 RESTRICTIONS
+
+Embedded Ctrl-As (octal 001) in the input will be mapped to spaces on
+output, due to an internal implementation detail.
+
+=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::Parser,
+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<Pod::Text::Termcap|Pod::Text::Termcap>.
+
+=head1 SEE ALSO
+
+L<Pod::Parser|Pod::Parser>, L<Pod::Text::Termcap|Pod::Text::Termcap>,
+pod2text(1)
+
+=head1 AUTHOR
+
+Please report bugs using L<http://rt.cpan.org>.
+
+Russ Allbery E<lt>rra@stanford.eduE<gt>, based I<very> heavily on the
+original Pod::Text by Tom Christiansen E<lt>tchrist@mox.perl.comE<gt> and
+its conversion to Pod::Parser by Brad Appleton
+E<lt>bradapp@enteract.comE<gt>.
+
+=cut
diff --git a/Master/tlpkg/tlperl/lib/Pod/Plainer.pm b/Master/tlpkg/tlperl/lib/Pod/Plainer.pm
new file mode 100644
index 00000000000..373e8d090af
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Plainer.pm
@@ -0,0 +1,69 @@
+package Pod::Plainer;
+use strict;
+use Pod::Parser;
+our @ISA = qw(Pod::Parser);
+our $VERSION = '0.01';
+
+our %E = qw( < lt > gt );
+
+sub escape_ltgt {
+ (undef, my $text) = @_;
+ $text =~ s/([<>])/E<$E{$1}>/g;
+ $text
+}
+
+sub simple_delimiters {
+ (undef, my $seq) = @_;
+ $seq -> left_delimiter( '<' );
+ $seq -> right_delimiter( '>' );
+ $seq;
+}
+
+sub textblock {
+ my($parser,$text,$line) = @_;
+ print {$parser->output_handle()}
+ $parser->parse_text(
+ { -expand_text => q(escape_ltgt),
+ -expand_seq => q(simple_delimiters) },
+ $text, $line ) -> raw_text();
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Pod::Plainer - Perl extension for converting Pod to old style Pod.
+
+=head1 SYNOPSIS
+
+ use Pod::Plainer;
+
+ my $parser = Pod::Plainer -> new ();
+ $parser -> parse_from_filehandle(\*STDIN);
+
+=head1 DESCRIPTION
+
+Pod::Plainer uses Pod::Parser which takes Pod with the (new)
+'CE<lt>E<lt> .. E<gt>E<gt>' constructs
+and returns the old(er) style with just 'CE<lt>E<gt>';
+'<' and '>' are replaced by 'EE<lt>ltE<gt>' and 'EE<lt>gtE<gt>'.
+
+This can be used to pre-process Pod before using tools which do not
+recognise the new style Pods.
+
+=head2 EXPORT
+
+None by default.
+
+=head1 AUTHOR
+
+Robin Barker, rmb1@cise.npl.co.uk
+
+=head1 SEE ALSO
+
+See L<Pod::Parser>.
+
+=cut
+
diff --git a/Master/tlpkg/tlperl/lib/Pod/Select.pm b/Master/tlpkg/tlperl/lib/Pod/Select.pm
new file mode 100644
index 00000000000..1cc14dff4b6
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Select.pm
@@ -0,0 +1,754 @@
+#############################################################################
+# Pod/Select.pm -- function to select portions of POD docs
+#
+# Copyright (C) 1996-2000 by Bradford Appleton. All rights reserved.
+# This file is part of "PodParser". PodParser is free software;
+# you can redistribute it and/or modify it under the same terms
+# as Perl itself.
+#############################################################################
+
+package Pod::Select;
+
+use vars qw($VERSION);
+$VERSION = 1.30; ## Current version of this package
+require 5.005; ## requires this Perl version or later
+
+#############################################################################
+
+=head1 NAME
+
+Pod::Select, podselect() - extract selected sections of POD from input
+
+=head1 SYNOPSIS
+
+ use Pod::Select;
+
+ ## Select all the POD sections for each file in @filelist
+ ## and print the result on standard output.
+ podselect(@filelist);
+
+ ## Same as above, but write to tmp.out
+ podselect({-output => "tmp.out"}, @filelist):
+
+ ## Select from the given filelist, only those POD sections that are
+ ## within a 1st level section named any of: NAME, SYNOPSIS, OPTIONS.
+ podselect({-sections => ["NAME|SYNOPSIS", "OPTIONS"]}, @filelist):
+
+ ## Select the "DESCRIPTION" section of the PODs from STDIN and write
+ ## the result to STDERR.
+ podselect({-output => ">&STDERR", -sections => ["DESCRIPTION"]}, \*STDIN);
+
+or
+
+ use Pod::Select;
+
+ ## Create a parser object for selecting POD sections from the input
+ $parser = new Pod::Select();
+
+ ## Select all the POD sections for each file in @filelist
+ ## and print the result to tmp.out.
+ $parser->parse_from_file("<&STDIN", "tmp.out");
+
+ ## Select from the given filelist, only those POD sections that are
+ ## within a 1st level section named any of: NAME, SYNOPSIS, OPTIONS.
+ $parser->select("NAME|SYNOPSIS", "OPTIONS");
+ for (@filelist) { $parser->parse_from_file($_); }
+
+ ## Select the "DESCRIPTION" and "SEE ALSO" sections of the PODs from
+ ## STDIN and write the result to STDERR.
+ $parser->select("DESCRIPTION");
+ $parser->add_selection("SEE ALSO");
+ $parser->parse_from_filehandle(\*STDIN, \*STDERR);
+
+=head1 REQUIRES
+
+perl5.005, Pod::Parser, Exporter, Carp
+
+=head1 EXPORTS
+
+podselect()
+
+=head1 DESCRIPTION
+
+B<podselect()> is a function which will extract specified sections of
+pod documentation from an input stream. This ability is provided by the
+B<Pod::Select> module which is a subclass of B<Pod::Parser>.
+B<Pod::Select> provides a method named B<select()> to specify the set of
+POD sections to select for processing/printing. B<podselect()> merely
+creates a B<Pod::Select> object and then invokes the B<podselect()>
+followed by B<parse_from_file()>.
+
+=head1 SECTION SPECIFICATIONS
+
+B<podselect()> and B<Pod::Select::select()> may be given one or more
+"section specifications" to restrict the text processed to only the
+desired set of sections and their corresponding subsections. A section
+specification is a string containing one or more Perl-style regular
+expressions separated by forward slashes ("/"). If you need to use a
+forward slash literally within a section title you can escape it with a
+backslash ("\/").
+
+The formal syntax of a section specification is:
+
+=over 4
+
+=item *
+
+I<head1-title-regex>/I<head2-title-regex>/...
+
+=back
+
+Any omitted or empty regular expressions will default to ".*".
+Please note that each regular expression given is implicitly
+anchored by adding "^" and "$" to the beginning and end. Also, if a
+given regular expression starts with a "!" character, then the
+expression is I<negated> (so C<!foo> would match anything I<except>
+C<foo>).
+
+Some example section specifications follow.
+
+=over 4
+
+=item *
+
+Match the C<NAME> and C<SYNOPSIS> sections and all of their subsections:
+
+C<NAME|SYNOPSIS>
+
+=item *
+
+Match only the C<Question> and C<Answer> subsections of the C<DESCRIPTION>
+section:
+
+C<DESCRIPTION/Question|Answer>
+
+=item *
+
+Match the C<Comments> subsection of I<all> sections:
+
+C</Comments>
+
+=item *
+
+Match all subsections of C<DESCRIPTION> I<except> for C<Comments>:
+
+C<DESCRIPTION/!Comments>
+
+=item *
+
+Match the C<DESCRIPTION> section but do I<not> match any of its subsections:
+
+C<DESCRIPTION/!.+>
+
+=item *
+
+Match all top level sections but none of their subsections:
+
+C</!.+>
+
+=back
+
+=begin _NOT_IMPLEMENTED_
+
+=head1 RANGE SPECIFICATIONS
+
+B<podselect()> and B<Pod::Select::select()> may be given one or more
+"range specifications" to restrict the text processed to only the
+desired ranges of paragraphs in the desired set of sections. A range
+specification is a string containing a single Perl-style regular
+expression (a regex), or else two Perl-style regular expressions
+(regexs) separated by a ".." (Perl's "range" operator is "..").
+The regexs in a range specification are delimited by forward slashes
+("/"). If you need to use a forward slash literally within a regex you
+can escape it with a backslash ("\/").
+
+The formal syntax of a range specification is:
+
+=over 4
+
+=item *
+
+/I<start-range-regex>/[../I<end-range-regex>/]
+
+=back
+
+Where each the item inside square brackets (the ".." followed by the
+end-range-regex) is optional. Each "range-regex" is of the form:
+
+ =cmd-expr text-expr
+
+Where I<cmd-expr> is intended to match the name of one or more POD
+commands, and I<text-expr> is intended to match the paragraph text for
+the command. If a range-regex is supposed to match a POD command, then
+the first character of the regex (the one after the initial '/')
+absolutely I<must> be a single '=' character; it may not be anything
+else (not even a regex meta-character) if it is supposed to match
+against the name of a POD command.
+
+If no I<=cmd-expr> is given then the text-expr will be matched against
+plain textblocks unless it is preceded by a space, in which case it is
+matched against verbatim text-blocks. If no I<text-expr> is given then
+only the command-portion of the paragraph is matched against.
+
+Note that these two expressions are each implicitly anchored. This
+means that when matching against the command-name, there will be an
+implicit '^' and '$' around the given I<=cmd-expr>; and when matching
+against the paragraph text there will be an implicit '\A' and '\Z'
+around the given I<text-expr>.
+
+Unlike with section-specs, the '!' character does I<not> have any special
+meaning (negation or otherwise) at the beginning of a range-spec!
+
+Some example range specifications follow.
+
+=over 4
+
+=item
+Match all C<=for html> paragraphs:
+
+C</=for html/>
+
+=item
+Match all paragraphs between C<=begin html> and C<=end html>
+(note that this will I<not> work correctly if such sections
+are nested):
+
+C</=begin html/../=end html/>
+
+=item
+Match all paragraphs between the given C<=item> name until the end of the
+current section:
+
+C</=item mine/../=head\d/>
+
+=item
+Match all paragraphs between the given C<=item> until the next item, or
+until the end of the itemized list (note that this will I<not> work as
+desired if the item contains an itemized list nested within it):
+
+C</=item mine/../=(item|back)/>
+
+=back
+
+=end _NOT_IMPLEMENTED_
+
+=cut
+
+#############################################################################
+
+use strict;
+#use diagnostics;
+use Carp;
+use Pod::Parser 1.04;
+use vars qw(@ISA @EXPORT $MAX_HEADING_LEVEL);
+
+@ISA = qw(Pod::Parser);
+@EXPORT = qw(&podselect);
+
+## Maximum number of heading levels supported for '=headN' directives
+*MAX_HEADING_LEVEL = \3;
+
+#############################################################################
+
+=head1 OBJECT METHODS
+
+The following methods are provided in this module. Each one takes a
+reference to the object itself as an implicit first parameter.
+
+=cut
+
+##---------------------------------------------------------------------------
+
+## =begin _PRIVATE_
+##
+## =head1 B<_init_headings()>
+##
+## Initialize the current set of active section headings.
+##
+## =cut
+##
+## =end _PRIVATE_
+
+use vars qw(%myData @section_headings);
+
+sub _init_headings {
+ my $self = shift;
+ local *myData = $self;
+
+ ## Initialize current section heading titles if necessary
+ unless (defined $myData{_SECTION_HEADINGS}) {
+ local *section_headings = $myData{_SECTION_HEADINGS} = [];
+ for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
+ $section_headings[$i] = '';
+ }
+ }
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<curr_headings()>
+
+ ($head1, $head2, $head3, ...) = $parser->curr_headings();
+ $head1 = $parser->curr_headings(1);
+
+This method returns a list of the currently active section headings and
+subheadings in the document being parsed. The list of headings returned
+corresponds to the most recently parsed paragraph of the input.
+
+If an argument is given, it must correspond to the desired section
+heading number, in which case only the specified section heading is
+returned. If there is no current section heading at the specified
+level, then C<undef> is returned.
+
+=cut
+
+sub curr_headings {
+ my $self = shift;
+ $self->_init_headings() unless (defined $self->{_SECTION_HEADINGS});
+ my @headings = @{ $self->{_SECTION_HEADINGS} };
+ return (@_ > 0 and $_[0] =~ /^\d+$/) ? $headings[$_[0] - 1] : @headings;
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<select()>
+
+ $parser->select($section_spec1,$section_spec2,...);
+
+This method is used to select the particular sections and subsections of
+POD documentation that are to be printed and/or processed. The existing
+set of selected sections is I<replaced> with the given set of sections.
+See B<add_selection()> for adding to the current set of selected
+sections.
+
+Each of the C<$section_spec> arguments should be a section specification
+as described in L<"SECTION SPECIFICATIONS">. The section specifications
+are parsed by this method and the resulting regular expressions are
+stored in the invoking object.
+
+If no C<$section_spec> arguments are given, then the existing set of
+selected sections is cleared out (which means C<all> sections will be
+processed).
+
+This method should I<not> normally be overridden by subclasses.
+
+=cut
+
+use vars qw(@selected_sections);
+
+sub select {
+ my $self = shift;
+ my @sections = @_;
+ local *myData = $self;
+ local $_;
+
+### NEED TO DISCERN A SECTION-SPEC FROM A RANGE-SPEC (look for m{^/.+/$}?)
+
+ ##---------------------------------------------------------------------
+ ## The following is a blatant hack for backward compatibility, and for
+ ## implementing add_selection(). If the *first* *argument* is the
+ ## string "+", then the remaining section specifications are *added*
+ ## to the current set of selections; otherwise the given section
+ ## specifications will *replace* the current set of selections.
+ ##
+ ## This should probably be fixed someday, but for the present time,
+ ## it seems incredibly unlikely that "+" would ever correspond to
+ ## a legitimate section heading
+ ##---------------------------------------------------------------------
+ my $add = ($sections[0] eq "+") ? shift(@sections) : "";
+
+ ## Reset the set of sections to use
+ unless (@sections > 0) {
+ delete $myData{_SELECTED_SECTIONS} unless ($add);
+ return;
+ }
+ $myData{_SELECTED_SECTIONS} = []
+ unless ($add && exists $myData{_SELECTED_SECTIONS});
+ local *selected_sections = $myData{_SELECTED_SECTIONS};
+
+ ## Compile each spec
+ my $spec;
+ for $spec (@sections) {
+ if ( defined($_ = &_compile_section_spec($spec)) ) {
+ ## Store them in our sections array
+ push(@selected_sections, $_);
+ }
+ else {
+ carp "Ignoring section spec \"$spec\"!\n";
+ }
+ }
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<add_selection()>
+
+ $parser->add_selection($section_spec1,$section_spec2,...);
+
+This method is used to add to the currently selected sections and
+subsections of POD documentation that are to be printed and/or
+processed. See <select()> for replacing the currently selected sections.
+
+Each of the C<$section_spec> arguments should be a section specification
+as described in L<"SECTION SPECIFICATIONS">. The section specifications
+are parsed by this method and the resulting regular expressions are
+stored in the invoking object.
+
+This method should I<not> normally be overridden by subclasses.
+
+=cut
+
+sub add_selection {
+ my $self = shift;
+ $self->select("+", @_);
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<clear_selections()>
+
+ $parser->clear_selections();
+
+This method takes no arguments, it has the exact same effect as invoking
+<select()> with no arguments.
+
+=cut
+
+sub clear_selections {
+ my $self = shift;
+ $self->select();
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<match_section()>
+
+ $boolean = $parser->match_section($heading1,$heading2,...);
+
+Returns a value of true if the given section and subsection heading
+titles match any of the currently selected section specifications in
+effect from prior calls to B<select()> and B<add_selection()> (or if
+there are no explictly selected/deselected sections).
+
+The arguments C<$heading1>, C<$heading2>, etc. are the heading titles of
+the corresponding sections, subsections, etc. to try and match. If
+C<$headingN> is omitted then it defaults to the current corresponding
+section heading title in the input.
+
+This method should I<not> normally be overridden by subclasses.
+
+=cut
+
+sub match_section {
+ my $self = shift;
+ my (@headings) = @_;
+ local *myData = $self;
+
+ ## Return true if no restrictions were explicitly specified
+ my $selections = (exists $myData{_SELECTED_SECTIONS})
+ ? $myData{_SELECTED_SECTIONS} : undef;
+ return 1 unless ((defined $selections) && (@{$selections} > 0));
+
+ ## Default any unspecified sections to the current one
+ my @current_headings = $self->curr_headings();
+ for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
+ (defined $headings[$i]) or $headings[$i] = $current_headings[$i];
+ }
+
+ ## Look for a match against the specified section expressions
+ my ($section_spec, $regex, $negated, $match);
+ for $section_spec ( @{$selections} ) {
+ ##------------------------------------------------------
+ ## Each portion of this spec must match in order for
+ ## the spec to be matched. So we will start with a
+ ## match-value of 'true' and logically 'and' it with
+ ## the results of matching a given element of the spec.
+ ##------------------------------------------------------
+ $match = 1;
+ for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
+ $regex = $section_spec->[$i];
+ $negated = ($regex =~ s/^\!//);
+ $match &= ($negated ? ($headings[$i] !~ /${regex}/)
+ : ($headings[$i] =~ /${regex}/));
+ last unless ($match);
+ }
+ return 1 if ($match);
+ }
+ return 0; ## no match
+}
+
+##---------------------------------------------------------------------------
+
+=head1 B<is_selected()>
+
+ $boolean = $parser->is_selected($paragraph);
+
+This method is used to determine if the block of text given in
+C<$paragraph> falls within the currently selected set of POD sections
+and subsections to be printed or processed. This method is also
+responsible for keeping track of the current input section and
+subsections. It is assumed that C<$paragraph> is the most recently read
+(but not yet processed) input paragraph.
+
+The value returned will be true if the C<$paragraph> and the rest of the
+text in the same section as C<$paragraph> should be selected (included)
+for processing; otherwise a false value is returned.
+
+=cut
+
+sub is_selected {
+ my ($self, $paragraph) = @_;
+ local $_;
+ local *myData = $self;
+
+ $self->_init_headings() unless (defined $myData{_SECTION_HEADINGS});
+
+ ## Keep track of current sections levels and headings
+ $_ = $paragraph;
+ if (/^=((?:sub)*)(?:head(?:ing)?|sec(?:tion)?)(\d*)\s+(.*)\s*$/)
+ {
+ ## This is a section heading command
+ my ($level, $heading) = ($2, $3);
+ $level = 1 + (length($1) / 3) if ((! length $level) || (length $1));
+ ## Reset the current section heading at this level
+ $myData{_SECTION_HEADINGS}->[$level - 1] = $heading;
+ ## Reset subsection headings of this one to empty
+ for (my $i = $level; $i < $MAX_HEADING_LEVEL; ++$i) {
+ $myData{_SECTION_HEADINGS}->[$i] = '';
+ }
+ }
+
+ return $self->match_section();
+}
+
+#############################################################################
+
+=head1 EXPORTED FUNCTIONS
+
+The following functions are exported by this module. Please note that
+these are functions (not methods) and therefore C<do not> take an
+implicit first argument.
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=head1 B<podselect()>
+
+ podselect(\%options,@filelist);
+
+B<podselect> will print the raw (untranslated) POD paragraphs of all
+POD sections in the given input files specified by C<@filelist>
+according to the given options.
+
+If any argument to B<podselect> is a reference to a hash
+(associative array) then the values with the following keys are
+processed as follows:
+
+=over 4
+
+=item B<-output>
+
+A string corresponding to the desired output file (or ">&STDOUT"
+or ">&STDERR"). The default is to use standard output.
+
+=item B<-sections>
+
+A reference to an array of sections specifications (as described in
+L<"SECTION SPECIFICATIONS">) which indicate the desired set of POD
+sections and subsections to be selected from input. If no section
+specifications are given, then all sections of the PODs are used.
+
+=begin _NOT_IMPLEMENTED_
+
+=item B<-ranges>
+
+A reference to an array of range specifications (as described in
+L<"RANGE SPECIFICATIONS">) which indicate the desired range of POD
+paragraphs to be selected from the desired input sections. If no range
+specifications are given, then all paragraphs of the desired sections
+are used.
+
+=end _NOT_IMPLEMENTED_
+
+=back
+
+All other arguments should correspond to the names of input files
+containing POD sections. A file name of "-" or "<&STDIN" will
+be interpeted to mean standard input (which is the default if no
+filenames are given).
+
+=cut
+
+sub podselect {
+ my(@argv) = @_;
+ my %defaults = ();
+ my $pod_parser = new Pod::Select(%defaults);
+ my $num_inputs = 0;
+ my $output = ">&STDOUT";
+ my %opts;
+ local $_;
+ for (@argv) {
+ if (ref($_)) {
+ next unless (ref($_) eq 'HASH');
+ %opts = (%defaults, %{$_});
+
+ ##-------------------------------------------------------------
+ ## Need this for backward compatibility since we formerly used
+ ## options that were all uppercase words rather than ones that
+ ## looked like Unix command-line options.
+ ## to be uppercase keywords)
+ ##-------------------------------------------------------------
+ %opts = map {
+ my ($key, $val) = (lc $_, $opts{$_});
+ $key =~ s/^(?=\w)/-/;
+ $key =~ /^-se[cl]/ and $key = '-sections';
+ #! $key eq '-range' and $key .= 's';
+ ($key => $val);
+ } (keys %opts);
+
+ ## Process the options
+ (exists $opts{'-output'}) and $output = $opts{'-output'};
+
+ ## Select the desired sections
+ $pod_parser->select(@{ $opts{'-sections'} })
+ if ( (defined $opts{'-sections'})
+ && ((ref $opts{'-sections'}) eq 'ARRAY') );
+
+ #! ## Select the desired paragraph ranges
+ #! $pod_parser->select(@{ $opts{'-ranges'} })
+ #! if ( (defined $opts{'-ranges'})
+ #! && ((ref $opts{'-ranges'}) eq 'ARRAY') );
+ }
+ else {
+ $pod_parser->parse_from_file($_, $output);
+ ++$num_inputs;
+ }
+ }
+ $pod_parser->parse_from_file("-") unless ($num_inputs > 0);
+}
+
+#############################################################################
+
+=head1 PRIVATE METHODS AND DATA
+
+B<Pod::Select> makes uses a number of internal methods and data fields
+which clients should not need to see or use. For the sake of avoiding
+name collisions with client data and methods, these methods and fields
+are briefly discussed here. Determined hackers may obtain further
+information about them by reading the B<Pod::Select> source code.
+
+Private data fields are stored in the hash-object whose reference is
+returned by the B<new()> constructor for this class. The names of all
+private methods and data-fields used by B<Pod::Select> begin with a
+prefix of "_" and match the regular expression C</^_\w+$/>.
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=begin _PRIVATE_
+
+=head1 B<_compile_section_spec()>
+
+ $listref = $parser->_compile_section_spec($section_spec);
+
+This function (note it is a function and I<not> a method) takes a
+section specification (as described in L<"SECTION SPECIFICATIONS">)
+given in C<$section_sepc>, and compiles it into a list of regular
+expressions. If C<$section_spec> has no syntax errors, then a reference
+to the list (array) of corresponding regular expressions is returned;
+otherwise C<undef> is returned and an error message is printed (using
+B<carp>) for each invalid regex.
+
+=end _PRIVATE_
+
+=cut
+
+sub _compile_section_spec {
+ my ($section_spec) = @_;
+ my (@regexs, $negated);
+
+ ## Compile the spec into a list of regexs
+ local $_ = $section_spec;
+ s|\\\\|\001|g; ## handle escaped backward slashes
+ s|\\/|\002|g; ## handle escaped forward slashes
+
+ ## Parse the regexs for the heading titles
+ @regexs = split('/', $_, $MAX_HEADING_LEVEL);
+
+ ## Set default regex for ommitted levels
+ for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
+ $regexs[$i] = '.*' unless ((defined $regexs[$i])
+ && (length $regexs[$i]));
+ }
+ ## Modify the regexs as needed and validate their syntax
+ my $bad_regexs = 0;
+ for (@regexs) {
+ $_ .= '.+' if ($_ eq '!');
+ s|\001|\\\\|g; ## restore escaped backward slashes
+ s|\002|\\/|g; ## restore escaped forward slashes
+ $negated = s/^\!//; ## check for negation
+ eval "/$_/"; ## check regex syntax
+ if ($@) {
+ ++$bad_regexs;
+ carp "Bad regular expression /$_/ in \"$section_spec\": $@\n";
+ }
+ else {
+ ## Add the forward and rear anchors (and put the negator back)
+ $_ = '^' . $_ unless (/^\^/);
+ $_ = $_ . '$' unless (/\$$/);
+ $_ = '!' . $_ if ($negated);
+ }
+ }
+ return (! $bad_regexs) ? [ @regexs ] : undef;
+}
+
+##---------------------------------------------------------------------------
+
+=begin _PRIVATE_
+
+=head2 $self->{_SECTION_HEADINGS}
+
+A reference to an array of the current section heading titles for each
+heading level (note that the first heading level title is at index 0).
+
+=end _PRIVATE_
+
+=cut
+
+##---------------------------------------------------------------------------
+
+=begin _PRIVATE_
+
+=head2 $self->{_SELECTED_SECTIONS}
+
+A reference to an array of references to arrays. Each subarray is a list
+of anchored regular expressions (preceded by a "!" if the expression is to
+be negated). The index of the expression in the subarray should correspond
+to the index of the heading title in C<$self-E<gt>{_SECTION_HEADINGS}>
+that it is to be matched against.
+
+=end _PRIVATE_
+
+=cut
+
+#############################################################################
+
+=head1 SEE ALSO
+
+L<Pod::Parser>
+
+=head1 AUTHOR
+
+Please report bugs using L<http://rt.cpan.org>.
+
+Brad Appleton E<lt>bradapp@enteract.comE<gt>
+
+Based on code for B<pod2text> written by
+Tom Christiansen E<lt>tchrist@mox.perl.comE<gt>
+
+=cut
+
+1;
+# vim: ts=4 sw=4 et
diff --git a/Master/tlpkg/tlperl/lib/Pod/Text.pm b/Master/tlpkg/tlperl/lib/Pod/Text.pm
new file mode 100644
index 00000000000..1028f2e9e1b
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Text.pm
@@ -0,0 +1,848 @@
+# Pod::Text -- Convert POD data to formatted ASCII text.
+# $Id: Text.pm,v 2.21 2002/08/04 03:34:58 eagle Exp $
+#
+# Copyright 1999, 2000, 2001, 2002 by Russ Allbery <rra@stanford.edu>
+#
+# This program is free software; you may redistribute it and/or modify it
+# under the same terms as Perl itself.
+#
+# 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.
+#
+# Perl core hackers, please note that this module is also separately
+# maintained outside of the Perl core as part of the podlators. Please send
+# me any patches at the address above in addition to sending them to the
+# standard Perl mailing lists.
+
+##############################################################################
+# Modules and declarations
+##############################################################################
+
+package Pod::Text;
+
+require 5.004;
+
+use Carp qw(carp croak);
+use Exporter ();
+use Pod::ParseLink qw(parselink);
+use Pod::Select ();
+
+use strict;
+use vars qw(@ISA @EXPORT %ESCAPES $VERSION);
+
+# We inherit from Pod::Select instead of Pod::Parser so that we can be used by
+# Pod::Usage.
+@ISA = qw(Pod::Select Exporter);
+
+# We have to export pod2text for backward compatibility.
+@EXPORT = qw(pod2text);
+
+# Don't use the CVS revision as the version, since this module is also in Perl
+# core and too many things could munge CVS magic revision strings. This
+# number should ideally be the same as the CVS revision in podlators, however.
+$VERSION = 2.21;
+
+
+##############################################################################
+# Table of supported E<> escapes
+##############################################################################
+
+# This table is taken near verbatim from Pod::PlainText in Pod::Parser, which
+# got it near verbatim from the original Pod::Text. It is therefore credited
+# to Tom Christiansen, and I'm glad I didn't have to write it. :) "iexcl" to
+# "divide" added by Tim Jenness.
+%ESCAPES = (
+ 'amp' => '&', # ampersand
+ 'apos' => "'", # apostrophe
+ 'lt' => '<', # left chevron, less-than
+ 'gt' => '>', # right chevron, greater-than
+ 'quot' => '"', # double quote
+ 'sol' => '/', # solidus (forward slash)
+ 'verbar' => '|', # vertical bar
+
+ "Aacute" => "\xC1", # capital A, acute accent
+ "aacute" => "\xE1", # small a, acute accent
+ "Acirc" => "\xC2", # capital A, circumflex accent
+ "acirc" => "\xE2", # small a, circumflex accent
+ "AElig" => "\xC6", # capital AE diphthong (ligature)
+ "aelig" => "\xE6", # small ae diphthong (ligature)
+ "Agrave" => "\xC0", # capital A, grave accent
+ "agrave" => "\xE0", # small a, grave accent
+ "Aring" => "\xC5", # capital A, ring
+ "aring" => "\xE5", # small a, ring
+ "Atilde" => "\xC3", # capital A, tilde
+ "atilde" => "\xE3", # small a, tilde
+ "Auml" => "\xC4", # capital A, dieresis or umlaut mark
+ "auml" => "\xE4", # small a, dieresis or umlaut mark
+ "Ccedil" => "\xC7", # capital C, cedilla
+ "ccedil" => "\xE7", # small c, cedilla
+ "Eacute" => "\xC9", # capital E, acute accent
+ "eacute" => "\xE9", # small e, acute accent
+ "Ecirc" => "\xCA", # capital E, circumflex accent
+ "ecirc" => "\xEA", # small e, circumflex accent
+ "Egrave" => "\xC8", # capital E, grave accent
+ "egrave" => "\xE8", # small e, grave accent
+ "ETH" => "\xD0", # capital Eth, Icelandic
+ "eth" => "\xF0", # small eth, Icelandic
+ "Euml" => "\xCB", # capital E, dieresis or umlaut mark
+ "euml" => "\xEB", # small e, dieresis or umlaut mark
+ "Iacute" => "\xCD", # capital I, acute accent
+ "iacute" => "\xED", # small i, acute accent
+ "Icirc" => "\xCE", # capital I, circumflex accent
+ "icirc" => "\xEE", # small i, circumflex accent
+ "Igrave" => "\xCC", # capital I, grave accent
+ "igrave" => "\xEC", # small i, grave accent
+ "Iuml" => "\xCF", # capital I, dieresis or umlaut mark
+ "iuml" => "\xEF", # small i, dieresis or umlaut mark
+ "Ntilde" => "\xD1", # capital N, tilde
+ "ntilde" => "\xF1", # small n, tilde
+ "Oacute" => "\xD3", # capital O, acute accent
+ "oacute" => "\xF3", # small o, acute accent
+ "Ocirc" => "\xD4", # capital O, circumflex accent
+ "ocirc" => "\xF4", # small o, circumflex accent
+ "Ograve" => "\xD2", # capital O, grave accent
+ "ograve" => "\xF2", # small o, grave accent
+ "Oslash" => "\xD8", # capital O, slash
+ "oslash" => "\xF8", # small o, slash
+ "Otilde" => "\xD5", # capital O, tilde
+ "otilde" => "\xF5", # small o, tilde
+ "Ouml" => "\xD6", # capital O, dieresis or umlaut mark
+ "ouml" => "\xF6", # small o, dieresis or umlaut mark
+ "szlig" => "\xDF", # small sharp s, German (sz ligature)
+ "THORN" => "\xDE", # capital THORN, Icelandic
+ "thorn" => "\xFE", # small thorn, Icelandic
+ "Uacute" => "\xDA", # capital U, acute accent
+ "uacute" => "\xFA", # small u, acute accent
+ "Ucirc" => "\xDB", # capital U, circumflex accent
+ "ucirc" => "\xFB", # small u, circumflex accent
+ "Ugrave" => "\xD9", # capital U, grave accent
+ "ugrave" => "\xF9", # small u, grave accent
+ "Uuml" => "\xDC", # capital U, dieresis or umlaut mark
+ "uuml" => "\xFC", # small u, dieresis or umlaut mark
+ "Yacute" => "\xDD", # capital Y, acute accent
+ "yacute" => "\xFD", # small y, acute accent
+ "yuml" => "\xFF", # small y, dieresis or umlaut mark
+
+ "laquo" => "\xAB", # left pointing double angle quotation mark
+ "lchevron" => "\xAB", # synonym (backwards compatibility)
+ "raquo" => "\xBB", # right pointing double angle quotation mark
+ "rchevron" => "\xBB", # synonym (backwards compatibility)
+
+ "iexcl" => "\xA1", # inverted exclamation mark
+ "cent" => "\xA2", # cent sign
+ "pound" => "\xA3", # (UK) pound sign
+ "curren" => "\xA4", # currency sign
+ "yen" => "\xA5", # yen sign
+ "brvbar" => "\xA6", # broken vertical bar
+ "sect" => "\xA7", # section sign
+ "uml" => "\xA8", # diaresis
+ "copy" => "\xA9", # Copyright symbol
+ "ordf" => "\xAA", # feminine ordinal indicator
+ "not" => "\xAC", # not sign
+ "shy" => '', # soft (discretionary) hyphen
+ "reg" => "\xAE", # registered trademark
+ "macr" => "\xAF", # macron, overline
+ "deg" => "\xB0", # degree sign
+ "plusmn" => "\xB1", # plus-minus sign
+ "sup2" => "\xB2", # superscript 2
+ "sup3" => "\xB3", # superscript 3
+ "acute" => "\xB4", # acute accent
+ "micro" => "\xB5", # micro sign
+ "para" => "\xB6", # pilcrow sign = paragraph sign
+ "middot" => "\xB7", # middle dot = Georgian comma
+ "cedil" => "\xB8", # cedilla
+ "sup1" => "\xB9", # superscript 1
+ "ordm" => "\xBA", # masculine ordinal indicator
+ "frac14" => "\xBC", # vulgar fraction one quarter
+ "frac12" => "\xBD", # vulgar fraction one half
+ "frac34" => "\xBE", # vulgar fraction three quarters
+ "iquest" => "\xBF", # inverted question mark
+ "times" => "\xD7", # multiplication sign
+ "divide" => "\xF7", # division sign
+
+ "nbsp" => "\x01", # non-breaking space
+);
+
+
+##############################################################################
+# Initialization
+##############################################################################
+
+# Initialize the object. Must be sure to call our parent initializer.
+sub initialize {
+ my $self = shift;
+
+ $$self{alt} = 0 unless defined $$self{alt};
+ $$self{indent} = 4 unless defined $$self{indent};
+ $$self{margin} = 0 unless defined $$self{margin};
+ $$self{loose} = 0 unless defined $$self{loose};
+ $$self{sentence} = 0 unless defined $$self{sentence};
+ $$self{width} = 76 unless defined $$self{width};
+
+ # Figure out what quotes we'll be using for C<> text.
+ $$self{quotes} ||= '"';
+ if ($$self{quotes} eq 'none') {
+ $$self{LQUOTE} = $$self{RQUOTE} = '';
+ } elsif (length ($$self{quotes}) == 1) {
+ $$self{LQUOTE} = $$self{RQUOTE} = $$self{quotes};
+ } elsif ($$self{quotes} =~ /^(.)(.)$/
+ || $$self{quotes} =~ /^(..)(..)$/) {
+ $$self{LQUOTE} = $1;
+ $$self{RQUOTE} = $2;
+ } else {
+ croak qq(Invalid quote specification "$$self{quotes}");
+ }
+
+ # Stack of indentations.
+ $$self{INDENTS} = [];
+
+ # Current left margin.
+ $$self{MARGIN} = $$self{indent} + $$self{margin};
+
+ $self->SUPER::initialize;
+
+ # Tell Pod::Parser that we want the non-POD stuff too if code was set.
+ $self->parseopts ('-want_nonPODs' => 1) if $$self{code};
+}
+
+
+##############################################################################
+# Core overrides
+##############################################################################
+
+# Called for each command paragraph. Gets the command, the associated
+# paragraph, the line number, and a Pod::Paragraph object. Just dispatches
+# the command to a method named the same as the command. =cut is handled
+# internally by Pod::Parser.
+sub command {
+ my $self = shift;
+ my $command = shift;
+ return if $command eq 'pod';
+ return if ($$self{EXCLUDE} && $command ne 'end');
+ if ($self->can ('cmd_' . $command)) {
+ $command = 'cmd_' . $command;
+ $self->$command (@_);
+ } else {
+ my ($text, $line, $paragraph) = @_;
+ my $file;
+ ($file, $line) = $paragraph->file_line;
+ $text =~ s/\n+\z//;
+ $text = " $text" if ($text =~ /^\S/);
+ warn qq($file:$line: Unknown command paragraph: =$command$text\n);
+ return;
+ }
+}
+
+# Called for a verbatim paragraph. Gets the paragraph, the line number, and a
+# Pod::Paragraph object. Just output it verbatim, but with tabs converted to
+# spaces.
+sub verbatim {
+ my $self = shift;
+ return if $$self{EXCLUDE};
+ $self->item if defined $$self{ITEM};
+ local $_ = shift;
+ return if /^\s*$/;
+ s/^(\s*\S+)/(' ' x $$self{MARGIN}) . $1/gme;
+ $self->output ($_);
+}
+
+# Called for a regular text block. Gets the paragraph, the line number, and a
+# Pod::Paragraph object. Perform interpolation and output the results.
+sub textblock {
+ my $self = shift;
+ return if $$self{EXCLUDE};
+ $self->output ($_[0]), return if $$self{VERBATIM};
+ local $_ = shift;
+ my $line = shift;
+
+ # Interpolate and output the paragraph.
+ $_ = $self->interpolate ($_, $line);
+ s/\s+$/\n/;
+ if (defined $$self{ITEM}) {
+ $self->item ($_ . "\n");
+ } else {
+ $self->output ($self->reformat ($_ . "\n"));
+ }
+}
+
+# Called for a formatting code. Gets the command, argument, and a
+# Pod::InteriorSequence object and is expected to return the resulting text.
+# Calls methods for code, bold, italic, file, and link to handle those types
+# of codes, and handles S<>, E<>, X<>, and Z<> directly.
+sub interior_sequence {
+ local $_;
+ my ($self, $command, $seq);
+ ($self, $command, $_, $seq) = @_;
+
+ # We have to defer processing of the inside of an L<> formatting code. If
+ # this code is nested inside an L<> code, return the literal raw text of
+ # it.
+ my $parent = $seq->nested;
+ while (defined $parent) {
+ return $seq->raw_text if ($parent->cmd_name eq 'L');
+ $parent = $parent->nested;
+ }
+
+ # Index entries are ignored in plain text.
+ return '' if ($command eq 'X' || $command eq 'Z');
+
+ # Expand escapes into the actual character now, warning if invalid.
+ if ($command eq 'E') {
+ if (/^\d+$/) {
+ return chr;
+ } else {
+ return $ESCAPES{$_} if defined $ESCAPES{$_};
+ my ($file, $line) = $seq->file_line;
+ warn "$file:$line: Unknown escape: E<$_>\n";
+ return "E<$_>";
+ }
+ }
+
+ # For all the other formatting codes, empty content produces no output.
+ return if $_ eq '';
+
+ # For S<>, compress all internal whitespace and then map spaces to \01.
+ # When we output the text, we'll map this back.
+ if ($command eq 'S') {
+ s/\s+/ /g;
+ tr/ /\01/;
+ return $_;
+ }
+
+ # Anything else needs to get dispatched to another method.
+ if ($command eq 'B') { return $self->seq_b ($_) }
+ elsif ($command eq 'C') { return $self->seq_c ($_) }
+ elsif ($command eq 'F') { return $self->seq_f ($_) }
+ elsif ($command eq 'I') { return $self->seq_i ($_) }
+ elsif ($command eq 'L') { return $self->seq_l ($_, $seq) }
+ else {
+ my ($file, $line) = $seq->file_line;
+ warn "$file:$line: Unknown formatting code: $command<$_>\n";
+ }
+}
+
+# Called for each paragraph that's actually part of the POD. We take
+# advantage of this opportunity to untabify the input. Also, if given the
+# code option, we may see paragraphs that aren't part of the POD and need to
+# output them directly.
+sub preprocess_paragraph {
+ my $self = shift;
+ local $_ = shift;
+ 1 while s/^(.*?)(\t+)/$1 . ' ' x (length ($2) * 8 - length ($1) % 8)/me;
+ $self->output_code ($_) if $self->cutting;
+ $_;
+}
+
+
+##############################################################################
+# Command paragraphs
+##############################################################################
+
+# All command paragraphs take the paragraph and the line number.
+
+# First level heading.
+sub cmd_head1 {
+ my ($self, $text, $line) = @_;
+ $self->heading ($text, $line, 0, '====');
+}
+
+# Second level heading.
+sub cmd_head2 {
+ my ($self, $text, $line) = @_;
+ $self->heading ($text, $line, $$self{indent} / 2, '== ');
+}
+
+# Third level heading.
+sub cmd_head3 {
+ my ($self, $text, $line) = @_;
+ $self->heading ($text, $line, $$self{indent} * 2 / 3 + 0.5, '= ');
+}
+
+# Third level heading.
+sub cmd_head4 {
+ my ($self, $text, $line) = @_;
+ $self->heading ($text, $line, $$self{indent} * 3 / 4 + 0.5, '- ');
+}
+
+# Start a list.
+sub cmd_over {
+ my $self = shift;
+ local $_ = shift;
+ $self->item ("\n\n") if defined $$self{ITEM};
+ unless (/^[-+]?\d+\s+$/) { $_ = $$self{indent} }
+ push (@{ $$self{INDENTS} }, $$self{MARGIN});
+ $$self{MARGIN} += ($_ + 0);
+}
+
+# End a list.
+sub cmd_back {
+ my ($self, $text, $line, $paragraph) = @_;
+ $self->item ("\n\n") if defined $$self{ITEM};
+ $$self{MARGIN} = pop @{ $$self{INDENTS} };
+ unless (defined $$self{MARGIN}) {
+ my $file;
+ ($file, $line) = $paragraph->file_line;
+ warn "$file:$line: Unmatched =back\n";
+ $$self{MARGIN} = $$self{indent};
+ }
+}
+
+# An individual list item.
+sub cmd_item {
+ my $self = shift;
+ if (defined $$self{ITEM}) { $self->item }
+ local $_ = shift;
+ s/\s+$//;
+ $$self{ITEM} = $_ ? $self->interpolate ($_) : '*';
+}
+
+# Begin a block for a particular translator. Setting VERBATIM triggers
+# special handling in textblock().
+sub cmd_begin {
+ my $self = shift;
+ local $_ = shift;
+ my ($kind) = /^(\S+)/ or return;
+ if ($kind eq 'text') {
+ $$self{VERBATIM} = 1;
+ } else {
+ $$self{EXCLUDE} = 1;
+ }
+}
+
+# End a block for a particular translator. We assume that all =begin/=end
+# pairs are properly closed.
+sub cmd_end {
+ my $self = shift;
+ $$self{EXCLUDE} = 0;
+ $$self{VERBATIM} = 0;
+}
+
+# One paragraph for a particular translator. Ignore it unless it's intended
+# for text, in which case we treat it as a verbatim text block.
+sub cmd_for {
+ my $self = shift;
+ local $_ = shift;
+ my $line = shift;
+ return unless s/^text\b[ \t]*\n?//;
+ $self->verbatim ($_, $line);
+}
+
+
+##############################################################################
+# Formatting codes
+##############################################################################
+
+# The simple ones. These are here mostly so that subclasses can override them
+# and do more complicated things.
+sub seq_b { return $_[0]{alt} ? "``$_[1]''" : $_[1] }
+sub seq_f { return $_[0]{alt} ? "\"$_[1]\"" : $_[1] }
+sub seq_i { return '*' . $_[1] . '*' }
+
+# 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 seq_c {
+ 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 = '(?: \[.*\] | \{.*\} )?';
+
+ # 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
+ | \` .* \' # `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 $_;
+
+ # If we didn't return, go ahead and quote the text.
+ return $$self{alt} ? "``$_''" : "$$self{LQUOTE}$_$$self{RQUOTE}";
+}
+
+# Handle links. Since this is plain text, we can't actually make any real
+# links, so this is all to figure out what text we print out. Most of the
+# work is done by Pod::ParseLink.
+sub seq_l {
+ my ($self, $link, $seq) = @_;
+ my ($text, $type) = (parselink ($link))[1,4];
+ my ($file, $line) = $seq->file_line;
+ $text = $self->interpolate ($text, $line);
+ $text = '<' . $text . '>' if $type eq 'url';
+ return $text || '';
+}
+
+
+##############################################################################
+# Header handling
+##############################################################################
+
+# The common code for handling all headers. Takes the interpolated header
+# text, the line number, the indentation, and the surrounding marker for the
+# alt formatting method.
+sub heading {
+ my ($self, $text, $line, $indent, $marker) = @_;
+ $self->item ("\n\n") if defined $$self{ITEM};
+ $text =~ s/\s+$//;
+ $text = $self->interpolate ($text, $line);
+ if ($$self{alt}) {
+ my $closemark = reverse (split (//, $marker));
+ my $margin = ' ' x $$self{margin};
+ $self->output ("\n" . "$margin$marker $text $closemark" . "\n\n");
+ } else {
+ $text .= "\n" if $$self{loose};
+ my $margin = ' ' x ($$self{margin} + $indent);
+ $self->output ($margin . $text . "\n");
+ }
+}
+
+
+##############################################################################
+# List handling
+##############################################################################
+
+# 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 = shift;
+ local $_ = shift;
+ my $tag = $$self{ITEM};
+ unless (defined $tag) {
+ carp "Item called without tag";
+ return;
+ }
+ undef $$self{ITEM};
+ my $indent = $$self{INDENTS}[-1];
+ unless (defined $indent) { $indent = $$self{indent} }
+ my $margin = ' ' x $$self{margin};
+ if (!$_ || /^\s+$/ || ($$self{MARGIN} - $indent < length ($tag) + 1)) {
+ my $realindent = $$self{MARGIN};
+ $$self{MARGIN} = $indent;
+ my $output = $self->reformat ($tag);
+ $output =~ s/^$margin /$margin:/ if ($$self{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 $_ && $_ =~ /^\s*$/;
+
+ $self->output ($output);
+ $$self{MARGIN} = $realindent;
+ $self->output ($self->reformat ($_)) if $_ && /\S/;
+ } else {
+ my $space = ' ' x $indent;
+ $space =~ s/^$margin /$margin:/ if $$self{alt};
+ $_ = $self->reformat ($_);
+ s/^$margin /$margin:/ if ($$self{alt} && $indent > 0);
+ my $tagspace = ' ' x length $tag;
+ s/^($space)$tagspace/$1$tag/ or warn "Bizarre space in item";
+ $self->output ($_);
+ }
+}
+
+
+##############################################################################
+# 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{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/;
+ $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{sentence}) {
+ s/ +$//mg;
+ s/\.\n/. \n/g;
+ s/\n/ /g;
+ s/ +/ /g;
+ } else {
+ s/\s+/ /g;
+ }
+ $self->wrap ($_);
+}
+
+# Output text to the output device.
+sub output { $_[1] =~ tr/\01/ /; print { $_[0]->output_handle } $_[1] }
+
+# 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]) }
+
+
+##############################################################################
+# 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 -<number>.
+ 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;
+ return $parser->parse_from_filehandle (@fhs);
+ } else {
+ return $parser->parse_from_file (@_);
+ }
+}
+
+
+##############################################################################
+# Module return value and documentation
+##############################################################################
+
+1;
+__END__
+
+=head1 NAME
+
+Pod::Text - Convert POD data to formatted ASCII text
+
+=head1 SYNOPSIS
+
+ use Pod::Text;
+ my $parser = Pod::Text->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 is a module that can convert documentation in the POD format (the
+preferred language for documenting Perl) into formatted ASCII. 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::Parser, Pod::Text supports the same methods and
+interfaces. See L<Pod::Parser> for all the details; briefly, one creates a
+new parser with C<< Pod::Text->new() >> and then calls either
+parse_from_filehandle() or parse_from_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 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<indent> option. To set the right
+margin, see the I<width> option.
+
+=item quotes
+
+Sets the quote marks used to surround CE<lt>> text. If the value is a
+single character, it is used as both the left and right quote; if it is two
+characters, the first character is used as the left quote and the second as
+the right quoted; and if it is four characters, the first two are used as
+the left quote and the second two as the right quote.
+
+This may also be set to the special value C<none>, in which case no quote
+marks are added around CE<lt>> 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 true.
+
+=item width
+
+The column at which to wrap text on the right-hand side. Defaults to 76.
+
+=back
+
+The standard Pod::Parser method parse_from_filehandle() takes up to two
+arguments, the first being the file handle to read POD from and the second
+being the file handle to write the formatted output to. The first defaults
+to STDIN if not given, and the second defaults to STDOUT. The method
+parse_from_file() is almost identical, except that its two arguments are the
+input and output disk files instead. See L<Pod::Parser> for the specific
+details.
+
+=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 quote specification "%s"
+
+(F) The quote specification given (the quotes option to the constructor) was
+invalid. A quote specification must be one, two, or four characters long.
+
+=item %s:%d: Unknown command paragraph: %s
+
+(W) The POD source contained a non-standard command paragraph (something of
+the form C<=command args>) that Pod::Man didn't know about. It was ignored.
+
+=item %s:%d: Unknown escape: %s
+
+(W) The POD source contained an C<EE<lt>E<gt>> escape that Pod::Text didn't
+know about.
+
+=item %s:%d: Unknown formatting code: %s
+
+(W) The POD source contained a non-standard formatting code (something of
+the form C<XE<lt>E<gt>>) that Pod::Text didn't know about.
+
+=item %s:%d: Unmatched =back
+
+(W) Pod::Text encountered a C<=back> command that didn't correspond to an
+C<=over> command.
+
+=back
+
+=head1 RESTRICTIONS
+
+Embedded Ctrl-As (octal 001) in the input will be mapped to spaces on
+output, due to an internal implementation detail.
+
+=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::Parser,
+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<Pod::Text::Termcap>.
+
+=head1 SEE ALSO
+
+L<Pod::Parser>, L<Pod::Text::Termcap>, L<pod2text(1)>
+
+The current version of this module is always available from its web site at
+L<http://www.eyrie.org/~eagle/software/podlators/>. It is also part of the
+Perl core distribution as of 5.6.0.
+
+=head1 AUTHOR
+
+Russ Allbery <rra@stanford.edu>, based I<very> heavily on the original
+Pod::Text by Tom Christiansen <tchrist@mox.perl.com> and its conversion to
+Pod::Parser by Brad Appleton <bradapp@enteract.com>.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 1999, 2000, 2001, 2002 by Russ Allbery <rra@stanford.edu>.
+
+This program is free software; you may redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut
diff --git a/Master/tlpkg/tlperl/lib/Pod/Text/Color.pm b/Master/tlpkg/tlperl/lib/Pod/Text/Color.pm
new file mode 100644
index 00000000000..2ba31369b96
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Text/Color.pm
@@ -0,0 +1,145 @@
+# Pod::Text::Color -- Convert POD data to formatted color ASCII text
+# $Id: Color.pm,v 1.4 2002/07/15 05:46:00 eagle Exp $
+#
+# Copyright 1999, 2001 by Russ Allbery <rra@stanford.edu>
+#
+# This program is free software; you may redistribute it and/or modify it
+# under the same terms as Perl itself.
+#
+# 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.
+
+##############################################################################
+# Modules and declarations
+##############################################################################
+
+package Pod::Text::Color;
+
+require 5.004;
+
+use Pod::Text ();
+use Term::ANSIColor qw(colored);
+
+use strict;
+use vars qw(@ISA $VERSION);
+
+@ISA = qw(Pod::Text);
+
+# Don't use the CVS revision as the version, since this module is also in Perl
+# core and too many things could munge CVS magic revision strings. This
+# number should ideally be the same as the CVS revision in podlators, however.
+$VERSION = 1.04;
+
+
+##############################################################################
+# Overrides
+##############################################################################
+
+# Make level one headings bold.
+sub cmd_head1 {
+ my $self = shift;
+ local $_ = shift;
+ s/\s+$//;
+ $self->SUPER::cmd_head1 (colored ($_, 'bold'));
+}
+
+# Make level two headings bold.
+sub cmd_head2 {
+ my $self = shift;
+ local $_ = shift;
+ s/\s+$//;
+ $self->SUPER::cmd_head2 (colored ($_, 'bold'));
+}
+
+# Fix the various formatting codes.
+sub seq_b { return colored ($_[1], 'bold') }
+sub seq_f { return colored ($_[1], 'cyan') }
+sub seq_i { return colored ($_[1], 'yellow') }
+
+# Output any included code in green.
+sub output_code {
+ my ($self, $code) = @_;
+ $code = colored ($code, 'green');
+ $self->output ($code);
+}
+
+# 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{width} - $$self{MARGIN};
+ while (length > $width) {
+ if (s/^((?:(?:\e\[[\d;]+m)?[^\n]){0,$width})\s+//
+ || s/^((?:(?:\e\[[\d;]+m)?[^\n]){$width})//) {
+ $output .= $spaces . $1 . "\n";
+ } else {
+ last;
+ }
+ }
+ $output .= $spaces . $_;
+ $output =~ s/\s+$/\n\n/;
+ $output;
+}
+
+##############################################################################
+# Module return value and documentation
+##############################################################################
+
+1;
+__END__
+
+=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<Pod::Text> 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<pod2text> should be taught about those.
+
+=head1 SEE ALSO
+
+L<Pod::Text>, L<Pod::Parser>
+
+The current version of this module is always available from its web site at
+L<http://www.eyrie.org/~eagle/software/podlators/>. It is also part of the
+Perl core distribution as of 5.6.0.
+
+=head1 AUTHOR
+
+Russ Allbery <rra@stanford.edu>.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 1999, 2001 by Russ Allbery <rra@stanford.edu>.
+
+This program is free software; you may redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut
diff --git a/Master/tlpkg/tlperl/lib/Pod/Text/Overstrike.pm b/Master/tlpkg/tlperl/lib/Pod/Text/Overstrike.pm
new file mode 100644
index 00000000000..8ba918396c1
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Text/Overstrike.pm
@@ -0,0 +1,208 @@
+# Pod::Text::Overstrike -- Convert POD data to formatted overstrike text
+# $Id: Overstrike.pm,v 1.10 2002/08/04 03:35:01 eagle Exp $
+#
+# Created by Joe Smith <Joe.Smith@inwap.com> 30-Nov-2000
+# (based on Pod::Text::Color by Russ Allbery <rra@stanford.edu>)
+#
+# This program is free software; you may redistribute it and/or modify it
+# under the same terms as Perl itself.
+#
+# 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.
+
+##############################################################################
+# Modules and declarations
+##############################################################################
+
+package Pod::Text::Overstrike;
+
+require 5.004;
+
+use Pod::Text ();
+
+use strict;
+use vars qw(@ISA $VERSION);
+
+@ISA = qw(Pod::Text);
+
+# Don't use the CVS revision as the version, since this module is also in Perl
+# core and too many things could munge CVS magic revision strings. This
+# number should ideally be the same as the CVS revision in podlators, however.
+$VERSION = 1.10;
+
+
+##############################################################################
+# Overrides
+##############################################################################
+
+# Make level one headings bold, overridding any existing formatting.
+sub cmd_head1 {
+ my ($self, $text, $line) = @_;
+ $text =~ s/\s+$//;
+ $text = $self->strip_format ($self->interpolate ($text, $line));
+ $text =~ s/(.)/$1\b$1/g;
+ $self->SUPER::cmd_head1 ($text);
+}
+
+# Make level two headings bold, overriding any existing formatting.
+sub cmd_head2 {
+ my ($self, $text, $line) = @_;
+ $text =~ s/\s+$//;
+ $text = $self->strip_format ($self->interpolate ($text, $line));
+ $text =~ s/(.)/$1\b$1/g;
+ $self->SUPER::cmd_head2 ($text);
+}
+
+# Make level three headings underscored, overriding any existing formatting.
+sub cmd_head3 {
+ my ($self, $text, $line) = @_;
+ $text =~ s/\s+$//;
+ $text = $self->strip_format ($self->interpolate ($text, $line));
+ $text =~ s/(.)/_\b$1/g;
+ $self->SUPER::cmd_head3 ($text);
+}
+
+# Level four headings look like level three headings.
+sub cmd_head4 {
+ my ($self, $text, $line) = @_;
+ $text =~ s/\s+$//;
+ $text = $self->strip_format ($self->interpolate ($text, $line));
+ $text =~ s/(.)/_\b$1/g;
+ $self->SUPER::cmd_head4 ($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, $line, $indent, $marker) = @_;
+ $self->item ("\n\n") if defined $$self{ITEM};
+ $text .= "\n" if $$self{loose};
+ my $margin = ' ' x ($$self{margin} + $indent);
+ $self->output ($margin . $text . "\n");
+}
+
+# Fix the various formatting codes.
+sub seq_b { local $_ = strip_format (@_); s/(.)/$1\b$1/g; $_ }
+sub seq_f { local $_ = strip_format (@_); s/(.)/_\b$1/g; $_ }
+sub seq_i { local $_ = strip_format (@_); 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);
+}
+
+# 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{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/;
+ $output;
+}
+
+##############################################################################
+# Utility functions
+##############################################################################
+
+# 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;
+}
+
+##############################################################################
+# Module return value and documentation
+##############################################################################
+
+1;
+__END__
+
+=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
+hardcopy terminals and/or lineprinters, yet is readable on softcopy (CRT)
+terminals.
+
+Overstruck text is best viewed by page-at-a-time programs that take
+advantage of the terminal's B<stand-out> and I<underline> capabilities, such
+as the less program on Unix.
+
+Apart from the overstrike, it in all ways functions like Pod::Text. See
+L<Pod::Text> 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 SEE ALSO
+
+L<Pod::Text>, L<Pod::Parser>
+
+The current version of this module is always available from its web site at
+L<http://www.eyrie.org/~eagle/software/podlators/>. It is also part of the
+Perl core distribution as of 5.6.0.
+
+=head1 AUTHOR
+
+Joe Smith <Joe.Smith@inwap.com>, using the framework created by Russ Allbery
+<rra@stanford.edu>.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2000 by Joe Smith <Joe.Smith@inwap.com>.
+Copyright 2001 by Russ Allbery <rra@stanford.edu>.
+
+This program is free software; you may redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut
diff --git a/Master/tlpkg/tlperl/lib/Pod/Text/Termcap.pm b/Master/tlpkg/tlperl/lib/Pod/Text/Termcap.pm
new file mode 100644
index 00000000000..02a7fb9842a
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Pod/Text/Termcap.pm
@@ -0,0 +1,180 @@
+# Pod::Text::Termcap -- Convert POD data to ASCII text with format escapes.
+# $Id: Termcap.pm,v 1.11 2003/07/09 21:52:30 eagle Exp $
+#
+# Copyright 1999, 2001, 2002 by Russ Allbery <rra@stanford.edu>
+#
+# This program is free software; you may redistribute it and/or modify it
+# under the same terms as Perl itself.
+#
+# 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.
+
+##############################################################################
+# Modules and declarations
+##############################################################################
+
+package Pod::Text::Termcap;
+
+require 5.004;
+
+use Pod::Text ();
+use POSIX ();
+use Term::Cap;
+
+use strict;
+use vars qw(@ISA $VERSION);
+
+@ISA = qw(Pod::Text);
+
+# Don't use the CVS revision as the version, since this module is also in Perl
+# core and too many things could munge CVS magic revision strings. This
+# number should ideally be the same as the CVS revision in podlators, however.
+$VERSION = 1.11;
+
+
+##############################################################################
+# Overrides
+##############################################################################
+
+# In the initialization method, grab our terminal characteristics as well as
+# do all the stuff we normally do.
+sub initialize {
+ my $self = shift;
+ my ($ospeed, $term, $termios);
+
+ # $ENV{HOME} is usually not set on Windows. The default Term::Cap path
+ # may not work on Solaris.
+ 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;
+ }
+
+ # Fall back on the ANSI escape sequences if Term::Cap doesn't work.
+ eval { $term = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed } };
+ $$self{BOLD} = $$term{_md} || "\e[1m";
+ $$self{UNDL} = $$term{_us} || "\e[4m";
+ $$self{NORM} = $$term{_me} || "\e[m";
+
+ unless (defined $$self{width}) {
+ $$self{width} = $ENV{COLUMNS} || $$term{_co} || 80;
+ $$self{width} -= 2;
+ }
+
+ $self->SUPER::initialize;
+}
+
+# Make level one headings bold.
+sub cmd_head1 {
+ my $self = shift;
+ local $_ = shift;
+ s/\s+$//;
+ $self->SUPER::cmd_head1 ("$$self{BOLD}$_$$self{NORM}");
+}
+
+# Make level two headings bold.
+sub cmd_head2 {
+ my $self = shift;
+ local $_ = shift;
+ s/\s+$//;
+ $self->SUPER::cmd_head2 ("$$self{BOLD}$_$$self{NORM}");
+}
+
+# Fix up B<> and I<>. Note that we intentionally don't do F<>.
+sub seq_b { my $self = shift; return "$$self{BOLD}$_[0]$$self{NORM}" }
+sub seq_i { my $self = shift; return "$$self{UNDL}$_[0]$$self{NORM}" }
+
+# Output any included code in bold.
+sub output_code {
+ my ($self, $code) = @_;
+ $self->output ($$self{BOLD} . $code . $$self{NORM});
+}
+
+# Override the wrapping code to igore the special sequences.
+sub wrap {
+ my $self = shift;
+ local $_ = shift;
+ my $output = '';
+ my $spaces = ' ' x $$self{MARGIN};
+ my $width = $$self{width} - $$self{MARGIN};
+ my $code = "(?:\Q$$self{BOLD}\E|\Q$$self{UNDL}\E|\Q$$self{NORM}\E)";
+ while (length > $width) {
+ if (s/^((?:$code?[^\n]){0,$width})\s+//
+ || s/^((?:$code?[^\n]){$width})//) {
+ $output .= $spaces . $1 . "\n";
+ } else {
+ last;
+ }
+ }
+ $output .= $spaces . $_;
+ $output =~ s/\s+$/\n\n/;
+ $output;
+}
+
+
+##############################################################################
+# Module return value and documentation
+##############################################################################
+
+1;
+__END__
+
+=head1 NAME
+
+Pod::Text::Termcap - Convert POD data to ASCII text with format escapes
+
+=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<Pod::Text> for details and available options.
+
+=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 SEE ALSO
+
+L<Pod::Text>, L<Pod::Parser>, L<Term::Cap>
+
+The current version of this module is always available from its web site at
+L<http://www.eyrie.org/~eagle/software/podlators/>. It is also part of the
+Perl core distribution as of 5.6.0.
+
+=head1 AUTHOR
+
+Russ Allbery <rra@stanford.edu>.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 1999, 2001, 2002 by Russ Allbery <rra@stanford.edu>.
+
+This program is free software; you may redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut