diff options
author | Nicholas Clark <nick@ccl4.org> | 2009-09-26 16:47:48 +0100 |
---|---|---|
committer | Nicholas Clark <nick@ccl4.org> | 2009-09-26 17:51:17 +0100 |
commit | f4e6b6923ba5d1ff0ca1ddc96955a42cab82e1e4 (patch) | |
tree | f1c5d409b315a50c738e6db0e182631c46c3fa4e /cpan | |
parent | 832db5b145e835174f45afb2c497b046dc1fc2ac (diff) | |
download | perl-f4e6b6923ba5d1ff0ca1ddc96955a42cab82e1e4.tar.gz |
Move podlators from ext/ to cpan/
Diffstat (limited to 'cpan')
29 files changed, 7350 insertions, 0 deletions
diff --git a/cpan/podlators/Makefile.PL b/cpan/podlators/Makefile.PL new file mode 100644 index 0000000000..fb80c342fa --- /dev/null +++ b/cpan/podlators/Makefile.PL @@ -0,0 +1,7 @@ +# core-only Makefile.PL +use ExtUtils::MakeMaker; +WriteMakefile ( + NAME => 'Pod', + DISTNAME => 'podlators', + VERSION_FROM => 'VERSION', +); diff --git a/cpan/podlators/VERSION b/cpan/podlators/VERSION new file mode 100644 index 0000000000..279daa436b --- /dev/null +++ b/cpan/podlators/VERSION @@ -0,0 +1 @@ +$VERSION = '2.2.2'; diff --git a/cpan/podlators/lib/Pod/Man.pm b/cpan/podlators/lib/Pod/Man.pm new file mode 100644 index 0000000000..71a4d7a7f5 --- /dev/null +++ b/cpan/podlators/lib/Pod/Man.pm @@ -0,0 +1,1747 @@ +# Pod::Man -- Convert POD data to formatted *roff input. +# +# Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Russ Allbery <rra@stanford.edu> +# Substantial contributions by Sean Burke <sburke@cpan.org> +# +# 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 strict; +use subs qw(makespace); +use vars qw(@ISA %ESCAPES $PREAMBLE $VERSION); + +use Carp qw(croak); +use Pod::Simple (); +use POSIX qw(strftime); + +@ISA = qw(Pod::Simple); + +$VERSION = '2.22'; + +# Set the debugging level. If someone has inserted a debug function into this +# class already, use that. Otherwise, use any Pod::Simple debug function +# that's defined, and failing that, define a debug level of 10. +BEGIN { + my $parent = defined (&Pod::Simple::DEBUG) ? \&Pod::Simple::DEBUG : undef; + unless (defined &DEBUG) { + *DEBUG = $parent || sub () { 10 }; + } +} + +# Import the ASCII constant from Pod::Simple. This is true iff we're in an +# ASCII-based universe (including such things as ISO 8859-1 and UTF-8), and is +# generally only false for EBCDIC. +BEGIN { *ASCII = \&Pod::Simple::ASCII } + +# Pretty-print a data structure. Only used for debugging. +BEGIN { *pretty = \&Pod::Simple::pretty } + +############################################################################## +# Object initialization +############################################################################## + +# Initialize the object and set various Pod::Simple options that we need. +# Here, we also process any additional options passed to the constructor or +# set up defaults if none were given. Note that all internal object keys are +# in all-caps, reserving all lower-case object keys for Pod::Simple and user +# arguments. +sub new { + my $class = shift; + my $self = $class->SUPER::new; + + # Tell Pod::Simple not to handle S<> by automatically inserting . + $self->nbsp_for_S (1); + + # Tell Pod::Simple to keep whitespace whenever possible. + if ($self->can ('preserve_whitespace')) { + $self->preserve_whitespace (1); + } else { + $self->fullstop_space_harden (1); + } + + # The =for and =begin targets that we accept. + $self->accept_targets (qw/man MAN roff ROFF/); + + # Ensure that contiguous blocks of code are merged together. Otherwise, + # some of the guesswork heuristics don't work right. + $self->merge_text (1); + + # Pod::Simple doesn't do anything useful with our arguments, but we want + # to put them in our object as hash keys and values. This could cause + # problems if we ever clash with Pod::Simple's own internal class + # variables. + %$self = (%$self, @_); + + # Send errors to stderr if requested. + if ($$self{stderr}) { + $self->no_errata_section (1); + $self->complain_stderr (1); + delete $$self{stderr}; + } + + # Initialize various other internal constants based on our arguments. + $self->init_fonts; + $self->init_quotes; + $self->init_page; + + # For right now, default to turning on all of the magic. + $$self{MAGIC_CPP} = 1; + $$self{MAGIC_EMDASH} = 1; + $$self{MAGIC_FUNC} = 1; + $$self{MAGIC_MANREF} = 1; + $$self{MAGIC_SMALLCAPS} = 1; + $$self{MAGIC_VARS} = 1; + + return $self; +} + +# Translate a font string into an escape. +sub toescape { (length ($_[0]) > 1 ? '\f(' : '\f') . $_[0] } + +# Determine which fonts the user wishes to use and store them in the object. +# Regular, italic, bold, and bold-italic are constants, but the fixed width +# fonts may be set by the user. Sets the internal hash key FONTS which is +# used to map our internal font escapes to actual *roff sequences later. +sub init_fonts { + my ($self) = @_; + + # Figure out the fixed-width font. If user-supplied, make sure that they + # are the right length. + for (qw/fixed fixedbold fixeditalic fixedbolditalic/) { + my $font = $$self{$_}; + if (defined ($font) && (length ($font) < 1 || length ($font) > 2)) { + croak qq(roff font should be 1 or 2 chars, not "$font"); + } + } + + # Set the default fonts. We can't be sure portably across different + # implementations what fixed bold-italic may be called (if it's even + # available), so default to just bold. + $$self{fixed} ||= 'CW'; + $$self{fixedbold} ||= 'CB'; + $$self{fixeditalic} ||= 'CI'; + $$self{fixedbolditalic} ||= 'CB'; + + # Set up a table of font escapes. First number is fixed-width, second is + # bold, third is italic. + $$self{FONTS} = { '000' => '\fR', '001' => '\fI', + '010' => '\fB', '011' => '\f(BI', + '100' => toescape ($$self{fixed}), + '101' => toescape ($$self{fixeditalic}), + '110' => toescape ($$self{fixedbold}), + '111' => toescape ($$self{fixedbolditalic}) }; +} + +# Initialize the quotes that we'll be using for C<> text. This requires some +# special handling, both to parse the user parameter if given and to make sure +# that the quotes will be safe against *roff. Sets the internal hash keys +# LQUOTE and RQUOTE. +sub init_quotes { + my ($self) = (@_); + + $$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/\"/\"\"/; +} + +# Initialize the page title information and indentation from our arguments. +sub init_page { + my ($self) = @_; + + # We used to try first to get the version number from a local binary, but + # we shouldn't need that any more. Get the version from the running Perl. + # Work a little magic to handle subversions correctly under both the + # pre-5.6 and the post-5.6 version numbering schemes. + my @version = ($] =~ /^(\d+)\.(\d{3})(\d{0,3})$/); + $version[2] ||= 0; + $version[2] *= 10 ** (3 - length $version[2]); + for (@version) { $_ += 0 } + my $version = join ('.', @version); + + # Set the defaults for page titles and indentation if the user didn't + # override anything. + $$self{center} = 'User Contributed Perl Documentation' + unless defined $$self{center}; + $$self{release} = 'perl v' . $version + unless defined $$self{release}; + $$self{indent} = 4 + unless defined $$self{indent}; + + # Double quotes in things that will be quoted. + for (qw/center release/) { + $$self{$_} =~ s/\"/\"\"/g if $$self{$_}; + } +} + +############################################################################## +# Core parsing +############################################################################## + +# This is the glue that connects the code below with Pod::Simple itself. The +# goal is to convert the event stream coming from the POD parser into method +# calls to handlers once the complete content of a tag has been seen. Each +# paragraph or POD command will have textual content associated with it, and +# as soon as all of a paragraph or POD command has been seen, that content +# will be passed in to the corresponding method for handling that type of +# object. The exceptions are handlers for lists, which have opening tag +# handlers and closing tag handlers that will be called right away. +# +# The internal hash key PENDING is used to store the contents of a tag until +# all of it has been seen. It holds a stack of open tags, each one +# represented by a tuple of the attributes hash for the tag, formatting +# options for the tag (which are inherited), and the contents of the tag. + +# Add a block of text to the contents of the current node, formatting it +# according to the current formatting instructions as we do. +sub _handle_text { + my ($self, $text) = @_; + DEBUG > 3 and print "== $text\n"; + my $tag = $$self{PENDING}[-1]; + $$tag[2] .= $self->format_text ($$tag[1], $text); +} + +# Given an element name, get the corresponding method name. +sub method_for_element { + my ($self, $element) = @_; + $element =~ tr/-/_/; + $element =~ tr/A-Z/a-z/; + $element =~ tr/_a-z0-9//cd; + return $element; +} + +# Handle the start of a new element. If cmd_element is defined, assume that +# we need to collect the entire tree for this element before passing it to the +# element method, and create a new tree into which we'll collect blocks of +# text and nested elements. Otherwise, if start_element is defined, call it. +sub _handle_element_start { + my ($self, $element, $attrs) = @_; + DEBUG > 3 and print "++ $element (<", join ('> <', %$attrs), ">)\n"; + my $method = $self->method_for_element ($element); + + # If we have a command handler, we need to accumulate the contents of the + # tag before calling it. Turn off IN_NAME for any command other than + # <Para> so that IN_NAME isn't still set for the first heading after the + # NAME heading. + if ($self->can ("cmd_$method")) { + DEBUG > 2 and print "<$element> starts saving a tag\n"; + $$self{IN_NAME} = 0 if ($element ne 'Para'); + + # How we're going to format embedded text blocks depends on the tag + # and also depends on our parent tags. Thankfully, inside tags that + # turn off guesswork and reformatting, nothing else can turn it back + # on, so this can be strictly inherited. + my $formatting = $$self{PENDING}[-1][1]; + $formatting = $self->formatting ($formatting, $element); + push (@{ $$self{PENDING} }, [ $attrs, $formatting, '' ]); + DEBUG > 4 and print "Pending: [", pretty ($$self{PENDING}), "]\n"; + } elsif ($self->can ("start_$method")) { + my $method = 'start_' . $method; + $self->$method ($attrs, ''); + } else { + DEBUG > 2 and print "No $method start method, skipping\n"; + } +} + +# Handle the end of an element. If we had a cmd_ method for this element, +# this is where we pass along the tree that we built. Otherwise, if we have +# an end_ method for the element, call that. +sub _handle_element_end { + my ($self, $element) = @_; + DEBUG > 3 and print "-- $element\n"; + my $method = $self->method_for_element ($element); + + # If we have a command handler, pull off the pending text and pass it to + # the handler along with the saved attribute hash. + if ($self->can ("cmd_$method")) { + DEBUG > 2 and print "</$element> stops saving a tag\n"; + my $tag = pop @{ $$self{PENDING} }; + DEBUG > 4 and print "Popped: [", pretty ($tag), "]\n"; + DEBUG > 4 and print "Pending: [", pretty ($$self{PENDING}), "]\n"; + my $method = 'cmd_' . $method; + my $text = $self->$method ($$tag[0], $$tag[2]); + if (defined $text) { + if (@{ $$self{PENDING} } > 1) { + $$self{PENDING}[-1][2] .= $text; + } else { + $self->output ($text); + } + } + } elsif ($self->can ("end_$method")) { + my $method = 'end_' . $method; + $self->$method (); + } else { + DEBUG > 2 and print "No $method end method, skipping\n"; + } +} + +############################################################################## +# General formatting +############################################################################## + +# Return formatting instructions for a new block. Takes the current +# formatting and the new element. Formatting inherits negatively, in the +# sense that if the parent has turned off guesswork, all child elements should +# leave it off. We therefore return a copy of the same formatting +# instructions but possibly with more things turned off depending on the +# element. +sub formatting { + my ($self, $current, $element) = @_; + my %options; + if ($current) { + %options = %$current; + } else { + %options = (guesswork => 1, cleanup => 1, convert => 1); + } + if ($element eq 'Data') { + $options{guesswork} = 0; + $options{cleanup} = 0; + $options{convert} = 0; + } elsif ($element eq 'X') { + $options{guesswork} = 0; + $options{cleanup} = 0; + } elsif ($element eq 'Verbatim' || $element eq 'C') { + $options{guesswork} = 0; + $options{literal} = 1; + } + return \%options; +} + +# Format a text block. Takes a hash of formatting options and the text to +# format. Currently, the only formatting options are guesswork, cleanup, and +# convert, all of which are boolean. +sub format_text { + my ($self, $options, $text) = @_; + my $guesswork = $$options{guesswork} && !$$self{IN_NAME}; + my $cleanup = $$options{cleanup}; + my $convert = $$options{convert}; + my $literal = $$options{literal}; + + # Cleanup just tidies up a few things, telling *roff that the hyphens are + # hard, putting a bit of space between consecutive underscores, and + # escaping backslashes. Be careful not to mangle our character + # translations by doing this before processing character translation. + if ($cleanup) { + $text =~ s/\\/\\e/g; + $text =~ s/-/\\-/g; + $text =~ s/_(?=_)/_\\|/g; + } + + # Normally we do character translation, but we won't even do that in + # <Data> blocks or if UTF-8 output is desired. + if ($convert && !$$self{utf8} && ASCII) { + $text =~ s/([^\x00-\x7F])/$ESCAPES{ord ($1)} || "X"/eg; + } + + # Ensure that *roff doesn't convert literal quotes to UTF-8 single quotes, + # but don't mess up our accept escapes. + if ($literal) { + $text =~ s/(?<!\\\*)\'/\\*\(Aq/g; + $text =~ s/(?<!\\\*)\`/\\\`/g; + } + + # If guesswork is asked for, do that. This involves more substantial + # formatting based on various heuristics that may only be appropriate for + # particular documents. + if ($guesswork) { + $text = $self->guesswork ($text); + } + + return $text; +} + +# Handles C<> text, deciding whether to put \*C` around it or not. This is a +# whole bunch of messy heuristics to try to avoid overquoting, originally from +# Barrie Slaymaker. This largely duplicates similar code in Pod::Text. +sub quote_literal { + my $self = shift; + local $_ = shift; + + # A regex that matches the portion of a variable reference that's the + # array or hash index, separated out just because we want to use it in + # several places in the following regex. + my $index = '(?: \[.*\] | \{.*\} )?'; + + # Check for things that we don't want to quote, and if we find any of + # them, return the string with just a font change and no quoting. + m{ + ^\s* + (?: + ( [\'\`\"] ) .* \1 # already quoted + | \\\*\(Aq .* \\\*\(Aq # quoted and escaped + | \\?\` .* ( \' | \\\*\(Aq ) # `quoted' + | \$+ [\#^]? \S $index # special ($^Foo, $") + | [\$\@%&*]+ \#? [:\'\w]+ $index # plain var or func + | [\$\@%&*]* [:\'\w]+ (?: -> )? \(\s*[^\s,]\s*\) # 0/1-arg func call + | [-+]? ( \d[\d.]* | \.\d+ ) (?: [eE][-+]?\d+ )? # a number + | 0x [a-fA-F\d]+ # a hex constant + ) + \s*\z + }xso and return '\f(FS' . $_ . '\f(FE'; + + # If we didn't return, go ahead and quote the text. + return '\f(FS\*(C`' . $_ . "\\*(C'\\f(FE"; +} + +# Takes a text block to perform guesswork on. Returns the text block with +# formatting codes added. This is the code that marks up various Perl +# constructs and things commonly used in man pages without requiring the user +# to add any explicit markup, and is applied to all non-literal text. We're +# guaranteed that the text we're applying guesswork to does not contain any +# *roff formatting codes. Note that the inserted font sequences must be +# treated later with mapfonts or textmapfonts. +# +# This method is very fragile, both in the regular expressions it uses and in +# the ordering of those modifications. Care and testing is required when +# modifying it. +sub guesswork { + my $self = shift; + local $_ = shift; + DEBUG > 5 and print " Guesswork called on [$_]\n"; + + # By the time we reach this point, all hypens will be escaped by adding a + # backslash. We want to undo that escaping if they're part of regular + # words and there's only a single dash, since that's a real hyphen that + # *roff gets to consider a possible break point. Make sure that a dash + # after the first character of a word stays non-breaking, however. + # + # Note that this is not user-controllable; we pretty much have to do this + # transformation or *roff will mangle the output in unacceptable ways. + s{ + ( (?:\G|^|\s) [\(\"]* [a-zA-Z] ) ( \\- )? + ( (?: [a-zA-Z\']+ \\-)+ ) + ( [a-zA-Z\']+ ) (?= [\)\".?!,;:]* (?:\s|\Z|\\\ ) ) + \b + } { + my ($prefix, $hyphen, $main, $suffix) = ($1, $2, $3, $4); + $hyphen ||= ''; + $main =~ s/\\-/-/g; + $prefix . $hyphen . $main . $suffix; + }egx; + + # Translate "--" into a real em-dash if it's used like one. This means + # that it's either surrounded by whitespace, it follows a regular word, or + # it occurs between two regular words. + if ($$self{MAGIC_EMDASH}) { + s{ (\s) \\-\\- (\s) } { $1 . '\*(--' . $2 }egx; + s{ (\b[a-zA-Z]+) \\-\\- (\s|\Z|[a-zA-Z]+\b) } { $1 . '\*(--' . $2 }egx; + } + + # Make words in all-caps a little bit smaller; they look better that way. + # However, we don't want to change Perl code (like @ARGV), nor do we want + # to fix the MIME in MIME-Version since it looks weird with the + # full-height V. + # + # We change only a string of all caps (2) either at the beginning of the + # line or following regular punctuation (like quotes) or whitespace (1), + # and followed by either similar punctuation, an em-dash, or the end of + # the line (3). + if ($$self{MAGIC_SMALLCAPS}) { + s{ + ( ^ | [\s\(\"\'\`\[\{<>] | \\\ ) # (1) + ( [A-Z] [A-Z] (?: [/A-Z+:\d_\$&] | \\- )* ) # (2) + (?= [\s>\}\]\(\)\'\".?!,;] | \\*\(-- | \\\ | $ ) # (3) + } { + $1 . '\s-1' . $2 . '\s0' + }egx; + } + + # Note that from this point forward, we have to adjust for \s-1 and \s-0 + # strings inserted around things that we've made small-caps if later + # transforms should work on those strings. + + # Italize functions in the form func(), including functions that are in + # all capitals, but don't italize if there's anything between the parens. + # The function must start with an alphabetic character or underscore and + # then consist of word characters or colons. + if ($$self{MAGIC_FUNC}) { + s{ + ( \b | \\s-1 ) + ( [A-Za-z_] ([:\w] | \\s-?[01])+ \(\) ) + } { + $1 . '\f(IS' . $2 . '\f(IE' + }egx; + } + + # Change references to manual pages to put the page name in italics but + # the number in the regular font, with a thin space between the name and + # the number. Only recognize func(n) where func starts with an alphabetic + # character or underscore and contains only word characters, periods (for + # configuration file man pages), or colons, and n is a single digit, + # optionally followed by some number of lowercase letters. Note that this + # does not recognize man page references like perl(l) or socket(3SOCKET). + if ($$self{MAGIC_MANREF}) { + s{ + ( \b | \\s-1 ) + ( [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. Be + # careful not to convert functions, though; there are too many subtleties + # with them to want to perform this transformation. + if ($$self{MAGIC_VARS}) { + s{ + ( ^ | \s+ ) + ( [\$\@%] [\w:]+ ) + (?! \( ) + } { + $1 . '\f(FS' . $2 . '\f(FE' + }egx; + } + + # Fix up double quotes. Unfortunately, we miss this transformation if the + # quoted text contains any code with formatting codes and there's not much + # we can effectively do about that, which makes it somewhat unclear if + # this is really a good idea. + s{ \" ([^\"]+) \" } { '\*(L"' . $1 . '\*(R"' }egx; + + # Make C++ into \*(C+, which is a squinched version. + if ($$self{MAGIC_CPP}) { + s{ \b C\+\+ } {\\*\(C+}gx; + } + + # Done. + DEBUG > 5 and print " Guesswork returning [$_]\n"; + return $_; +} + +############################################################################## +# Output +############################################################################## + +# When building up the *roff code, we don't use real *roff fonts. Instead, we +# embed font codes of the form \f(<font>[SE] where <font> is one of B, I, or +# F, S stands for start, and E stands for end. This method turns these into +# the right start and end codes. +# +# We add this level of complexity because the old pod2man didn't get code like +# B<someI<thing> else> right; after I<> it switched back to normal text rather +# than bold. We take care of this by using variables that state whether bold, +# italic, or fixed are turned on as a combined pointer to our current font +# sequence, and set each to the number of current nestings of start tags for +# that font. +# +# \fP changes to the previous font, but only one previous font is kept. We +# don't know what the outside level font is; normally it's R, but if we're +# inside a heading it could be something else. So arrange things so that the +# outside font is always the "previous" font and end with \fP instead of \fR. +# Idea from Zack Weinberg. +sub mapfonts { + my ($self, $text) = @_; + my ($fixed, $bold, $italic) = (0, 0, 0); + my %magic = (F => \$fixed, B => \$bold, I => \$italic); + my $last = '\fR'; + $text =~ s< + \\f\((.)(.) + > < + my $sequence = ''; + my $f; + if ($last ne '\fR') { $sequence = '\fP' } + ${ $magic{$1} } += ($2 eq 'S') ? 1 : -1; + $f = $$self{FONTS}{ ($fixed && 1) . ($bold && 1) . ($italic && 1) }; + if ($f eq $last) { + ''; + } else { + if ($f ne '\fR') { $sequence .= $f } + $last = $f; + $sequence; + } + >gxe; + return $text; +} + +# Unfortunately, there is a bug in Solaris 2.6 nroff (not present in GNU +# groff) where the sequence \fB\fP\f(CW\fP leaves the font set to B rather +# than R, presumably because \f(CW doesn't actually do a font change. To work +# around this, use a separate textmapfonts for text blocks where the default +# font is always R and only use the smart mapfonts for headings. +sub textmapfonts { + my ($self, $text) = @_; + my ($fixed, $bold, $italic) = (0, 0, 0); + my %magic = (F => \$fixed, B => \$bold, I => \$italic); + $text =~ s< + \\f\((.)(.) + > < + ${ $magic{$1} } += ($2 eq 'S') ? 1 : -1; + $$self{FONTS}{ ($fixed && 1) . ($bold && 1) . ($italic && 1) }; + >gxe; + return $text; +} + +# Given a command and a single argument that may or may not contain double +# quotes, handle double-quote formatting for it. If there are no double +# quotes, just return the command followed by the argument in double quotes. +# If there are double quotes, use an if statement to test for nroff, and for +# nroff output the command followed by the argument in double quotes with +# embedded double quotes doubled. For other formatters, remap paired double +# quotes to LQUOTE and RQUOTE. +sub switchquotes { + my ($self, $command, $text, $extra) = @_; + $text =~ s/\\\*\([LR]\"/\"/g; + + # We also have to deal with \*C` and \*C', which are used to add the + # quotes around C<> text, since they may expand to " and if they do this + # confuses the .SH macros and the like no end. Expand them ourselves. + # Also separate troff from nroff if there are any fixed-width fonts in use + # to work around problems with Solaris nroff. + my $c_is_quote = ($$self{LQUOTE} =~ /\"/) || ($$self{RQUOTE} =~ /\"/); + my $fixedpat = join '|', @{ $$self{FONTS} }{'100', '101', '110', '111'}; + $fixedpat =~ s/\\/\\\\/g; + $fixedpat =~ s/\(/\\\(/g; + if ($text =~ m/\"/ || $text =~ m/$fixedpat/) { + $text =~ s/\"/\"\"/g; + my $nroff = $text; + my $troff = $text; + $troff =~ s/\"\"([^\"]*)\"\"/\`\`$1\'\'/g; + if ($c_is_quote and $text =~ m/\\\*\(C[\'\`]/) { + $nroff =~ s/\\\*\(C\`/$$self{LQUOTE}/g; + $nroff =~ s/\\\*\(C\'/$$self{RQUOTE}/g; + $troff =~ s/\\\*\(C[\'\`]//g; + } + $nroff = qq("$nroff") . ($extra ? " $extra" : ''); + $troff = qq("$troff") . ($extra ? " $extra" : ''); + + # Work around the Solaris nroff bug where \f(CW\fP leaves the font set + # to Roman rather than the actual previous font when used in headings. + # troff output may still be broken, but at least we can fix nroff by + # just switching the font changes to the non-fixed versions. + $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. Bother with .ie only if the nroff + # and troff output aren't the same. + if ($nroff ne $troff) { + return ".ie n $command $nroff\n.el $command $troff\n"; + } else { + return "$command $nroff\n"; + } + } else { + $text = qq("$text") . ($extra ? " $extra" : ''); + return "$command $text\n"; + } +} + +# Protect leading quotes and periods against interpretation as commands. Also +# protect anything starting with a backslash, since it could expand or hide +# something that *roff would interpret as a command. This is overkill, but +# it's much simpler than trying to parse *roff here. +sub protect { + my ($self, $text) = @_; + $text =~ s/^([.\'\\])/\\&$1/mg; + return $text; +} + +# Make vertical whitespace if NEEDSPACE is set, appropriate to the indentation +# level the situation. This function is needed since in *roff one has to +# create vertical whitespace after paragraphs and between some things, but +# other macros create their own whitespace. Also close out a sequence of +# repeated =items, since calling makespace means we're about to begin the item +# body. +sub makespace { + my ($self) = @_; + $self->output (".PD\n") if $$self{ITEMS} > 1; + $$self{ITEMS} = 0; + $self->output ($$self{INDENT} > 0 ? ".Sp\n" : ".PP\n") + if $$self{NEEDSPACE}; +} + +# Output any pending index entries, and optionally an index entry given as an +# argument. Support multiple index entries in X<> separated by slashes, and +# strip special escapes from index entries. +sub outindex { + my ($self, $section, $index) = @_; + my @entries = map { split m%\s*/\s*% } @{ $$self{INDEX} }; + return unless ($section || @entries); + + # We're about to output all pending entries, so clear our pending queue. + $$self{INDEX} = []; + + # Build the output. Regular index entries are marked Xref, and headings + # pass in their own section. Undo some *roff formatting on headings. + my @output; + if (@entries) { + push @output, [ 'Xref', join (' ', @entries) ]; + } + if ($section) { + $index =~ s/\\-/-/g; + $index =~ s/\\(?:s-?\d|.\(..|.)//g; + push @output, [ $section, $index ]; + } + + # Print out the .IX commands. + for (@output) { + my ($type, $entry) = @$_; + $entry =~ s/\"/\"\"/g; + $self->output (".IX $type " . '"' . $entry . '"' . "\n"); + } +} + +# Output some text, without any additional changes. +sub output { + my ($self, @text) = @_; + print { $$self{output_fh} } @text; +} + +############################################################################## +# Document initialization +############################################################################## + +# Handle the start of the document. Here we handle empty documents, as well +# as setting up our basic macros in a preamble and building the page title. +sub start_document { + my ($self, $attrs) = @_; + if ($$attrs{contentless} && !$$self{ALWAYS_EMIT_SOMETHING}) { + DEBUG and print "Document is contentless\n"; + $$self{CONTENTLESS} = 1; + return; + } + + # If we were given the utf8 option, set an output encoding on our file + # handle. Wrap in an eval in case we're using a version of Perl too old + # to understand this. + # + # This is evil because it changes the global state of a file handle that + # we may not own. However, we can't just blindly encode all output, since + # there may be a pre-applied output encoding (such as from PERL_UNICODE) + # and then we would double-encode. This seems to be the least bad + # approach. + if ($$self{utf8}) { + eval { binmode ($$self{output_fh}, ':encoding(UTF-8)') }; + } + + # Determine information for the preamble and then output it. + my ($name, $section); + if (defined $$self{name}) { + $name = $$self{name}; + $section = $$self{section} || 1; + } else { + ($name, $section) = $self->devise_title; + } + my $date = $$self{date} || $self->devise_date; + $self->preamble ($name, $section, $date) + unless $self->bare_output or DEBUG > 9; + + # Initialize a few per-document variables. + $$self{INDENT} = 0; # Current indentation level. + $$self{INDENTS} = []; # Stack of indentations. + $$self{INDEX} = []; # Index keys waiting to be printed. + $$self{IN_NAME} = 0; # Whether processing the NAME section. + $$self{ITEMS} = 0; # The number of consecutive =items. + $$self{ITEMTYPES} = []; # Stack of =item types, one per list. + $$self{SHIFTWAIT} = 0; # Whether there is a shift waiting. + $$self{SHIFTS} = []; # Stack of .RS shifts. + $$self{PENDING} = [[]]; # Pending output. +} + +# Handle the end of the document. This does nothing but print out a final +# comment at the end of the document under debugging. +sub end_document { + my ($self) = @_; + return if $self->bare_output; + return if ($$self{CONTENTLESS} && !$$self{ALWAYS_EMIT_SOMETHING}); + $self->output (q(.\" [End document]) . "\n") if DEBUG; +} + +# Try to figure out the name and section from the file name and return them as +# a list, returning an empty name and section 1 if we can't find any better +# information. Uses File::Basename and File::Spec as necessary. +sub devise_title { + my ($self) = @_; + my $name = $self->source_filename || ''; + my $section = $$self{section} || 1; + $section = 3 if (!$$self{section} && $name =~ /\.pm\z/i); + $name =~ s/\.p(od|[lm])\z//i; + + # If the section isn't 3, then the name defaults to just the basename of + # the file. Otherwise, assume we're dealing with a module. We want to + # figure out the full module name from the path to the file, but we don't + # want to include too much of the path into the module name. Lose + # anything up to the first off: + # + # */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, site_perl, or vendor_perl + # component, any OS-specific component, and any version number component, + # and strip off an initial component of "lib" or "blib/lib" since that's + # what ExtUtils::MakeMaker creates. splitdir requires at least File::Spec + # 0.8. + if ($section !~ /^3/) { + require File::Basename; + $name = uc File::Basename::basename ($name); + } else { + 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 < @dirs; $i++) { + if ($dirs[$i] =~ /perl/) { + $cut = $i + 1; + $cut++ if ($dirs[$i + 1] && $dirs[$i + 1] eq 'lib'); + last; + } + } + if ($cut > 0) { + splice (@dirs, 0, $cut); + shift @dirs if ($dirs[0] =~ /^(site|vendor)(_perl)?$/); + shift @dirs if ($dirs[0] =~ /^[\d.]+$/); + shift @dirs if ($dirs[0] =~ /^(.*-$^O|$^O-.*|$^O)$/); + } + shift @dirs if $dirs[0] eq 'lib'; + splice (@dirs, 0, 2) if ($dirs[0] eq 'blib' && $dirs[1] eq 'lib'); + + # Remove empty directories when building the module name; they + # occur too easily on Unix by doubling slashes. + $name = join ('::', (grep { $_ ? $_ : () } @dirs), $file); + } + return ($name, $section); +} + +# Determine the modification date and return that, properly formatted in ISO +# format. If we can't get the modification date of the input, instead use the +# current time. Pod::Simple returns a completely unuseful stringified file +# handle as the source_filename for input from a file handle, so we have to +# deal with that as well. +sub devise_date { + my ($self) = @_; + my $input = $self->source_filename; + my $time; + if ($input) { + $time = (stat $input)[9] || time; + } else { + $time = time; + } + return strftime ('%Y-%m-%d', localtime $time); +} + +# Print out the preamble and the title. The meaning of the arguments to .TH +# unfortunately vary by system; some systems consider the fourth argument to +# be a "source" and others use it as a version number. Generally it's just +# presented as the left-side footer, though, so it doesn't matter too much if +# a particular system gives it another interpretation. +# +# The order of date and release used to be reversed in older versions of this +# module, but this order is correct for both Solaris and Linux. +sub preamble { + my ($self, $name, $section, $date) = @_; + my $preamble = $self->preamble_template (!$$self{utf8}); + + # Build the index line and make sure that it will be syntactically valid. + my $index = "$name $section"; + $index =~ s/\"/\"\"/g; + + # If name or section contain spaces, quote them (section really never + # should, but we may as well be cautious). + for ($name, $section) { + if (/\s/) { + s/\"/\"\"/g; + $_ = '"' . $_ . '"'; + } + } + + # Double quotes in date, since it will be quoted. + $date =~ s/\"/\"\"/g; + + # Substitute into the preamble the configuration options. + $preamble =~ s/\@CFONT\@/$$self{fixed}/; + $preamble =~ s/\@LQUOTE\@/$$self{LQUOTE}/; + $preamble =~ s/\@RQUOTE\@/$$self{RQUOTE}/; + chomp $preamble; + + # Get the version information. + my $version = $self->version_report; + + # Finally output everything. + $self->output (<<"----END OF HEADER----"); +.\\" Automatically generated by $version +.\\" +.\\" Standard preamble: +.\\" ======================================================================== +$preamble +.\\" ======================================================================== +.\\" +.IX Title "$index" +.TH $name $section "$date" "$$self{release}" "$$self{center}" +.\\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\\" way too many mistakes in technical documents. +.if n .ad l +.nh +----END OF HEADER---- + $self->output (".\\\" [End of preamble]\n") if DEBUG; +} + +############################################################################## +# Text blocks +############################################################################## + +# Handle a basic block of text. The only tricky part of this is if this is +# the first paragraph of text after an =over, in which case we have to change +# indentations for *roff. +sub cmd_para { + my ($self, $attrs, $text) = @_; + my $line = $$attrs{start_line}; + + # Output the paragraph. We also have to handle =over without =item. If + # there's an =over without =item, SHIFTWAIT will be set, and we need to + # handle creation of the indent here. Add the shift to SHIFTS so that it + # will be cleaned up on =back. + $self->makespace; + if ($$self{SHIFTWAIT}) { + $self->output (".RS $$self{INDENT}\n"); + push (@{ $$self{SHIFTS} }, $$self{INDENT}); + $$self{SHIFTWAIT} = 0; + } + + # Add the line number for debugging, but not in the NAME section just in + # case the comment would confuse apropos. + $self->output (".\\\" [At source line $line]\n") + if defined ($line) && DEBUG && !$$self{IN_NAME}; + + # Force exactly one newline at the end and strip unwanted trailing + # whitespace at the end. + $text =~ s/\s*$/\n/; + + # Output the paragraph. + $self->output ($self->protect ($self->textmapfonts ($text))); + $self->outindex; + $$self{NEEDSPACE} = 1; + return ''; +} + +# Handle a verbatim paragraph. Put a null token at the beginning of each line +# to protect against commands and wrap in .Vb/.Ve (which we define in our +# prelude). +sub cmd_verbatim { + my ($self, $attrs, $text) = @_; + + # Ignore an empty verbatim paragraph. + return unless $text =~ /\S/; + + # Force exactly one newline at the end and strip unwanted trailing + # whitespace at the end. + $text =~ s/\s*$/\n/; + + # Get a count of the number of lines before the first blank line, which + # we'll pass to .Vb as its parameter. This tells *roff to keep that many + # lines together. We don't want to tell *roff to keep huge blocks + # together. + my @lines = split (/\n/, $text); + my $unbroken = 0; + for (@lines) { + last if /^\s*$/; + $unbroken++; + } + $unbroken = 10 if ($unbroken > 12 && !$$self{MAGIC_VNOPAGEBREAK_LIMIT}); + + # Prepend a null token to each line. + $text =~ s/^/\\&/gm; + + # Output the results. + $self->makespace; + $self->output (".Vb $unbroken\n$text.Ve\n"); + $$self{NEEDSPACE} = 1; + return ''; +} + +# Handle literal text (produced by =for and similar constructs). Just output +# it with the minimum of changes. +sub cmd_data { + my ($self, $attrs, $text) = @_; + $text =~ s/^\n+//; + $text =~ s/\n{0,2}$/\n/; + $self->output ($text); + return ''; +} + +############################################################################## +# Headings +############################################################################## + +# Common code for all headings. This is called before the actual heading is +# output. It returns the cleaned up heading text (putting the heading all on +# one line) and may do other things, like closing bad =item blocks. +sub heading_common { + my ($self, $text, $line) = @_; + $text =~ s/\s+$//; + $text =~ s/\s*\n\s*/ /g; + + # This should never happen; it means that we have a heading after =item + # without an intervening =back. But just in case, handle it anyway. + if ($$self{ITEMS} > 1) { + $$self{ITEMS} = 0; + $self->output (".PD\n"); + } + + # Output the current source line. + $self->output ( ".\\\" [At source line $line]\n" ) + if defined ($line) && DEBUG; + return $text; +} + +# First level heading. We can't output .IX in the NAME section due to a bug +# in some versions of catman, so don't output a .IX for that section. .SH +# already uses small caps, so remove \s0 and \s-1. Maintain IN_NAME as +# appropriate. +sub cmd_head1 { + my ($self, $attrs, $text) = @_; + $text =~ s/\\s-?\d//g; + $text = $self->heading_common ($text, $$attrs{start_line}); + my $isname = ($text eq 'NAME' || $text =~ /\(NAME\)/); + $self->output ($self->switchquotes ('.SH', $self->mapfonts ($text))); + $self->outindex ('Header', $text) unless $isname; + $$self{NEEDSPACE} = 0; + $$self{IN_NAME} = $isname; + return ''; +} + +# Second level heading. +sub cmd_head2 { + my ($self, $attrs, $text) = @_; + $text = $self->heading_common ($text, $$attrs{start_line}); + $self->output ($self->switchquotes ('.SS', $self->mapfonts ($text))); + $self->outindex ('Subsection', $text); + $$self{NEEDSPACE} = 0; + return ''; +} + +# Third level heading. *roff doesn't have this concept, so just put the +# heading in italics as a normal paragraph. +sub cmd_head3 { + my ($self, $attrs, $text) = @_; + $text = $self->heading_common ($text, $$attrs{start_line}); + $self->makespace; + $self->output ($self->textmapfonts ('\f(IS' . $text . '\f(IE') . "\n"); + $self->outindex ('Subsection', $text); + $$self{NEEDSPACE} = 1; + return ''; +} + +# Fourth level heading. *roff doesn't have this concept, so just put the +# heading as a normal paragraph. +sub cmd_head4 { + my ($self, $attrs, $text) = @_; + $text = $self->heading_common ($text, $$attrs{start_line}); + $self->makespace; + $self->output ($self->textmapfonts ($text) . "\n"); + $self->outindex ('Subsection', $text); + $$self{NEEDSPACE} = 1; + return ''; +} + +############################################################################## +# Formatting codes +############################################################################## + +# All of the formatting codes that aren't handled internally by the parser, +# other than L<> and X<>. +sub cmd_b { return '\f(BS' . $_[2] . '\f(BE' } +sub cmd_i { return '\f(IS' . $_[2] . '\f(IE' } +sub cmd_f { return '\f(IS' . $_[2] . '\f(IE' } +sub cmd_c { return $_[0]->quote_literal ($_[2]) } + +# Index entries are just added to the pending entries. +sub cmd_x { + my ($self, $attrs, $text) = @_; + push (@{ $$self{INDEX} }, $text); + return ''; +} + +# Links reduce to the text that we're given, wrapped in angle brackets if it's +# a URL. +sub cmd_l { + my ($self, $attrs, $text) = @_; + return $$attrs{type} eq 'url' ? "<$text>" : $text; +} + +############################################################################## +# List handling +############################################################################## + +# Handle the beginning of an =over block. Takes the type of the block as the +# first argument, and then the attr hash. This is called by the handlers for +# the four different types of lists (bullet, number, text, and block). +sub over_common_start { + my ($self, $type, $attrs) = @_; + my $line = $$attrs{start_line}; + my $indent = $$attrs{indent}; + DEBUG > 3 and print " Starting =over $type (line $line, indent ", + ($indent || '?'), "\n"; + + # Find the indentation level. + unless (defined ($indent) && $indent =~ /^[-+]?\d{1,4}\s*$/) { + $indent = $$self{indent}; + } + + # If we've gotten multiple indentations in a row, we need to emit the + # pending indentation for the last level that we saw and haven't acted on + # yet. SHIFTS is the stack of indentations that we've actually emitted + # code for. + if (@{ $$self{SHIFTS} } < @{ $$self{INDENTS} }) { + $self->output (".RS $$self{INDENT}\n"); + push (@{ $$self{SHIFTS} }, $$self{INDENT}); + } + + # Now, do record-keeping. INDENTS is a stack of indentations that we've + # seen so far, and INDENT is the current level of indentation. ITEMTYPES + # is a stack of list types that we've seen. + push (@{ $$self{INDENTS} }, $$self{INDENT}); + push (@{ $$self{ITEMTYPES} }, $type); + $$self{INDENT} = $indent + 0; + $$self{SHIFTWAIT} = 1; +} + +# End an =over block. Takes no options other than the class pointer. +# Normally, once we close a block and therefore remove something from INDENTS, +# INDENTS will now be longer than SHIFTS, indicating that we also need to emit +# *roff code to close the indent. This isn't *always* true, depending on the +# circumstance. If we're still inside an indentation, we need to emit another +# .RE and then a new .RS to unconfuse *roff. +sub over_common_end { + my ($self) = @_; + DEBUG > 3 and print " Ending =over\n"; + $$self{INDENT} = pop @{ $$self{INDENTS} }; + pop @{ $$self{ITEMTYPES} }; + + # If we emitted code for that indentation, end it. + if (@{ $$self{SHIFTS} } > @{ $$self{INDENTS} }) { + $self->output (".RE\n"); + pop @{ $$self{SHIFTS} }; + } + + # If we're still in an indentation, *roff will have now lost track of the + # right depth of that indentation, so fix that. + if (@{ $$self{INDENTS} } > 0) { + $self->output (".RE\n"); + $self->output (".RS $$self{INDENT}\n"); + } + $$self{NEEDSPACE} = 1; + $$self{SHIFTWAIT} = 0; +} + +# Dispatch the start and end calls as appropriate. +sub start_over_bullet { my $s = shift; $s->over_common_start ('bullet', @_) } +sub start_over_number { my $s = shift; $s->over_common_start ('number', @_) } +sub start_over_text { my $s = shift; $s->over_common_start ('text', @_) } +sub start_over_block { my $s = shift; $s->over_common_start ('block', @_) } +sub end_over_bullet { $_[0]->over_common_end } +sub end_over_number { $_[0]->over_common_end } +sub end_over_text { $_[0]->over_common_end } +sub end_over_block { $_[0]->over_common_end } + +# The common handler for all item commands. Takes the type of the item, the +# attributes, and then the text of the item. +# +# Emit an index entry for anything that's interesting, but don't emit index +# entries for things like bullets and numbers. Newlines in an item title are +# turned into spaces since *roff can't handle them embedded. +sub item_common { + my ($self, $type, $attrs, $text) = @_; + my $line = $$attrs{start_line}; + DEBUG > 3 and print " $type item (line $line): $text\n"; + + # Clean up the text. We want to end up with two variables, one ($text) + # which contains any body text after taking out the item portion, and + # another ($item) which contains the actual item text. + $text =~ s/\s+$//; + my ($item, $index); + if ($type eq 'bullet') { + $item = "\\\(bu"; + $text =~ s/\n*$/\n/; + } elsif ($type eq 'number') { + $item = $$attrs{number} . '.'; + } else { + $item = $text; + $item =~ s/\s*\n\s*/ /g; + $text = ''; + $index = $item if ($item =~ /\w/); + } + + # Take care of the indentation. If shifts and indents are equal, close + # the top shift, since we're about to create an indentation with .IP. + # Also output .PD 0 to turn off spacing between items if this item is + # directly following another one. We only have to do that once for a + # whole chain of items so do it for the second item in the change. Note + # that makespace is what undoes this. + if (@{ $$self{SHIFTS} } == @{ $$self{INDENTS} }) { + $self->output (".RE\n"); + pop @{ $$self{SHIFTS} }; + } + $self->output (".PD 0\n") if ($$self{ITEMS} == 1); + + # Now, output the item tag itself. + $item = $self->textmapfonts ($item); + $self->output ($self->switchquotes ('.IP', $item, $$self{INDENT})); + $$self{NEEDSPACE} = 0; + $$self{ITEMS}++; + $$self{SHIFTWAIT} = 0; + + # If body text for this item was included, go ahead and output that now. + if ($text) { + $text =~ s/\s*$/\n/; + $self->makespace; + $self->output ($self->protect ($self->textmapfonts ($text))); + $$self{NEEDSPACE} = 1; + } + $self->outindex ($index ? ('Item', $index) : ()); +} + +# Dispatch the item commands to the appropriate place. +sub cmd_item_bullet { my $self = shift; $self->item_common ('bullet', @_) } +sub cmd_item_number { my $self = shift; $self->item_common ('number', @_) } +sub cmd_item_text { my $self = shift; $self->item_common ('text', @_) } +sub cmd_item_block { my $self = shift; $self->item_common ('block', @_) } + +############################################################################## +# Backward compatibility +############################################################################## + +# Reset the underlying Pod::Simple object between calls to parse_from_file so +# that the same object can be reused to convert multiple pages. +sub parse_from_file { + my $self = shift; + $self->reinit; + + # Fake the old cutting option to Pod::Parser. This fiddings with internal + # Pod::Simple state and is quite ugly; we need a better approach. + if (ref ($_[0]) eq 'HASH') { + my $opts = shift @_; + if (defined ($$opts{-cutting}) && !$$opts{-cutting}) { + $$self{in_pod} = 1; + $$self{last_was_blank} = 1; + } + } + + # Do the work. + my $retval = $self->SUPER::parse_from_file (@_); + + # Flush output, since Pod::Simple doesn't do this. Ideally we should also + # close the file descriptor if we had to open one, but we can't easily + # figure this out. + my $fh = $self->output_fh (); + my $oldfh = select $fh; + my $oldflush = $|; + $| = 1; + print $fh ''; + $| = $oldflush; + select $oldfh; + return $retval; +} + +# Pod::Simple failed to provide this backward compatibility function, so +# implement it ourselves. File handles are one of the inputs that +# parse_from_file supports. +sub parse_from_filehandle { + my $self = shift; + $self->parse_from_file (@_); +} + +############################################################################## +# Translation tables +############################################################################## + +# The following table is adapted from Tom Christiansen's pod2man. It assumes +# that the standard preamble has already been printed, since that's what +# defines all of the accent marks. We really want to do something better than +# this when *roff actually supports other character sets itself, since these +# results are pretty poor. +# +# This only works in an ASCII world. What to do in a non-ASCII world is very +# unclear -- hopefully we can assume UTF-8 and just leave well enough alone. +@ESCAPES{0xA0 .. 0xFF} = ( + "\\ ", undef, undef, undef, undef, undef, undef, undef, + undef, undef, undef, undef, undef, "\\%", undef, undef, + + undef, undef, undef, undef, undef, undef, undef, undef, + undef, undef, undef, undef, undef, undef, undef, undef, + + "A\\*`", "A\\*'", "A\\*^", "A\\*~", "A\\*:", "A\\*o", "\\*(AE", "C\\*,", + "E\\*`", "E\\*'", "E\\*^", "E\\*:", "I\\*`", "I\\*'", "I\\*^", "I\\*:", + + "\\*(D-", "N\\*~", "O\\*`", "O\\*'", "O\\*^", "O\\*~", "O\\*:", undef, + "O\\*/", "U\\*`", "U\\*'", "U\\*^", "U\\*:", "Y\\*'", "\\*(Th", "\\*8", + + "a\\*`", "a\\*'", "a\\*^", "a\\*~", "a\\*:", "a\\*o", "\\*(ae", "c\\*,", + "e\\*`", "e\\*'", "e\\*^", "e\\*:", "i\\*`", "i\\*'", "i\\*^", "i\\*:", + + "\\*(d-", "n\\*~", "o\\*`", "o\\*'", "o\\*^", "o\\*~", "o\\*:", undef, + "o\\*/" , "u\\*`", "u\\*'", "u\\*^", "u\\*:", "y\\*'", "\\*(th", "y\\*:", +) if ASCII; + +############################################################################## +# Premable +############################################################################## + +# The following is the static preamble which starts all *roff output we +# generate. Most is static except for the font to use as a fixed-width font, +# which is designed by @CFONT@, and the left and right quotes to use for C<> +# text, designated by @LQOUTE@ and @RQUOTE@. However, the second part, which +# defines the accent marks, is only used if $escapes is set to true. +sub preamble_template { + my ($self, $accents) = @_; + my $preamble = <<'----END OF PREAMBLE----'; +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft @CFONT@ +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` @LQUOTE@ +. ds C' @RQUOTE@ +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +----END OF PREAMBLE---- + + if ($accents) { + $preamble .= <<'----END OF PREAMBLE----' +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +----END OF PREAMBLE---- +#`# for cperl-mode + } + return $preamble; +} + +############################################################################## +# Module return value and documentation +############################################################################## + +1; +__END__ + +=head1 NAME + +Pod::Man - Convert POD data to formatted *roff input + +=for stopwords +en em ALLCAPS teeny fixedbold fixeditalic fixedbolditalic stderr utf8 +UTF-8 Allbery Sean Burke Ossanna Solaris formatters troff uppercased +Christiansen + +=head1 SYNOPSIS + + use Pod::Man; + my $parser = Pod::Man->new (release => $VERSION, section => 8); + + # Read POD from STDIN and write to STDOUT. + $parser->parse_file (\*STDIN); + + # Read POD from file.pod and write to file.1. + $parser->parse_from_file ('file.pod', 'file.1'); + +=head1 DESCRIPTION + +Pod::Man is a module to convert documentation in the POD format (the +preferred language for documenting Perl) into *roff input using the man +macro set. The resulting *roff code is suitable for display on a terminal +using L<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::Simple, Pod::Man supports the same methods and +interfaces. See L<Pod::Simple> for all the details. + +new() can take options, in the form of key/value pairs that control the +behavior of the parser. See below for details. + +If no options are given, Pod::Man uses the name of the input file with any +trailing C<.pod>, C<.pm>, or C<.pl> stripped as the man page title, to +section 1 unless the file ended in C<.pm> in which case it defaults to +section 3, to a centered title of "User Contributed Perl Documentation", to +a centered footer of the Perl version it is run with, and to a left-hand +footer of the modification date of its input (or the current date if given +C<STDIN> for input). + +Pod::Man assumes that your *roff formatters have a fixed-width font named +C<CW>. If yours is called something else (like C<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 underscores, 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 C<STDIN>), and the date will be formatted as +C<YYYY-MM-DD>. + +=item fixed + +The fixed-width font to use for verbatim text and code. Defaults to +C<CW>. Some systems may want C<CR> instead. Only matters for B<troff> +output. + +=item fixedbold + +Bold version of the fixed-width font. Defaults to C<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 C<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 C<CB>. Some +systems (such as Solaris) have this font available as C<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 C<.pm> in which +case section 3 will be selected. + +=item stderr + +Send error messages about invalid POD to standard error instead of +appending a POD ERRORS section to the generated *roff output. + +=item utf8 + +By default, Pod::Man produces the most conservative possible *roff output +to try to ensure that it will work with as many different *roff +implementations as possible. Many *roff implementations cannot handle +non-ASCII characters, so this means all non-ASCII characters are converted +either to a *roff escape sequence that tries to create a properly accented +character (at least for troff output) or to C<X>. + +If this option is set, Pod::Man will instead output UTF-8. If your *roff +implementation can handle it, this is the best output format to use and +avoids corruption of documents containing non-ASCII characters. However, +be warned that *roff source with literal UTF-8 characters is not supported +by many implementations and may even result in segfaults and other bad +behavior. + +Be aware that, when using this option, the input encoding of your POD +source must be properly declared unless it is US-ASCII or Latin-1. POD +input without an C<=encoding> command will be assumed to be in Latin-1, +and if it's actually in UTF-8, the output will be double-encoded. See +L<perlpod(1)> for more information on the C<=encoding> command. + +=back + +The standard Pod::Simple method parse_file() takes one argument naming the +POD file to read from. By default, the output is sent to C<STDOUT>, but +this can be changed with the output_fd() method. + +The standard Pod::Simple method parse_from_file() takes up to two +arguments, the first being the input file to read POD from and the second +being the file to write the formatted output to. + +You can also call parse_lines() to parse an array of lines or +parse_string_document() to parse a document already in memory. To put the +output into a string instead of a file handle, call the output_string() +method. See L<Pod::Simple> 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 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. + +=back + +=head1 BUGS + +Encoding handling assumes that PerlIO is available and does not work +properly if it isn't. The C<utf8> option is therefore not supported +unless Perl is built with PerlIO support. + +There is currently no way to turn off the guesswork that tries to format +unmarked text appropriately, and sometimes it isn't wanted (particularly +when using POD to document something other than Perl). Most of the work +toward fixing this has now been done, however, and all that's still needed +is a user interface. + +The NAME section should be recognized specially and index entries emitted +for everything in that section. This would have to be deferred until the +next section, since extraneous things in NAME tends to confuse various man +page processors. Currently, no index entries are emitted for anything in +NAME. + +Pod::Man doesn't handle font names longer than two characters. Neither do +most B<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 non-ASCII characters. It would +ideally be nice if all of those definitions were only output if needed, +perhaps on the fly as the characters are used. + +Pod::Man is excessively slow. + +=head1 CAVEATS + +If Pod::Man is given the C<utf8> option, the encoding of its output file +handle will be forced to UTF-8 if possible, overriding any existing +encoding. This will be done even if the file handle is not created by +Pod::Man and was passed in from outside. This maintains consistency +regardless of PERL_UNICODE and other settings. + +The handling of hyphens and em dashes is somewhat fragile, and one may get +the wrong one under some circumstances. This should only matter for +B<troff> output. + +When and whether to use small caps is somewhat tricky, and Pod::Man doesn't +necessarily get it right. + +Converting neutral double quotes to properly matched double quotes doesn't +work unless there are no formatting codes between the quote marks. This +only matters for troff output. + +=head1 AUTHOR + +Russ Allbery <rra@stanford.edu>, based I<very> heavily on the original +B<pod2man> by Tom Christiansen <tchrist@mox.perl.com>. The modifications to +work with Pod::Simple instead of Pod::Parser were originally contributed by +Sean Burke (but I've since hacked them beyond recognition and all bugs are +mine). + +=head1 COPYRIGHT AND LICENSE + +Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +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. + +=head1 SEE ALSO + +L<Pod::Simple>, 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. + +=cut diff --git a/cpan/podlators/lib/Pod/ParseLink.pm b/cpan/podlators/lib/Pod/ParseLink.pm new file mode 100644 index 0000000000..7cb2d656f6 --- /dev/null +++ b/cpan/podlators/lib/Pod/ParseLink.pm @@ -0,0 +1,182 @@ +# Pod::ParseLink -- Parse an L<> formatting code in POD text. +# +# Copyright 2001, 2008 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); + +$VERSION = '1.09'; + +############################################################################## +# 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 + +=for stopwords +markup Allbery URL + +=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 C<url>, C<pod>, or C<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 backward +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, 2008 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/cpan/podlators/lib/Pod/Text.pm b/cpan/podlators/lib/Pod/Text.pm new file mode 100644 index 0000000000..533c4cf4fe --- /dev/null +++ b/cpan/podlators/lib/Pod/Text.pm @@ -0,0 +1,861 @@ +# Pod::Text -- Convert POD data to formatted ASCII text. +# +# Copyright 1999, 2000, 2001, 2002, 2004, 2006, 2008 +# 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 strict; +use vars qw(@ISA @EXPORT %ESCAPES $VERSION); + +use Carp qw(carp croak); +use Exporter (); +use Pod::Simple (); + +@ISA = qw(Pod::Simple Exporter); + +# We have to export pod2text for backward compatibility. +@EXPORT = qw(pod2text); + +$VERSION = '3.13'; + +############################################################################## +# Initialization +############################################################################## + +# This function handles code blocks. It's registered as a callback to +# Pod::Simple and therefore doesn't work as a regular method call, but all it +# does is call output_code with the line. +sub handle_code { + my ($line, $number, $parser) = @_; + $parser->output_code ($line . "\n"); +} + +# Initialize the object and set various Pod::Simple options that we need. +# Here, we also process any additional options passed to the constructor or +# set up defaults if none were given. Note that all internal object keys are +# in all-caps, reserving all lower-case object keys for Pod::Simple and user +# arguments. +sub new { + my $class = shift; + my $self = $class->SUPER::new; + + # Tell Pod::Simple to handle S<> by automatically inserting . + $self->nbsp_for_S (1); + + # Tell Pod::Simple to keep whitespace whenever possible. + if ($self->can ('preserve_whitespace')) { + $self->preserve_whitespace (1); + } else { + $self->fullstop_space_harden (1); + } + + # The =for and =begin targets that we accept. + $self->accept_targets (qw/text TEXT/); + + # Ensure that contiguous blocks of code are merged together. Otherwise, + # some of the guesswork heuristics don't work right. + $self->merge_text (1); + + # Pod::Simple doesn't do anything useful with our arguments, but we want + # to put them in our object as hash keys and values. This could cause + # problems if we ever clash with Pod::Simple's own internal class + # variables. + my %opts = @_; + my @opts = map { ("opt_$_", $opts{$_}) } keys %opts; + %$self = (%$self, @opts); + + # Send errors to stderr if requested. + if ($$self{opt_stderr}) { + $self->no_errata_section (1); + $self->complain_stderr (1); + delete $$self{opt_stderr}; + } + + # Initialize various things from our parameters. + $$self{opt_alt} = 0 unless defined $$self{opt_alt}; + $$self{opt_indent} = 4 unless defined $$self{opt_indent}; + $$self{opt_margin} = 0 unless defined $$self{opt_margin}; + $$self{opt_loose} = 0 unless defined $$self{opt_loose}; + $$self{opt_sentence} = 0 unless defined $$self{opt_sentence}; + $$self{opt_width} = 76 unless defined $$self{opt_width}; + + # Figure out what quotes we'll be using for C<> text. + $$self{opt_quotes} ||= '"'; + if ($$self{opt_quotes} eq 'none') { + $$self{LQUOTE} = $$self{RQUOTE} = ''; + } elsif (length ($$self{opt_quotes}) == 1) { + $$self{LQUOTE} = $$self{RQUOTE} = $$self{opt_quotes}; + } elsif ($$self{opt_quotes} =~ /^(.)(.)$/ + || $$self{opt_quotes} =~ /^(..)(..)$/) { + $$self{LQUOTE} = $1; + $$self{RQUOTE} = $2; + } else { + croak qq(Invalid quote specification "$$self{opt_quotes}"); + } + + # If requested, do something with the non-POD text. + $self->code_handler (\&handle_code) if $$self{opt_code}; + + # Return the created object. + return $self; +} + +############################################################################## +# Core parsing +############################################################################## + +# This is the glue that connects the code below with Pod::Simple itself. The +# goal is to convert the event stream coming from the POD parser into method +# calls to handlers once the complete content of a tag has been seen. Each +# paragraph or POD command will have textual content associated with it, and +# as soon as all of a paragraph or POD command has been seen, that content +# will be passed in to the corresponding method for handling that type of +# object. The exceptions are handlers for lists, which have opening tag +# handlers and closing tag handlers that will be called right away. +# +# The internal hash key PENDING is used to store the contents of a tag until +# all of it has been seen. It holds a stack of open tags, each one +# represented by a tuple of the attributes hash for the tag and the contents +# of the tag. + +# Add a block of text to the contents of the current node, formatting it +# according to the current formatting instructions as we do. +sub _handle_text { + my ($self, $text) = @_; + my $tag = $$self{PENDING}[-1]; + $$tag[1] .= $text; +} + +# Given an element name, get the corresponding method name. +sub method_for_element { + my ($self, $element) = @_; + $element =~ tr/-/_/; + $element =~ tr/A-Z/a-z/; + $element =~ tr/_a-z0-9//cd; + return $element; +} + +# Handle the start of a new element. If cmd_element is defined, assume that +# we need to collect the entire tree for this element before passing it to the +# element method, and create a new tree into which we'll collect blocks of +# text and nested elements. Otherwise, if start_element is defined, call it. +sub _handle_element_start { + my ($self, $element, $attrs) = @_; + my $method = $self->method_for_element ($element); + + # If we have a command handler, we need to accumulate the contents of the + # tag before calling it. + if ($self->can ("cmd_$method")) { + push (@{ $$self{PENDING} }, [ $attrs, '' ]); + } elsif ($self->can ("start_$method")) { + my $method = 'start_' . $method; + $self->$method ($attrs, ''); + } +} + +# Handle the end of an element. If we had a cmd_ method for this element, +# this is where we pass along the text that we've accumulated. Otherwise, if +# we have an end_ method for the element, call that. +sub _handle_element_end { + my ($self, $element) = @_; + my $method = $self->method_for_element ($element); + + # If we have a command handler, pull off the pending text and pass it to + # the handler along with the saved attribute hash. + if ($self->can ("cmd_$method")) { + my $tag = pop @{ $$self{PENDING} }; + my $method = 'cmd_' . $method; + my $text = $self->$method (@$tag); + if (defined $text) { + if (@{ $$self{PENDING} } > 1) { + $$self{PENDING}[-1][1] .= $text; + } else { + $self->output ($text); + } + } + } elsif ($self->can ("end_$method")) { + my $method = 'end_' . $method; + $self->$method (); + } +} + +############################################################################## +# Output formatting +############################################################################## + +# Wrap a line, indenting by the current left margin. We can't use Text::Wrap +# because it plays games with tabs. We can't use formline, even though we'd +# really like to, because it screws up non-printing characters. So we have to +# do the wrapping ourselves. +sub wrap { + my $self = shift; + local $_ = shift; + my $output = ''; + my $spaces = ' ' x $$self{MARGIN}; + my $width = $$self{opt_width} - $$self{MARGIN}; + while (length > $width) { + if (s/^([^\n]{0,$width})\s+// || s/^([^\n]{$width})//) { + $output .= $spaces . $1 . "\n"; + } else { + last; + } + } + $output .= $spaces . $_; + $output =~ s/\s+$/\n\n/; + return $output; +} + +# Reformat a paragraph of text for the current margin. Takes the text to +# reformat and returns the formatted text. +sub reformat { + my $self = shift; + local $_ = shift; + + # If we're trying to preserve two spaces after sentences, do some munging + # to support that. Otherwise, smash all repeated whitespace. + if ($$self{opt_sentence}) { + s/ +$//mg; + s/\.\n/. \n/g; + s/\n/ /g; + s/ +/ /g; + } else { + s/\s+/ /g; + } + return $self->wrap ($_); +} + +# Output text to the output device. Replace non-breaking spaces with spaces +# and soft hyphens with nothing, and then try to fix the output encoding if +# necessary to match the input encoding unless UTF-8 output is forced. This +# preserves the traditional pass-through behavior of Pod::Text. +sub output { + my ($self, $text) = @_; + $text =~ tr/\240\255/ /d; + unless ($$self{opt_utf8} || $$self{CHECKED_ENCODING}) { + my $encoding = $$self{encoding} || ''; + if ($encoding) { + eval { binmode ($$self{output_fh}, ":encoding($encoding)") }; + } + $$self{CHECKED_ENCODING} = 1; + } + print { $$self{output_fh} } $text; +} + +# Output a block of code (something that isn't part of the POD text). Called +# by preprocess_paragraph only if we were given the code option. Exists here +# only so that it can be overridden by subclasses. +sub output_code { $_[0]->output ($_[1]) } + +############################################################################## +# Document initialization +############################################################################## + +# Set up various things that have to be initialized on a per-document basis. +sub start_document { + my $self = shift; + my $margin = $$self{opt_indent} + $$self{opt_margin}; + + # Initialize a few per-document variables. + $$self{INDENTS} = []; # Stack of indentations. + $$self{MARGIN} = $margin; # Default left margin. + $$self{PENDING} = [[]]; # Pending output. + + # We have to redo encoding handling for each document. + delete $$self{CHECKED_ENCODING}; + + # If we were given the utf8 option, set an output encoding on our file + # handle. Wrap in an eval in case we're using a version of Perl too old + # to understand this. + # + # This is evil because it changes the global state of a file handle that + # we may not own. However, we can't just blindly encode all output, since + # there may be a pre-applied output encoding (such as from PERL_UNICODE) + # and then we would double-encode. This seems to be the least bad + # approach. + if ($$self{opt_utf8}) { + eval { binmode ($$self{output_fh}, ':encoding(UTF-8)') }; + } + + return ''; +} + +############################################################################## +# Text blocks +############################################################################## + +# This method is called whenever an =item command is complete (in other words, +# we've seen its associated paragraph or know for certain that it doesn't have +# one). It gets the paragraph associated with the item as an argument. If +# that argument is empty, just output the item tag; if it contains a newline, +# output the item tag followed by the newline. Otherwise, see if there's +# enough room for us to output the item tag in the margin of the text or if we +# have to put it on a separate line. +sub item { + my ($self, $text) = @_; + my $tag = $$self{ITEM}; + unless (defined $tag) { + carp "Item called without tag"; + return; + } + undef $$self{ITEM}; + + # Calculate the indentation and margin. $fits is set to true if the tag + # will fit into the margin of the paragraph given our indentation level. + my $indent = $$self{INDENTS}[-1]; + $indent = $$self{opt_indent} unless defined $indent; + my $margin = ' ' x $$self{opt_margin}; + my $fits = ($$self{MARGIN} - $indent >= length ($tag) + 1); + + # If the tag doesn't fit, or if we have no associated text, print out the + # tag separately. Otherwise, put the tag in the margin of the paragraph. + if (!$text || $text =~ /^\s+$/ || !$fits) { + my $realindent = $$self{MARGIN}; + $$self{MARGIN} = $indent; + my $output = $self->reformat ($tag); + $output =~ s/^$margin /$margin:/ if ($$self{opt_alt} && $indent > 0); + $output =~ s/\n*$/\n/; + + # If the text is just whitespace, we have an empty item paragraph; + # this can result from =over/=item/=back without any intermixed + # paragraphs. Insert some whitespace to keep the =item from merging + # into the next paragraph. + $output .= "\n" if $text && $text =~ /^\s*$/; + + $self->output ($output); + $$self{MARGIN} = $realindent; + $self->output ($self->reformat ($text)) if ($text && $text =~ /\S/); + } else { + my $space = ' ' x $indent; + $space =~ s/^$margin /$margin:/ if $$self{opt_alt}; + $text = $self->reformat ($text); + $text =~ s/^$margin /$margin:/ if ($$self{opt_alt} && $indent > 0); + my $tagspace = ' ' x length $tag; + $text =~ s/^($space)$tagspace/$1$tag/ or warn "Bizarre space in item"; + $self->output ($text); + } +} + +# Handle a basic block of text. The only tricky thing here is that if there +# is a pending item tag, we need to format this as an item paragraph. +sub cmd_para { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$/\n/; + if (defined $$self{ITEM}) { + $self->item ($text . "\n"); + } else { + $self->output ($self->reformat ($text . "\n")); + } + return ''; +} + +# Handle a verbatim paragraph. Just print it out, but indent it according to +# our margin. +sub cmd_verbatim { + my ($self, $attrs, $text) = @_; + $self->item if defined $$self{ITEM}; + return if $text =~ /^\s*$/; + $text =~ s/^(\n*)([ \t]*\S+)/$1 . (' ' x $$self{MARGIN}) . $2/gme; + $text =~ s/\s*$/\n\n/; + $self->output ($text); + return ''; +} + +# Handle literal text (produced by =for and similar constructs). Just output +# it with the minimum of changes. +sub cmd_data { + my ($self, $attrs, $text) = @_; + $text =~ s/^\n+//; + $text =~ s/\n{0,2}$/\n/; + $self->output ($text); + return ''; +} + +############################################################################## +# Headings +############################################################################## + +# The common code for handling all headers. Takes the header text, the +# indentation, and the surrounding marker for the alt formatting method. +sub heading { + my ($self, $text, $indent, $marker) = @_; + $self->item ("\n\n") if defined $$self{ITEM}; + $text =~ s/\s+$//; + if ($$self{opt_alt}) { + my $closemark = reverse (split (//, $marker)); + my $margin = ' ' x $$self{opt_margin}; + $self->output ("\n" . "$margin$marker $text $closemark" . "\n\n"); + } else { + $text .= "\n" if $$self{opt_loose}; + my $margin = ' ' x ($$self{opt_margin} + $indent); + $self->output ($margin . $text . "\n"); + } + return ''; +} + +# First level heading. +sub cmd_head1 { + my ($self, $attrs, $text) = @_; + $self->heading ($text, 0, '===='); +} + +# Second level heading. +sub cmd_head2 { + my ($self, $attrs, $text) = @_; + $self->heading ($text, $$self{opt_indent} / 2, '== '); +} + +# Third level heading. +sub cmd_head3 { + my ($self, $attrs, $text) = @_; + $self->heading ($text, $$self{opt_indent} * 2 / 3 + 0.5, '= '); +} + +# Fourth level heading. +sub cmd_head4 { + my ($self, $attrs, $text) = @_; + $self->heading ($text, $$self{opt_indent} * 3 / 4 + 0.5, '- '); +} + +############################################################################## +# List handling +############################################################################## + +# Handle the beginning of an =over block. Takes the type of the block as the +# first argument, and then the attr hash. This is called by the handlers for +# the four different types of lists (bullet, number, text, and block). +sub over_common_start { + my ($self, $attrs) = @_; + $self->item ("\n\n") if defined $$self{ITEM}; + + # Find the indentation level. + my $indent = $$attrs{indent}; + unless (defined ($indent) && $indent =~ /^\s*[-+]?\d{1,4}\s*$/) { + $indent = $$self{opt_indent}; + } + + # Add this to our stack of indents and increase our current margin. + push (@{ $$self{INDENTS} }, $$self{MARGIN}); + $$self{MARGIN} += ($indent + 0); + return ''; +} + +# End an =over block. Takes no options other than the class pointer. Output +# any pending items and then pop one level of indentation. +sub over_common_end { + my ($self) = @_; + $self->item ("\n\n") if defined $$self{ITEM}; + $$self{MARGIN} = pop @{ $$self{INDENTS} }; + return ''; +} + +# Dispatch the start and end calls as appropriate. +sub start_over_bullet { $_[0]->over_common_start ($_[1]) } +sub start_over_number { $_[0]->over_common_start ($_[1]) } +sub start_over_text { $_[0]->over_common_start ($_[1]) } +sub start_over_block { $_[0]->over_common_start ($_[1]) } +sub end_over_bullet { $_[0]->over_common_end } +sub end_over_number { $_[0]->over_common_end } +sub end_over_text { $_[0]->over_common_end } +sub end_over_block { $_[0]->over_common_end } + +# The common handler for all item commands. Takes the type of the item, the +# attributes, and then the text of the item. +sub item_common { + my ($self, $type, $attrs, $text) = @_; + $self->item if defined $$self{ITEM}; + + # Clean up the text. We want to end up with two variables, one ($text) + # which contains any body text after taking out the item portion, and + # another ($item) which contains the actual item text. Note the use of + # the internal Pod::Simple attribute here; that's a potential land mine. + $text =~ s/\s+$//; + my ($item, $index); + if ($type eq 'bullet') { + $item = '*'; + } elsif ($type eq 'number') { + $item = $$attrs{'~orig_content'}; + } else { + $item = $text; + $item =~ s/\s*\n\s*/ /g; + $text = ''; + } + $$self{ITEM} = $item; + + # If body text for this item was included, go ahead and output that now. + if ($text) { + $text =~ s/\s*$/\n/; + $self->item ($text); + } + return ''; +} + +# Dispatch the item commands to the appropriate place. +sub cmd_item_bullet { my $self = shift; $self->item_common ('bullet', @_) } +sub cmd_item_number { my $self = shift; $self->item_common ('number', @_) } +sub cmd_item_text { my $self = shift; $self->item_common ('text', @_) } +sub cmd_item_block { my $self = shift; $self->item_common ('block', @_) } + +############################################################################## +# Formatting codes +############################################################################## + +# The simple ones. +sub cmd_b { return $_[0]{alt} ? "``$_[2]''" : $_[2] } +sub cmd_f { return $_[0]{alt} ? "\"$_[2]\"" : $_[2] } +sub cmd_i { return '*' . $_[2] . '*' } +sub cmd_x { return '' } + +# Apply a whole bunch of messy heuristics to not quote things that don't +# benefit from being quoted. These originally come from Barrie Slaymaker and +# largely duplicate code in Pod::Man. +sub cmd_c { + my ($self, $attrs, $text) = @_; + + # A regex that matches the portion of a variable reference that's the + # array or hash index, separated out just because we want to use it in + # several places in the following regex. + my $index = '(?: \[.*\] | \{.*\} )?'; + + # Check for things that we don't want to quote, and if we find any of + # them, return the string with just a font change and no quoting. + $text =~ m{ + ^\s* + (?: + ( [\'\`\"] ) .* \1 # already quoted + | \` .* \' # `quoted' + | \$+ [\#^]? \S $index # special ($^Foo, $") + | [\$\@%&*]+ \#? [:\'\w]+ $index # plain var or func + | [\$\@%&*]* [:\'\w]+ (?: -> )? \(\s*[^\s,]\s*\) # 0/1-arg func call + | [+-]? ( \d[\d.]* | \.\d+ ) (?: [eE][+-]?\d+ )? # a number + | 0x [a-fA-F\d]+ # a hex constant + ) + \s*\z + }xo && return $text; + + # If we didn't return, go ahead and quote the text. + return $$self{opt_alt} + ? "``$text''" + : "$$self{LQUOTE}$text$$self{RQUOTE}"; +} + +# Links reduce to the text that we're given, wrapped in angle brackets if it's +# a URL. +sub cmd_l { + my ($self, $attrs, $text) = @_; + return $$attrs{type} eq 'url' ? "<$text>" : $text; +} + +############################################################################## +# Backwards compatibility +############################################################################## + +# The old Pod::Text module did everything in a pod2text() function. This +# tries to provide the same interface for legacy applications. +sub pod2text { + my @args; + + # This is really ugly; I hate doing option parsing in the middle of a + # module. But the old Pod::Text module supported passing flags to its + # entry function, so handle -a and -<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; + $parser->output_fh ($fhs[1]); + my $retval = $parser->parse_file ($fhs[0]); + my $fh = $parser->output_fh (); + close $fh; + return $retval; + } else { + $parser->output_fh (\*STDOUT); + return $parser->parse_file (@_); + } +} + +# Reset the underlying Pod::Simple object between calls to parse_from_file so +# that the same object can be reused to convert multiple pages. +sub parse_from_file { + my $self = shift; + $self->reinit; + + # Fake the old cutting option to Pod::Parser. This fiddings with internal + # Pod::Simple state and is quite ugly; we need a better approach. + if (ref ($_[0]) eq 'HASH') { + my $opts = shift @_; + if (defined ($$opts{-cutting}) && !$$opts{-cutting}) { + $$self{in_pod} = 1; + $$self{last_was_blank} = 1; + } + } + + # Do the work. + my $retval = $self->Pod::Simple::parse_from_file (@_); + + # Flush output, since Pod::Simple doesn't do this. Ideally we should also + # close the file descriptor if we had to open one, but we can't easily + # figure this out. + my $fh = $self->output_fh (); + my $oldfh = select $fh; + my $oldflush = $|; + $| = 1; + print $fh ''; + $| = $oldflush; + select $oldfh; + return $retval; +} + +# Pod::Simple failed to provide this backward compatibility function, so +# implement it ourselves. File handles are one of the inputs that +# parse_from_file supports. +sub parse_from_filehandle { + my $self = shift; + $self->parse_from_file (@_); +} + +############################################################################## +# Module return value and documentation +############################################################################## + +1; +__END__ + +=head1 NAME + +Pod::Text - Convert POD data to formatted ASCII text + +=for stopwords +alt stderr Allbery Sean Burke's Christiansen UTF-8 pre-Unicode utf8 + +=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::Simple, Pod::Text supports the same methods and +interfaces. See L<Pod::Simple> for all the details; briefly, one creates a +new parser with C<< Pod::Text->new() >> and then normally calls parse_file(). + +new() can take options, in the form of key/value pairs, that control the +behavior of the parser. The currently recognized options are: + +=over 4 + +=item alt + +If set to a true value, selects an alternate output format that, among other +things, uses a different heading style and marks C<=item> entries with a +colon in the left margin. Defaults to false. + +=item code + +If set to a true value, the non-POD parts of the input file will be included +in the output. Useful for viewing code documented with POD blocks with the +POD rendered and the code left intact. + +=item 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 stderr + +Send error messages about invalid POD to standard error instead of +appending a POD ERRORS section to the generated output. + +=item utf8 + +By default, Pod::Text uses the same output encoding as the input encoding +of the POD source (provided that Perl was built with PerlIO; otherwise, it +doesn't encode its output). If this option is given, the output encoding +is forced to UTF-8. + +Be aware that, when using this option, the input encoding of your POD +source must be properly declared unless it is US-ASCII or Latin-1. POD +input without an C<=encoding> command will be assumed to be in Latin-1, +and if it's actually in UTF-8, the output will be double-encoded. See +L<perlpod(1)> for more information on the C<=encoding> command. + +=item width + +The column at which to wrap text on the right-hand side. Defaults to 76. + +=back + +The standard Pod::Simple method parse_file() takes one argument, the file or +file handle to read from, and writes output to standard output unless that +has been changed with the output_fh() method. See L<Pod::Simple> for the +specific details and for other alternative interfaces. + +=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. + +=back + +=head1 BUGS + +Encoding handling assumes that PerlIO is available and does not work +properly if it isn't. The C<utf8> option is therefore not supported +unless Perl is built with PerlIO support. + +=head1 CAVEATS + +If Pod::Text is given the C<utf8> option, the encoding of its output file +handle will be forced to UTF-8 if possible, overriding any existing +encoding. This will be done even if the file handle is not created by +Pod::Text and was passed in from outside. This maintains consistency +regardless of PERL_UNICODE and other settings. + +If the C<utf8> option is not given, the encoding of its output file handle +will be forced to the detected encoding of the input POD, which preserves +whatever the input text is. This ensures backward compatibility with +earlier, pre-Unicode versions of this module, without large numbers of +Perl warnings. + +This is not ideal, but it seems to be the best compromise. If it doesn't +work for you, please let me know the details of how it broke. + +=head1 NOTES + +This is a replacement for an earlier Pod::Text module written by Tom +Christiansen. It has a revamped interface, since it now uses Pod::Simple, +but an interface roughly compatible with the old Pod::Text::pod2text() +function is still available. Please change to the new calling convention, +though. + +The original Pod::Text contained code to do formatting via termcap +sequences, although it wasn't turned on by default and it was problematic to +get it to work at all. This rewrite doesn't even try to do that, but a +subclass of it does. Look for L<Pod::Text::Termcap>. + +=head1 SEE ALSO + +L<Pod::Simple>, L<Pod::Text::Termcap>, L<perlpod(1)>, 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>. Sean Burke's initial +conversion of Pod::Man to use Pod::Simple provided much-needed guidance on +how to use Pod::Simple. + +=head1 COPYRIGHT AND LICENSE + +Copyright 1999, 2000, 2001, 2002, 2004, 2006, 2008 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/cpan/podlators/lib/Pod/Text/Color.pm b/cpan/podlators/lib/Pod/Text/Color.pm new file mode 100644 index 0000000000..517f5d0458 --- /dev/null +++ b/cpan/podlators/lib/Pod/Text/Color.pm @@ -0,0 +1,146 @@ +# Pod::Text::Color -- Convert POD data to formatted color ASCII text +# +# Copyright 1999, 2001, 2004, 2006, 2008 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); + +$VERSION = '2.05'; + +############################################################################## +# Overrides +############################################################################## + +# Make level one headings bold. +sub cmd_head1 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $self->SUPER::cmd_head1 ($attrs, colored ($text, 'bold')); +} + +# Make level two headings bold. +sub cmd_head2 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $self->SUPER::cmd_head2 ($attrs, colored ($text, 'bold')); +} + +# Fix the various formatting codes. +sub cmd_b { return colored ($_[2], 'bold') } +sub cmd_f { return colored ($_[2], 'cyan') } +sub cmd_i { return colored ($_[2], 'yellow') } + +# 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{opt_width} - $$self{MARGIN}; + + # We have to do $shortchar and $longchar in variables because the + # construct ${char}{0,$width} didn't do the right thing until Perl 5.8.x. + my $char = '(?:(?:\e\[[\d;]+m)*[^\n])'; + my $shortchar = $char . "{0,$width}"; + my $longchar = $char . "{$width}"; + while (length > $width) { + if (s/^($shortchar)\s+// || s/^($longchar)//) { + $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 + +=for stopwords +Allbery + +=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::Simple> + +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, 2004, 2006, 2008 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/cpan/podlators/lib/Pod/Text/Overstrike.pm b/cpan/podlators/lib/Pod/Text/Overstrike.pm new file mode 100644 index 0000000000..a76fc28f8e --- /dev/null +++ b/cpan/podlators/lib/Pod/Text/Overstrike.pm @@ -0,0 +1,212 @@ +# Pod::Text::Overstrike -- Convert POD data to formatted overstrike text +# +# Created by Joe Smith <Joe.Smith@inwap.com> 30-Nov-2000 +# (based on Pod::Text::Color by Russ Allbery <rra@stanford.edu>) +# Copyright 2000 Joe Smith <Joe.Smith@inwap.com>. +# Copyright 2001, 2004, 2008 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); + +$VERSION = '2.03'; + +############################################################################## +# Overrides +############################################################################## + +# Make level one headings bold, overridding any existing formatting. +sub cmd_head1 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $text = $self->strip_format ($text); + $text =~ s/(.)/$1\b$1/g; + return $self->SUPER::cmd_head1 ($attrs, $text); +} + +# Make level two headings bold, overriding any existing formatting. +sub cmd_head2 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $text = $self->strip_format ($text); + $text =~ s/(.)/$1\b$1/g; + return $self->SUPER::cmd_head2 ($attrs, $text); +} + +# Make level three headings underscored, overriding any existing formatting. +sub cmd_head3 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $text = $self->strip_format ($text); + $text =~ s/(.)/_\b$1/g; + return $self->SUPER::cmd_head3 ($attrs, $text); +} + +# Level four headings look like level three headings. +sub cmd_head4 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $text = $self->strip_format ($text); + $text =~ s/(.)/_\b$1/g; + return $self->SUPER::cmd_head4 ($attrs, $text); +} + +# The common code for handling all headers. We have to override to avoid +# interpolating twice and because we don't want to honor alt. +sub heading { + my ($self, $text, $indent, $marker) = @_; + $self->item ("\n\n") if defined $$self{ITEM}; + $text .= "\n" if $$self{opt_loose}; + my $margin = ' ' x ($$self{opt_margin} + $indent); + $self->output ($margin . $text . "\n"); + return ''; +} + +# Fix the various formatting codes. +sub cmd_b { local $_ = $_[0]->strip_format ($_[2]); s/(.)/$1\b$1/g; $_ } +sub cmd_f { local $_ = $_[0]->strip_format ($_[2]); s/(.)/_\b$1/g; $_ } +sub cmd_i { local $_ = $_[0]->strip_format ($_[2]); s/(.)/_\b$1/g; $_ } + +# Output any included code in bold. +sub output_code { + my ($self, $code) = @_; + $code =~ s/(.)/$1\b$1/g; + $self->output ($code); +} + +# We unfortunately have to override the wrapping code here, since the normal +# wrapping code gets really confused by all the backspaces. +sub wrap { + my $self = shift; + local $_ = shift; + my $output = ''; + my $spaces = ' ' x $$self{MARGIN}; + my $width = $$self{opt_width} - $$self{MARGIN}; + while (length > $width) { + # This regex represents a single character, that's possibly underlined + # or in bold (in which case, it's three characters; the character, a + # backspace, and a character). Use [^\n] rather than . to protect + # against odd settings of $*. + my $char = '(?:[^\n][\b])?[^\n]'; + if (s/^((?>$char){0,$width})(?:\Z|\s+)//) { + $output .= $spaces . $1 . "\n"; + } else { + last; + } + } + $output .= $spaces . $_; + $output =~ s/\s+$/\n\n/; + return $output; +} + +############################################################################## +# 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 + +=for stopwords +overstrike + +Pod::Text::Overstrike - Convert POD data to formatted overstrike text + +=for stopwords +overstruck Overstruck Allbery terminal's + +=head1 SYNOPSIS + + use Pod::Text::Overstrike; + my $parser = Pod::Text::Overstrike->new (sentence => 0, width => 78); + + # Read POD from STDIN and write to STDOUT. + $parser->parse_from_filehandle; + + # Read POD from file.pod and write to file.txt. + $parser->parse_from_file ('file.pod', 'file.txt'); + +=head1 DESCRIPTION + +Pod::Text::Overstrike is a simple subclass of Pod::Text that highlights +output text using overstrike sequences, in a manner similar to nroff. +Characters in bold text are overstruck (character, backspace, character) +and characters in underlined text are converted to overstruck underscores +(underscore, backspace, character). This format was originally designed +for hard-copy terminals and/or line printers, yet is readable on soft-copy +(CRT) terminals. + +Overstruck text is best viewed by page-at-a-time programs that take +advantage of the terminal's B<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::Simple> + +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, 2004 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/cpan/podlators/lib/Pod/Text/Termcap.pm b/cpan/podlators/lib/Pod/Text/Termcap.pm new file mode 100644 index 0000000000..4a75b30251 --- /dev/null +++ b/cpan/podlators/lib/Pod/Text/Termcap.pm @@ -0,0 +1,184 @@ +# Pod::Text::Termcap -- Convert POD data to ASCII text with format escapes. +# +# Copyright 1999, 2001, 2002, 2004, 2006, 2008 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); + +$VERSION = '2.05'; + +############################################################################## +# Overrides +############################################################################## + +# In the initialization method, grab our terminal characteristics as well as +# do all the stuff we normally do. +sub new { + my ($self, @args) = @_; + my ($ospeed, $term, $termios); + $self = $self->SUPER::new (@args); + + # $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{opt_width} = $ENV{COLUMNS} || $$term{_co} || 80; + $$self{opt_width} -= 2; + } + + return $self; +} + +# Make level one headings bold. +sub cmd_head1 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $self->SUPER::cmd_head1 ($attrs, "$$self{BOLD}$text$$self{NORM}"); +} + +# Make level two headings bold. +sub cmd_head2 { + my ($self, $attrs, $text) = @_; + $text =~ s/\s+$//; + $self->SUPER::cmd_head2 ($attrs, "$$self{BOLD}$text$$self{NORM}"); +} + +# Fix up B<> and I<>. Note that we intentionally don't do F<>. +sub cmd_b { my $self = shift; return "$$self{BOLD}$_[1]$$self{NORM}" } +sub cmd_i { my $self = shift; return "$$self{UNDL}$_[1]$$self{NORM}" } + +# 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{opt_width} - $$self{MARGIN}; + + # $codes matches a single special sequence. $char matches any number of + # special sequences preceeding a single character other than a newline. + # We have to do $shortchar and $longchar in variables because the + # construct ${char}{0,$width} didn't do the right thing until Perl 5.8.x. + my $codes = "(?:\Q$$self{BOLD}\E|\Q$$self{UNDL}\E|\Q$$self{NORM}\E)"; + my $char = "(?:$codes*[^\\n])"; + my $shortchar = $char . "{0,$width}"; + my $longchar = $char . "{$width}"; + while (length > $width) { + if (s/^($shortchar)\s+// || s/^($longchar)//) { + $output .= $spaces . $1 . "\n"; + } else { + last; + } + } + $output .= $spaces . $_; + $output =~ s/\s+$/\n\n/; + return $output; +} + +############################################################################## +# Module return value and documentation +############################################################################## + +1; +__END__ + +=head1 NAME + +Pod::Text::Termcap - Convert POD data to ASCII text with format escapes + +=for stopwords +ECMA-48 VT100 Allbery + +=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::Simple>, 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, 2004, 2006, 2008 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/cpan/podlators/t/basic.cap b/cpan/podlators/t/basic.cap new file mode 100644 index 0000000000..20fc1e561c --- /dev/null +++ b/cpan/podlators/t/basic.cap @@ -0,0 +1,268 @@ +[1mNAME[m + basic.pod - Test of various basic POD features in translators. + +[1mHEADINGS[m + Try a few different levels of headings, with embedded formatting codes and + other interesting bits. + +[1mThis "is" a "level 1" heading[m + [1m``Level'' "2 [4mheading[m[m + Level 3 [1mheading [4mwith "weird stuff "" (double quote)"[m[m + Level "4 "heading" + Now try again with [1mintermixed[m text. + +[1mThis "is" a "level 1" heading[m + Text. + + [1m``Level'' 2 [4mheading[m[m + Text. + + Level 3 [1mheading [4mwith "weird stuff"[m[m + Text. + + Level "4 "heading" + Text. + +[1mLINKS[m + These are all taken from the Pod::Parser tests. + + Try out [4mLOTS[m of different ways of specifying references: + + Reference the "section" in manpage + + Reference the "section" in "manpage" + + Reference the "section" in manpage + + Now try it using the new "|" stuff ... + + Reference the thistext| + + Reference the thistext | + + Reference the thistext| + + Reference the thistext | + + Reference the thistext| + + Reference the thistext| + + And then throw in a few new ones of my own. + + foo + + foo + + "bar" in foo + + "baz boo" in foo + + "bar" + + "baz boo" + + "baz boo" + + "baz boo" in foo bar + + "boo var baz" + + "bar baz" + + "boo", "bar", and "baz" + + foobar + + Testing [4mitalics[m + + "[4mItalic[m text" in foo + + "Section "with" [4m[1mother[m markup[m" in foo|bar + + Nested <http://www.perl.org/> + +[1mOVER AND ITEMS[m + Taken from Pod::Parser tests, this is a test to ensure that multiline + =item paragraphs get indented appropriately. + + This is a test. + + There should be whitespace now before this line. + + Taken from Pod::Parser tests, this is a test to ensure the nested =item + paragraphs get indented appropriately. + + 1 First section. + + a this is item a + + b this is item b + + 2 Second section. + + a this is item a + + b this is item b + + c + d This is item c & d. + + Now some additional weirdness of our own. Make sure that multiple tags for + one paragraph are properly compacted. + + "foo" + [1mbar[m + "baz" + There shouldn't be any spaces between any of these item tags; this + idiom is used in perlfunc. + + Some longer item text + Just to make sure that we test paragraphs where the item text doesn't + fit in the margin of the paragraph (and make sure that this paragraph + fills a few lines). + + Let's also make it multiple paragraphs to be sure that works. + + Test use of =over without =item as a block "quote" or block paragraph. + + This should be indented four spaces but otherwise formatted the same + as any other regular text paragraph. Make sure it's long enough to see + the results of the formatting..... + + Now try the same thing nested, and make sure that the indentation is reset + back properly. + + This paragraph should be doubly indented. + + This paragraph should only be singly indented. + + * This is an item in the middle of a block-quote, which should be + allowed. + + * We're also testing tagless item commands. + + Should be back to the single level of indentation. + + Should be back to regular indentation. + + Now also check the transformation of * into real bullets for man pages. + + * An item. We're also testing using =over without a number, and making + sure that item text wraps properly. + + * Another item. + + and now test the numbering of item blocks. + + 1. First item. + + 2. Second item. + +[1mFORMATTING CODES[m + Another test taken from Pod::Parser. + + This is a test to see if I can do not only $self and "method()", but also + "$self->method()" and "$self->{FIELDNAME}" and "$Foo <=> $Bar" without + resorting to escape sequences. If I want to refer to the right-shift + operator I can do something like "$x >> 3" or even "$y >> 5". + + Now for the grand finale of "$self->method()->{FIELDNAME} = {FOO=>BAR}". + And I also want to make sure that newlines work like this "$self->{FOOBAR} + >> 3 and [$b => $a]->[$a <=> $b]" + + Of course I should still be able to do all this [4mwith[m escape sequences too: + "$self->method()" and "$self->{FIELDNAME}" and "{FOO=>BAR}". + + Dont forget "$self->method()->{FIELDNAME} = {FOO=>BAR}". + + And make sure that 0 works too! + + Now, if I use << or >> as my delimiters, then I have to use whitespace. So + things like "<$self-"method()>> and "<$self-"{FIELDNAME}>> wont end up + doing what you might expect since the first > will still terminate the + first < seen. + + Lets make sure these work for empty ones too, like "" and ">>" (just to be + obnoxious) + + The statement: "This is dog kind's [4mfinest[m hour!" is a parody of a + quotation from Winston Churchill. + + The following tests are added to those: + + Make sure that a few other odd [4mthings[m still work. This should be a + vertical bar: |. Here's a test of a few more special escapes that have to + be supported: + + & An ampersand. + + ' An apostrophe. + + < A less-than sign. + + > A greater-than sign. + + " A double quotation mark. + + / A forward slash. + + Try to get this bit of text over towards the edge so + |that all of this text inside S<> won't| be wrapped. Also test the + |same thing with non-breaking spaces.| + + There is a soft hyphen in hyphen at hy-phen. + + This is a test of an index entry. + +[1mVERBATIM[m + Throw in a few verbatim paragraphs. + + use Term::ANSIColor; + print color 'bold blue'; + print "This text is bold blue.\n"; + print color 'reset'; + print "This text is normal.\n"; + print colored ("Yellow on magenta.\n", 'yellow on_magenta'); + print "This text is normal.\n"; + print colored ['yellow on_magenta'], "Yellow on magenta.\n"; + + use Term::ANSIColor qw(uncolor); + print uncolor '01;31', "\n"; + + But this isn't verbatim (make sure it wraps properly), and the next + paragraph is again: + + use Term::ANSIColor qw(:constants); + print BOLD, BLUE, "This text is in bold blue.\n", RESET; + + use Term::ANSIColor qw(:constants); $Term::ANSIColor::AUTORESET = 1; print BOLD BLUE "This text is in bold blue.\n"; print "This text is normal.\n"; + + (Ugh, that's obnoxiously long.) Try different spacing: + + Starting with a tab. + Not + starting + with + a + tab. But this should still be verbatim. + As should this. + + This isn't. + + This is. And this: is an internal tab. It should be: + |--| <= lined up with that. + + (Tricky, but tabs should be expanded before the translator starts in on + the text since otherwise text with mixed tabs and spaces will get messed + up.) + + And now we test verbatim paragraphs right before a heading. Older + versions of Pod::Man generated two spaces between paragraphs like this + and the heading. (In order to properly test this, one may have to + visually inspect the nroff output when run on the generated *roff + text, unfortunately.) + +[1mCONCLUSION[m + That's all, folks! + diff --git a/cpan/podlators/t/basic.clr b/cpan/podlators/t/basic.clr new file mode 100644 index 0000000000..f98857187a --- /dev/null +++ b/cpan/podlators/t/basic.clr @@ -0,0 +1,269 @@ +[1mNAME[0m + basic.pod - Test of various basic POD features in translators. + +[1mHEADINGS[0m + Try a few different levels of headings, with embedded formatting codes + and other interesting bits. + +[1mThis "is" a "level 1" heading[0m + [1m``Level'' "2 [33mheading[0m[0m + Level 3 [1mheading [33mwith "weird [36mstuff "" (double quote)[0m"[0m[0m + Level "4 "heading" + Now try again with [1mintermixed[0m [36mtext[0m. + +[1mThis "is" a "level 1" heading[0m + Text. + + [1m``Level'' 2 [33mheading[0m[0m + Text. + + Level 3 [1mheading [33mwith "weird [36mstuff[0m"[0m[0m + Text. + + Level "4 "heading" + Text. + +[1mLINKS[0m + These are all taken from the Pod::Parser tests. + + Try out [33mLOTS[0m of different ways of specifying references: + + Reference the "section" in manpage + + Reference the "section" in "manpage" + + Reference the "section" in manpage + + Now try it using the new "|" stuff ... + + Reference the thistext| + + Reference the thistext | + + Reference the thistext| + + Reference the thistext | + + Reference the thistext| + + Reference the thistext| + + And then throw in a few new ones of my own. + + foo + + foo + + "bar" in foo + + "baz boo" in foo + + "bar" + + "baz boo" + + "baz boo" + + "baz boo" in foo bar + + "boo var baz" + + "bar baz" + + "boo", "bar", and "baz" + + foobar + + Testing [33mitalics[0m + + "[33mItalic[0m text" in foo + + "Section "with" [33m[1mother[0m markup[0m" in foo|bar + + Nested <http://www.perl.org/> + +[1mOVER AND ITEMS[0m + Taken from Pod::Parser tests, this is a test to ensure that multiline + =item paragraphs get indented appropriately. + + This is a test. + + There should be whitespace now before this line. + + Taken from Pod::Parser tests, this is a test to ensure the nested =item + paragraphs get indented appropriately. + + 1 First section. + + a this is item a + + b this is item b + + 2 Second section. + + a this is item a + + b this is item b + + c + d This is item c & d. + + Now some additional weirdness of our own. Make sure that multiple tags + for one paragraph are properly compacted. + + "foo" + [1mbar[0m + "baz" + There shouldn't be any spaces between any of these item tags; this + idiom is used in perlfunc. + + Some longer item text + Just to make sure that we test paragraphs where the item text + doesn't fit in the margin of the paragraph (and make sure that this + paragraph fills a few lines). + + Let's also make it multiple paragraphs to be sure that works. + + Test use of =over without =item as a block "quote" or block paragraph. + + This should be indented four spaces but otherwise formatted the same + as any other regular text paragraph. Make sure it's long enough to + see the results of the formatting..... + + Now try the same thing nested, and make sure that the indentation is + reset back properly. + + This paragraph should be doubly indented. + + This paragraph should only be singly indented. + + * This is an item in the middle of a block-quote, which should be + allowed. + + * We're also testing tagless item commands. + + Should be back to the single level of indentation. + + Should be back to regular indentation. + + Now also check the transformation of * into real bullets for man pages. + + * An item. We're also testing using =over without a number, and making + sure that item text wraps properly. + + * Another item. + + and now test the numbering of item blocks. + + 1. First item. + + 2. Second item. + +[1mFORMATTING CODES[0m + Another test taken from Pod::Parser. + + This is a test to see if I can do not only $self and "method()", but + also "$self->method()" and "$self->{FIELDNAME}" and "$Foo <=> $Bar" + without resorting to escape sequences. If I want to refer to the + right-shift operator I can do something like "$x >> 3" or even "$y >> + 5". + + Now for the grand finale of "$self->method()->{FIELDNAME} = {FOO=>BAR}". + And I also want to make sure that newlines work like this + "$self->{FOOBAR} >> 3 and [$b => $a]->[$a <=> $b]" + + Of course I should still be able to do all this [33mwith[0m escape sequences + too: "$self->method()" and "$self->{FIELDNAME}" and "{FOO=>BAR}". + + Dont forget "$self->method()->{FIELDNAME} = {FOO=>BAR}". + + And make sure that 0 works too! + + Now, if I use << or >> as my delimiters, then I have to use whitespace. + So things like "<$self-"method()>> and "<$self-"{FIELDNAME}>> wont end + up doing what you might expect since the first > will still terminate + the first < seen. + + Lets make sure these work for empty ones too, like "" and ">>" (just to + be obnoxious) + + The statement: "This is dog kind's [33mfinest[0m hour!" is a parody of a + quotation from Winston Churchill. + + The following tests are added to those: + + Make sure that a few other odd [33mthings[0m still work. This should be a + vertical bar: |. Here's a test of a few more special escapes that have + to be supported: + + & An ampersand. + + ' An apostrophe. + + < A less-than sign. + + > A greater-than sign. + + " A double quotation mark. + + / A forward slash. + + Try to get this bit of text over towards the edge so + |that all of this text inside S<> won't| be wrapped. Also test the + |same thing with non-breaking spaces.| + + There is a soft hyphen in hyphen at hy-phen. + + This is a test of an index entry. + +[1mVERBATIM[0m + Throw in a few verbatim paragraphs. + + use Term::ANSIColor; + print color 'bold blue'; + print "This text is bold blue.\n"; + print color 'reset'; + print "This text is normal.\n"; + print colored ("Yellow on magenta.\n", 'yellow on_magenta'); + print "This text is normal.\n"; + print colored ['yellow on_magenta'], "Yellow on magenta.\n"; + + use Term::ANSIColor qw(uncolor); + print uncolor '01;31', "\n"; + + But this isn't verbatim (make sure it wraps properly), and the next + paragraph is again: + + use Term::ANSIColor qw(:constants); + print BOLD, BLUE, "This text is in bold blue.\n", RESET; + + use Term::ANSIColor qw(:constants); $Term::ANSIColor::AUTORESET = 1; print BOLD BLUE "This text is in bold blue.\n"; print "This text is normal.\n"; + + (Ugh, that's obnoxiously long.) Try different spacing: + + Starting with a tab. + Not + starting + with + a + tab. But this should still be verbatim. + As should this. + + This isn't. + + This is. And this: is an internal tab. It should be: + |--| <= lined up with that. + + (Tricky, but tabs should be expanded before the translator starts in on + the text since otherwise text with mixed tabs and spaces will get messed + up.) + + And now we test verbatim paragraphs right before a heading. Older + versions of Pod::Man generated two spaces between paragraphs like this + and the heading. (In order to properly test this, one may have to + visually inspect the nroff output when run on the generated *roff + text, unfortunately.) + +[1mCONCLUSION[0m + That's all, folks! + diff --git a/cpan/podlators/t/basic.man b/cpan/podlators/t/basic.man new file mode 100644 index 0000000000..43874b6e87 --- /dev/null +++ b/cpan/podlators/t/basic.man @@ -0,0 +1,321 @@ +.SH "NAME" +basic.pod \- Test of various basic POD features in translators. +.SH "HEADINGS" +.IX Header "HEADINGS" +Try a few different levels of headings, with embedded formatting codes and +other interesting bits. +.ie n .SH "This ""is"" a ""level 1"" heading" +.el .SH "This \f(CWis\fP a ``level 1'' heading" +.IX Header "This is a level 1 heading" +.SS "``Level'' ""2 \fIheading\fP" +.IX Subsection "``Level'' ""2 heading" +\fILevel 3 \f(BIheading \f(BIwith \f(CB\*(C`weird \f(CBstuff "" (double quote)\f(CB\*(C'\f(BI\f(BI\fI\fR +.IX Subsection "Level 3 heading with weird stuff """" (double quote)" +.PP +Level "4 \f(CW\*(C`heading\*(C'\fR +.IX Subsection "Level ""4 heading" +.PP +Now try again with \fBintermixed\fR \fItext\fR. +.ie n .SH "This ""is"" a ""level 1"" heading" +.el .SH "This \f(CWis\fP a ``level 1'' heading" +.IX Header "This is a level 1 heading" +Text. +.SS "``Level'' 2 \fIheading\fP" +.IX Subsection "``Level'' 2 heading" +Text. +.PP +\fILevel 3 \f(BIheading \f(BIwith \f(CB\*(C`weird \f(CBstuff\f(CB\*(C'\f(BI\f(BI\fI\fR +.IX Subsection "Level 3 heading with weird stuff" +.PP +Text. +.PP +Level "4 \f(CW\*(C`heading\*(C'\fR +.IX Subsection "Level ""4 heading" +.PP +Text. +.SH "LINKS" +.IX Header "LINKS" +These are all taken from the Pod::Parser tests. +.PP +Try out \fI\s-1LOTS\s0\fR of different ways of specifying references: +.PP +Reference the \*(L"section\*(R" in manpage +.PP +Reference the \*(L"section\*(R" in \*(L"manpage\*(R" +.PP +Reference the \*(L"section\*(R" in manpage +.PP +Now try it using the new \*(L"|\*(R" stuff ... +.PP +Reference the thistext| +.PP +Reference the thistext | +.PP +Reference the thistext| +.PP +Reference the thistext | +.PP +Reference the thistext| +.PP +Reference the thistext| +.PP +And then throw in a few new ones of my own. +.PP +foo +.PP +foo +.PP +\&\*(L"bar\*(R" in foo +.PP +\&\*(L"baz boo\*(R" in foo +.PP +\&\*(L"bar\*(R" +.PP +\&\*(L"baz boo\*(R" +.PP +\&\*(L"baz boo\*(R" +.PP +\&\*(L"baz boo\*(R" in foo bar +.PP +\&\*(L"boo var baz\*(R" +.PP +\&\*(L"bar baz\*(R" +.PP +\&\*(L"boo\*(R", \*(L"bar\*(R", and \*(L"baz\*(R" +.PP +foobar +.PP +Testing \fIitalics\fR +.PP +"\fIItalic\fR text" in foo +.PP +"Section \f(CW\*(C`with\*(C'\fR \fI\f(BIother\fI markup\fR" in foo|bar +.PP +Nested <http://www.perl.org/> +.SH "OVER AND ITEMS" +.IX Header "OVER AND ITEMS" +Taken from Pod::Parser tests, this is a test to ensure that multiline +=item paragraphs get indented appropriately. +.IP "This is a test." 4 +.IX Item "This is a test." +.PP +There should be whitespace now before this line. +.PP +Taken from Pod::Parser tests, this is a test to ensure the nested =item +paragraphs get indented appropriately. +.IP "1." 2 +First section. +.RS 2 +.IP "a" 2 +.IX Item "a" +this is item a +.IP "b" 2 +.IX Item "b" +this is item b +.RE +.RS 2 +.RE +.IP "2." 2 +Second section. +.RS 2 +.IP "a" 2 +.IX Item "a" +this is item a +.IP "b" 2 +.IX Item "b" +this is item b +.IP "c" 2 +.IX Item "c" +.PD 0 +.IP "d" 2 +.IX Item "d" +.PD +This is item c & d. +.RE +.RS 2 +.RE +.PP +Now some additional weirdness of our own. Make sure that multiple tags +for one paragraph are properly compacted. +.ie n .IP """foo""" 4 +.el .IP "``foo''" 4 +.IX Item "foo" +.PD 0 +.IP "\fBbar\fR" 4 +.IX Item "bar" +.ie n .IP """baz""" 4 +.el .IP "\f(CWbaz\fR" 4 +.IX Item "baz" +.PD +There shouldn't be any spaces between any of these item tags; this idiom +is used in perlfunc. +.IP "Some longer item text" 4 +.IX Item "Some longer item text" +Just to make sure that we test paragraphs where the item text doesn't fit +in the margin of the paragraph (and make sure that this paragraph fills a +few lines). +.Sp +Let's also make it multiple paragraphs to be sure that works. +.PP +Test use of =over without =item as a block \*(L"quote\*(R" or block paragraph. +.Sp +.RS 4 +This should be indented four spaces but otherwise formatted the same as +any other regular text paragraph. Make sure it's long enough to see the +results of the formatting..... +.RE +.PP +Now try the same thing nested, and make sure that the indentation is reset +back properly. +.RS 4 +.Sp +.RS 4 +This paragraph should be doubly indented. +.RE +.RE +.RS 4 +.Sp +This paragraph should only be singly indented. +.IP "\(bu" 4 +This is an item in the middle of a block-quote, which should be allowed. +.IP "\(bu" 4 +We're also testing tagless item commands. +.RE +.RS 4 +.Sp +Should be back to the single level of indentation. +.RE +.PP +Should be back to regular indentation. +.PP +Now also check the transformation of * into real bullets for man pages. +.IP "\(bu" 4 +An item. We're also testing using =over without a number, and making sure +that item text wraps properly. +.IP "\(bu" 4 +Another item. +.PP +and now test the numbering of item blocks. +.IP "1." 4 +First item. +.IP "2." 4 +Second item. +.SH "FORMATTING CODES" +.IX Header "FORMATTING CODES" +Another test taken from Pod::Parser. +.PP +This is a test to see if I can do not only \f(CW$self\fR and \f(CW\*(C`method()\*(C'\fR, but +also \f(CW\*(C`$self\->method()\*(C'\fR and \f(CW\*(C`$self\->{FIELDNAME}\*(C'\fR and +\&\f(CW\*(C`$Foo <=> $Bar\*(C'\fR without resorting to escape sequences. If +I want to refer to the right-shift operator I can do something +like \f(CW\*(C`$x >> 3\*(C'\fR or even \f(CW\*(C`$y >> 5\*(C'\fR. +.PP +Now for the grand finale of \f(CW\*(C`$self\->method()\->{FIELDNAME} = {FOO=>BAR}\*(C'\fR. +And I also want to make sure that newlines work like this +\&\f(CW\*(C`$self\->{FOOBAR} >> 3 and [$b => $a]\->[$a <=> $b]\*(C'\fR +.PP +Of course I should still be able to do all this \fIwith\fR escape sequences +too: \f(CW\*(C`$self\->method()\*(C'\fR and \f(CW\*(C`$self\->{FIELDNAME}\*(C'\fR and +\&\f(CW\*(C`{FOO=>BAR}\*(C'\fR. +.PP +Dont forget \f(CW\*(C`$self\->method()\->{FIELDNAME} = {FOO=>BAR}\*(C'\fR. +.PP +And make sure that \f(CW0\fR works too! +.PP +Now, if I use << or >> as my delimiters, then I have to use whitespace. +So things like \f(CW\*(C`<$self\-\*(C'\fR\fImethod()\fR>> and \f(CW\*(C`<$self\-\*(C'\fR{\s-1FIELDNAME\s0}>> wont end +up doing what you might expect since the first > will still terminate +the first < seen. +.PP +Lets make sure these work for empty ones too, like \f(CW\*(C`\*(C'\fR and \f(CW\*(C`>>\*(C'\fR +(just to be obnoxious) +.PP +The statement: \f(CW\*(C`This is dog kind\*(Aqs \f(CIfinest\f(CW hour!\*(C'\fR is a parody of a +quotation from Winston Churchill. +.PP +The following tests are added to those: +.PP +Make sure that a few other odd \fIthings\fR still work. This should be +a vertical bar: |. Here's a test of a few more special escapes +that have to be supported: +.IP "&" 3 +An ampersand. +.IP "'" 3 +An apostrophe. +.IP "<" 3 +A less-than sign. +.IP ">" 3 +A greater-than sign. +.IP """" 3 +A double quotation mark. +.IP "/" 3 +A forward slash. +.PP +Try to get this bit of text over towards the edge so |that\ all\ of\ this\ text\ inside\ S<>\ won't| be wrapped. Also test the +|same\ thing\ with\ non-breaking\ spaces.| +.PP +There is a soft hy\%phen in hyphen at hy-phen. +.PP +This is a test of an index entry. +.IX Xref "index entry" +.SH "VERBATIM" +.IX Header "VERBATIM" +Throw in a few verbatim paragraphs. +.PP +.Vb 8 +\& use Term::ANSIColor; +\& print color \*(Aqbold blue\*(Aq; +\& print "This text is bold blue.\en"; +\& print color \*(Aqreset\*(Aq; +\& print "This text is normal.\en"; +\& print colored ("Yellow on magenta.\en", \*(Aqyellow on_magenta\*(Aq); +\& print "This text is normal.\en"; +\& print colored [\*(Aqyellow on_magenta\*(Aq], "Yellow on magenta.\en"; +\& +\& use Term::ANSIColor qw(uncolor); +\& print uncolor \*(Aq01;31\*(Aq, "\en"; +.Ve +.PP +But this isn't verbatim (make sure it wraps properly), and the next +paragraph is again: +.PP +.Vb 2 +\& use Term::ANSIColor qw(:constants); +\& print BOLD, BLUE, "This text is in bold blue.\en", RESET; +\& +\& use Term::ANSIColor qw(:constants); $Term::ANSIColor::AUTORESET = 1; print BOLD BLUE "This text is in bold blue.\en"; print "This text is normal.\en"; +.Ve +.PP +(Ugh, that's obnoxiously long.) Try different spacing: +.PP +.Vb 7 +\& Starting with a tab. +\&Not +\&starting +\&with +\&a +\&tab. But this should still be verbatim. +\& As should this. +.Ve +.PP +This isn't. +.PP +.Vb 2 +\& This is. And this: is an internal tab. It should be: +\& |\-\-| <= lined up with that. +.Ve +.PP +(Tricky, but tabs should be expanded before the translator starts in on +the text since otherwise text with mixed tabs and spaces will get messed +up.) +.PP +.Vb 5 +\& And now we test verbatim paragraphs right before a heading. Older +\& versions of Pod::Man generated two spaces between paragraphs like this +\& and the heading. (In order to properly test this, one may have to +\& visually inspect the nroff output when run on the generated *roff +\& text, unfortunately.) +.Ve +.SH "CONCLUSION" +.IX Header "CONCLUSION" +That's all, folks! diff --git a/cpan/podlators/t/basic.ovr b/cpan/podlators/t/basic.ovr new file mode 100644 index 0000000000..bb124a0bd4 --- /dev/null +++ b/cpan/podlators/t/basic.ovr @@ -0,0 +1,269 @@ +NNAAMMEE + basic.pod - Test of various basic POD features in translators. + +HHEEAADDIINNGGSS + Try a few different levels of headings, with embedded formatting codes + and other interesting bits. + +TThhiiss ""iiss"" aa ""lleevveell 11"" hheeaaddiinngg + ````LLeevveell'''' ""22 hheeaaddiinngg + _L_e_v_e_l_ _3_ _h_e_a_d_i_n_g_ _w_i_t_h_ _"_w_e_i_r_d_ _s_t_u_f_f_ _"_"_ _(_d_o_u_b_l_e_ _q_u_o_t_e_)_" + _L_e_v_e_l_ _"_4_ _"_h_e_a_d_i_n_g_" + Now try again with iinntteerrmmiixxeedd _t_e_x_t. + +TThhiiss ""iiss"" aa ""lleevveell 11"" hheeaaddiinngg + Text. + + ````LLeevveell'''' 22 hheeaaddiinngg + Text. + + _L_e_v_e_l_ _3_ _h_e_a_d_i_n_g_ _w_i_t_h_ _"_w_e_i_r_d_ _s_t_u_f_f_" + Text. + + _L_e_v_e_l_ _"_4_ _"_h_e_a_d_i_n_g_" + Text. + +LLIINNKKSS + These are all taken from the Pod::Parser tests. + + Try out _L_O_T_S of different ways of specifying references: + + Reference the "section" in manpage + + Reference the "section" in "manpage" + + Reference the "section" in manpage + + Now try it using the new "|" stuff ... + + Reference the thistext| + + Reference the thistext | + + Reference the thistext| + + Reference the thistext | + + Reference the thistext| + + Reference the thistext| + + And then throw in a few new ones of my own. + + foo + + foo + + "bar" in foo + + "baz boo" in foo + + "bar" + + "baz boo" + + "baz boo" + + "baz boo" in foo bar + + "boo var baz" + + "bar baz" + + "boo", "bar", and "baz" + + foobar + + Testing _i_t_a_l_i_c_s + + "_I_t_a_l_i_c text" in foo + + "Section "with" _o_t_h_e_r_ _m_a_r_k_u_p" in foo|bar + + Nested <http://www.perl.org/> + +OOVVEERR AANNDD IITTEEMMSS + Taken from Pod::Parser tests, this is a test to ensure that multiline + =item paragraphs get indented appropriately. + + This is a test. + + There should be whitespace now before this line. + + Taken from Pod::Parser tests, this is a test to ensure the nested =item + paragraphs get indented appropriately. + + 1 First section. + + a this is item a + + b this is item b + + 2 Second section. + + a this is item a + + b this is item b + + c + d This is item c & d. + + Now some additional weirdness of our own. Make sure that multiple tags + for one paragraph are properly compacted. + + "foo" + bbaarr + "baz" + There shouldn't be any spaces between any of these item tags; this + idiom is used in perlfunc. + + Some longer item text + Just to make sure that we test paragraphs where the item text + doesn't fit in the margin of the paragraph (and make sure that this + paragraph fills a few lines). + + Let's also make it multiple paragraphs to be sure that works. + + Test use of =over without =item as a block "quote" or block paragraph. + + This should be indented four spaces but otherwise formatted the same + as any other regular text paragraph. Make sure it's long enough to + see the results of the formatting..... + + Now try the same thing nested, and make sure that the indentation is + reset back properly. + + This paragraph should be doubly indented. + + This paragraph should only be singly indented. + + * This is an item in the middle of a block-quote, which should be + allowed. + + * We're also testing tagless item commands. + + Should be back to the single level of indentation. + + Should be back to regular indentation. + + Now also check the transformation of * into real bullets for man pages. + + * An item. We're also testing using =over without a number, and making + sure that item text wraps properly. + + * Another item. + + and now test the numbering of item blocks. + + 1. First item. + + 2. Second item. + +FFOORRMMAATTTTIINNGG CCOODDEESS + Another test taken from Pod::Parser. + + This is a test to see if I can do not only $self and "method()", but + also "$self->method()" and "$self->{FIELDNAME}" and "$Foo <=> $Bar" + without resorting to escape sequences. If I want to refer to the + right-shift operator I can do something like "$x >> 3" or even "$y >> + 5". + + Now for the grand finale of "$self->method()->{FIELDNAME} = {FOO=>BAR}". + And I also want to make sure that newlines work like this + "$self->{FOOBAR} >> 3 and [$b => $a]->[$a <=> $b]" + + Of course I should still be able to do all this _w_i_t_h escape sequences + too: "$self->method()" and "$self->{FIELDNAME}" and "{FOO=>BAR}". + + Dont forget "$self->method()->{FIELDNAME} = {FOO=>BAR}". + + And make sure that 0 works too! + + Now, if I use << or >> as my delimiters, then I have to use whitespace. + So things like "<$self-"method()>> and "<$self-"{FIELDNAME}>> wont end + up doing what you might expect since the first > will still terminate + the first < seen. + + Lets make sure these work for empty ones too, like "" and ">>" (just to + be obnoxious) + + The statement: "This is dog kind's _f_i_n_e_s_t hour!" is a parody of a + quotation from Winston Churchill. + + The following tests are added to those: + + Make sure that a few other odd _t_h_i_n_g_s still work. This should be a + vertical bar: |. Here's a test of a few more special escapes that have + to be supported: + + & An ampersand. + + ' An apostrophe. + + < A less-than sign. + + > A greater-than sign. + + " A double quotation mark. + + / A forward slash. + + Try to get this bit of text over towards the edge so + |that all of this text inside S<> won't| be wrapped. Also test the + |same thing with non-breaking spaces.| + + There is a soft hyphen in hyphen at hy-phen. + + This is a test of an index entry. + +VVEERRBBAATTIIMM + Throw in a few verbatim paragraphs. + + use Term::ANSIColor; + print color 'bold blue'; + print "This text is bold blue.\n"; + print color 'reset'; + print "This text is normal.\n"; + print colored ("Yellow on magenta.\n", 'yellow on_magenta'); + print "This text is normal.\n"; + print colored ['yellow on_magenta'], "Yellow on magenta.\n"; + + use Term::ANSIColor qw(uncolor); + print uncolor '01;31', "\n"; + + But this isn't verbatim (make sure it wraps properly), and the next + paragraph is again: + + use Term::ANSIColor qw(:constants); + print BOLD, BLUE, "This text is in bold blue.\n", RESET; + + use Term::ANSIColor qw(:constants); $Term::ANSIColor::AUTORESET = 1; print BOLD BLUE "This text is in bold blue.\n"; print "This text is normal.\n"; + + (Ugh, that's obnoxiously long.) Try different spacing: + + Starting with a tab. + Not + starting + with + a + tab. But this should still be verbatim. + As should this. + + This isn't. + + This is. And this: is an internal tab. It should be: + |--| <= lined up with that. + + (Tricky, but tabs should be expanded before the translator starts in on + the text since otherwise text with mixed tabs and spaces will get messed + up.) + + And now we test verbatim paragraphs right before a heading. Older + versions of Pod::Man generated two spaces between paragraphs like this + and the heading. (In order to properly test this, one may have to + visually inspect the nroff output when run on the generated *roff + text, unfortunately.) + +CCOONNCCLLUUSSIIOONN + That's all, folks! + diff --git a/cpan/podlators/t/basic.pod b/cpan/podlators/t/basic.pod new file mode 100644 index 0000000000..949b3a8886 --- /dev/null +++ b/cpan/podlators/t/basic.pod @@ -0,0 +1,383 @@ +=head1 NAME + +basic.pod - Test of various basic POD features in translators. + +=head1 HEADINGS + +Try a few different levels of headings, with embedded formatting codes and +other interesting bits. + +=head1 This C<is> a "level 1" heading + +=head2 ``Level'' "2 I<heading> + +=head3 Level 3 B<heading I<with C<weird F<stuff "" (double quote)>>>> + +=head4 Level "4 C<heading> + +Now try again with B<intermixed> F<text>. + +=head1 This C<is> a "level 1" heading + +Text. + +=head2 ``Level'' 2 I<heading> + +Text. + +=head3 Level 3 B<heading I<with C<weird F<stuff>>>> + +Text. + +=head4 Level "4 C<heading> + +Text. + +=head1 LINKS + +These are all taken from the Pod::Parser tests. + +Try out I<LOTS> of different ways of specifying references: + +Reference the L<manpage/section> + +Reference the L<"manpage"/section> + +Reference the L<manpage/"section"> + +Now try it using the new "|" stuff ... + +Reference the L<thistext|manpage/section>| + +Reference the L<thistext | manpage / section>| + +Reference the L<thistext| manpage/ section>| + +Reference the L<thistext |manpage /section>| + +Reference the L<thistext|manpage/"section">| + +Reference the L<thistext| +manpage/ +section>| + +And then throw in a few new ones of my own. + +L<foo> + +L<foo|bar> + +L<foo/bar> + +L<foo/"baz boo"> + +L</bar> + +L</"baz boo"> + +L</baz boo> + +L<foo bar/baz boo> + +L<"boo var baz"> + +L<bar baz> + +L</boo>, L</bar>, and L</baz> + +L<fooZ<>bar> + +L<Testing I<italics>|foo/bar> + +L<foo/I<Italic> text> + +L<fooE<verbar>barZ<>/Section C<with> I<B<other> markup>> + +L<Nested L<http://www.perl.org/>|fooE<sol>bar> + +=head1 OVER AND ITEMS + +Taken from Pod::Parser tests, this is a test to ensure that multiline +=item paragraphs get indented appropriately. + +=over 4 + +=item This +is +a +test. + +=back + +There should be whitespace now before this line. + +Taken from Pod::Parser tests, this is a test to ensure the nested =item +paragraphs get indented appropriately. + +=over 2 + +=item 1 + +First section. + +=over 2 + +=item a + +this is item a + +=item b + +this is item b + +=back + +=item 2 + +Second section. + +=over 2 + +=item a + +this is item a + +=item b + +this is item b + +=item c + +=item d + +This is item c & d. + +=back + +=back + +Now some additional weirdness of our own. Make sure that multiple tags +for one paragraph are properly compacted. + +=over 4 + +=item "foo" + +=item B<bar> + +=item C<baz> + +There shouldn't be any spaces between any of these item tags; this idiom +is used in perlfunc. + +=item Some longer item text + +Just to make sure that we test paragraphs where the item text doesn't fit +in the margin of the paragraph (and make sure that this paragraph fills a +few lines). + +Let's also make it multiple paragraphs to be sure that works. + +=back + +Test use of =over without =item as a block "quote" or block paragraph. + +=over 4 + +This should be indented four spaces but otherwise formatted the same as +any other regular text paragraph. Make sure it's long enough to see the +results of the formatting..... + +=back + +Now try the same thing nested, and make sure that the indentation is reset +back properly. + +=over 4 + +=over 4 + +This paragraph should be doubly indented. + +=back + +This paragraph should only be singly indented. + +=over 4 + +=item + +This is an item in the middle of a block-quote, which should be allowed. + +=item + +We're also testing tagless item commands. + +=back + +Should be back to the single level of indentation. + +=back + +Should be back to regular indentation. + +Now also check the transformation of * into real bullets for man pages. + +=over + +=item * + +An item. We're also testing using =over without a number, and making sure +that item text wraps properly. + +=item * + +Another item. + +=back + +and now test the numbering of item blocks. + +=over 4 + +=item 1. + +First item. + +=item 2. + +Second item. + +=back + +=head1 FORMATTING CODES + +Another test taken from Pod::Parser. + +This is a test to see if I can do not only C<$self> and C<method()>, but +also C<< $self->method() >> and C<< $self->{FIELDNAME} >> and +C<< $Foo <=> $Bar >> without resorting to escape sequences. If +I want to refer to the right-shift operator I can do something +like C<<< $x >> 3 >>> or even C<<<< $y >> 5 >>>>. + +Now for the grand finale of C<< $self->method()->{FIELDNAME} = {FOO=>BAR} >>. +And I also want to make sure that newlines work like this +C<<< +$self->{FOOBAR} >> 3 and [$b => $a]->[$a <=> $b] +>>> + +Of course I should still be able to do all this I<with> escape sequences +too: C<$self-E<gt>method()> and C<$self-E<gt>{FIELDNAME}> and +C<{FOO=E<gt>BAR}>. + +Dont forget C<$self-E<gt>method()-E<gt>{FIELDNAME} = {FOO=E<gt>BAR}>. + +And make sure that C<0> works too! + +Now, if I use << or >> as my delimiters, then I have to use whitespace. +So things like C<<$self->method()>> and C<<$self->{FIELDNAME}>> wont end +up doing what you might expect since the first > will still terminate +the first < seen. + +Lets make sure these work for empty ones too, like C<< >> and C<< >> >> +(just to be obnoxious) + +The statement: C<This is dog kind's I<finest> hour!> is a parody of a +quotation from Winston Churchill. + +The following tests are added to those: + +Make sure that a few othZ<>er odd I<Z<>things> still work. This should be +a vertical bar: E<verbar>. Here's a test of a few more special escapes +that have to be supported: + +=over 3 + +=item E<amp> + +An ampersand. + +=item E<apos> + +An apostrophe. + +=item E<lt> + +A less-than sign. + +=item E<gt> + +A greater-than sign. + +=item E<quot> + +A double quotation mark. + +=item E<sol> + +A forward slash. + +=back + +Try to get this bit of text over towards the edge so S<|that all of this +text inside SE<lt>E<gt> won't|> be wrapped. Also test the +|sameE<nbsp>thingE<nbsp>withE<nbsp>non-breakingS< spaces>.| + +There is a soft hyE<shy>phen in hyphen at hy-phen. + +This is a test of an X<index entry>index entry. + +=head1 VERBATIM + +Throw in a few verbatim paragraphs. + + use Term::ANSIColor; + print color 'bold blue'; + print "This text is bold blue.\n"; + print color 'reset'; + print "This text is normal.\n"; + print colored ("Yellow on magenta.\n", 'yellow on_magenta'); + print "This text is normal.\n"; + print colored ['yellow on_magenta'], "Yellow on magenta.\n"; + + use Term::ANSIColor qw(uncolor); + print uncolor '01;31', "\n"; + +But this isn't verbatim (make sure it wraps properly), and the next +paragraph is again: + + use Term::ANSIColor qw(:constants); + print BOLD, BLUE, "This text is in bold blue.\n", RESET; + + use Term::ANSIColor qw(:constants); $Term::ANSIColor::AUTORESET = 1; print BOLD BLUE "This text is in bold blue.\n"; print "This text is normal.\n"; + +(Ugh, that's obnoxiously long.) Try different spacing: + + Starting with a tab. +Not +starting +with +a +tab. But this should still be verbatim. + As should this. + +This isn't. + + This is. And this: is an internal tab. It should be: + |--| <= lined up with that. + +(Tricky, but tabs should be expanded before the translator starts in on +the text since otherwise text with mixed tabs and spaces will get messed +up.) + + And now we test verbatim paragraphs right before a heading. Older + versions of Pod::Man generated two spaces between paragraphs like this + and the heading. (In order to properly test this, one may have to + visually inspect the nroff output when run on the generated *roff + text, unfortunately.) + +=head1 CONCLUSION + +That's all, folks! + +=cut diff --git a/cpan/podlators/t/basic.t b/cpan/podlators/t/basic.t new file mode 100644 index 0000000000..603d108574 --- /dev/null +++ b/cpan/podlators/t/basic.t @@ -0,0 +1,127 @@ +#!/usr/bin/perl -w +# +# basic.t -- Basic tests for podlators. +# +# Copyright 2001, 2002, 2004, 2006 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..11\n"; +} + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::Man; +use Pod::Text; +use Pod::Text::Overstrike; +use Pod::Text::Termcap; + +# Find the path to the test source files. This requires some fiddling when +# these tests are run as part of Perl core. +sub source_path { + my $file = shift; + if ($ENV{PERL_CORE}) { + require File::Spec; + my $updir = File::Spec->updir; + my $dir = File::Spec->catdir ($updir, 'lib', 'Pod', 't'); + return File::Spec->catfile ($dir, $file); + } else { + return $file; + } +} + +$loaded = 1; +print "ok 1\n"; + +# Hard-code a few values to try to get reproducible results. +$ENV{COLUMNS} = 80; +$ENV{TERM} = 'xterm'; +$ENV{TERMCAP} = 'xterm:co=80:do=^J:md=\E[1m:us=\E[4m:me=\E[m'; + +# Map of translators to file extensions to find the formatted output to +# compare against. +my %translators = ('Pod::Man' => 'man', + 'Pod::Text' => 'txt', + 'Pod::Text::Color' => 'clr', + 'Pod::Text::Overstrike' => 'ovr', + 'Pod::Text::Termcap' => 'cap'); + +# Set default options to match those of pod2man and pod2text. +%options = (sentence => 0); + +my $n = 2; +for (sort keys %translators) { + if ($_ eq 'Pod::Text::Color') { + eval { require Term::ANSIColor }; + if ($@) { + print "ok $n # skip\n"; + $n++; + print "ok $n # skip\n"; + $n++; + next; + } + require Pod::Text::Color; + } + my $parser = $_->new (%options); + print (($parser && ref ($parser) eq $_) ? "ok $n\n" : "not ok $n\n"); + $n++; + + # For Pod::Man, strip out the autogenerated header up to the .TH title + # line. That means that we don't check those things; oh well. The header + # changes with each version change or touch of the input file. + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + $parser->parse_from_file (source_path ('basic.pod'), \*OUT); + close OUT; + if ($_ eq 'Pod::Man') { + open (TMP, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + open (OUTPUT, "> out.$translators{$_}") + or die "Cannot create out.$translators{$_}: $!\n"; + local $_; + while (<TMP>) { last if /^\.nh/ } + print OUTPUT while <TMP>; + close OUTPUT; + close TMP; + unlink 'out.tmp'; + } else { + rename ('out.tmp', "out.$translators{$_}") + or die "Cannot rename out.tmp: $!\n"; + } + { + local $/; + open (MASTER, source_path ("basic.$translators{$_}")) + or die "Cannot open basic.$translators{$_}: $!\n"; + open (OUTPUT, "out.$translators{$_}") + or die "Cannot open out.$translators{$_}: $!\n"; + my $master = <MASTER>; + my $output = <OUTPUT>; + close MASTER; + close OUTPUT; + + # OS/390 is EBCDIC, which uses a different character for ESC + # apparently. Try to convert so that the test still works. + if ($^O eq 'os390' && $_ eq 'Pod::Text::Termcap') { + $output =~ tr/\033/\047/; + } + + if ($master eq $output) { + print "ok $n\n"; + unlink "out.$translators{$_}"; + } else { + print "not ok $n\n"; + print "# Non-matching output left in out.$translators{$_}\n"; + } + } + $n++; +} diff --git a/cpan/podlators/t/basic.txt b/cpan/podlators/t/basic.txt new file mode 100644 index 0000000000..986e98a1cd --- /dev/null +++ b/cpan/podlators/t/basic.txt @@ -0,0 +1,269 @@ +NAME + basic.pod - Test of various basic POD features in translators. + +HEADINGS + Try a few different levels of headings, with embedded formatting codes + and other interesting bits. + +This "is" a "level 1" heading + ``Level'' "2 *heading* + Level 3 heading *with "weird stuff "" (double quote)"* + Level "4 "heading" + Now try again with intermixed text. + +This "is" a "level 1" heading + Text. + + ``Level'' 2 *heading* + Text. + + Level 3 heading *with "weird stuff"* + Text. + + Level "4 "heading" + Text. + +LINKS + These are all taken from the Pod::Parser tests. + + Try out *LOTS* of different ways of specifying references: + + Reference the "section" in manpage + + Reference the "section" in "manpage" + + Reference the "section" in manpage + + Now try it using the new "|" stuff ... + + Reference the thistext| + + Reference the thistext | + + Reference the thistext| + + Reference the thistext | + + Reference the thistext| + + Reference the thistext| + + And then throw in a few new ones of my own. + + foo + + foo + + "bar" in foo + + "baz boo" in foo + + "bar" + + "baz boo" + + "baz boo" + + "baz boo" in foo bar + + "boo var baz" + + "bar baz" + + "boo", "bar", and "baz" + + foobar + + Testing *italics* + + "*Italic* text" in foo + + "Section "with" *other markup*" in foo|bar + + Nested <http://www.perl.org/> + +OVER AND ITEMS + Taken from Pod::Parser tests, this is a test to ensure that multiline + =item paragraphs get indented appropriately. + + This is a test. + + There should be whitespace now before this line. + + Taken from Pod::Parser tests, this is a test to ensure the nested =item + paragraphs get indented appropriately. + + 1 First section. + + a this is item a + + b this is item b + + 2 Second section. + + a this is item a + + b this is item b + + c + d This is item c & d. + + Now some additional weirdness of our own. Make sure that multiple tags + for one paragraph are properly compacted. + + "foo" + bar + "baz" + There shouldn't be any spaces between any of these item tags; this + idiom is used in perlfunc. + + Some longer item text + Just to make sure that we test paragraphs where the item text + doesn't fit in the margin of the paragraph (and make sure that this + paragraph fills a few lines). + + Let's also make it multiple paragraphs to be sure that works. + + Test use of =over without =item as a block "quote" or block paragraph. + + This should be indented four spaces but otherwise formatted the same + as any other regular text paragraph. Make sure it's long enough to + see the results of the formatting..... + + Now try the same thing nested, and make sure that the indentation is + reset back properly. + + This paragraph should be doubly indented. + + This paragraph should only be singly indented. + + * This is an item in the middle of a block-quote, which should be + allowed. + + * We're also testing tagless item commands. + + Should be back to the single level of indentation. + + Should be back to regular indentation. + + Now also check the transformation of * into real bullets for man pages. + + * An item. We're also testing using =over without a number, and making + sure that item text wraps properly. + + * Another item. + + and now test the numbering of item blocks. + + 1. First item. + + 2. Second item. + +FORMATTING CODES + Another test taken from Pod::Parser. + + This is a test to see if I can do not only $self and "method()", but + also "$self->method()" and "$self->{FIELDNAME}" and "$Foo <=> $Bar" + without resorting to escape sequences. If I want to refer to the + right-shift operator I can do something like "$x >> 3" or even "$y >> + 5". + + Now for the grand finale of "$self->method()->{FIELDNAME} = {FOO=>BAR}". + And I also want to make sure that newlines work like this + "$self->{FOOBAR} >> 3 and [$b => $a]->[$a <=> $b]" + + Of course I should still be able to do all this *with* escape sequences + too: "$self->method()" and "$self->{FIELDNAME}" and "{FOO=>BAR}". + + Dont forget "$self->method()->{FIELDNAME} = {FOO=>BAR}". + + And make sure that 0 works too! + + Now, if I use << or >> as my delimiters, then I have to use whitespace. + So things like "<$self-"method()>> and "<$self-"{FIELDNAME}>> wont end + up doing what you might expect since the first > will still terminate + the first < seen. + + Lets make sure these work for empty ones too, like "" and ">>" (just to + be obnoxious) + + The statement: "This is dog kind's *finest* hour!" is a parody of a + quotation from Winston Churchill. + + The following tests are added to those: + + Make sure that a few other odd *things* still work. This should be a + vertical bar: |. Here's a test of a few more special escapes that have + to be supported: + + & An ampersand. + + ' An apostrophe. + + < A less-than sign. + + > A greater-than sign. + + " A double quotation mark. + + / A forward slash. + + Try to get this bit of text over towards the edge so + |that all of this text inside S<> won't| be wrapped. Also test the + |same thing with non-breaking spaces.| + + There is a soft hyphen in hyphen at hy-phen. + + This is a test of an index entry. + +VERBATIM + Throw in a few verbatim paragraphs. + + use Term::ANSIColor; + print color 'bold blue'; + print "This text is bold blue.\n"; + print color 'reset'; + print "This text is normal.\n"; + print colored ("Yellow on magenta.\n", 'yellow on_magenta'); + print "This text is normal.\n"; + print colored ['yellow on_magenta'], "Yellow on magenta.\n"; + + use Term::ANSIColor qw(uncolor); + print uncolor '01;31', "\n"; + + But this isn't verbatim (make sure it wraps properly), and the next + paragraph is again: + + use Term::ANSIColor qw(:constants); + print BOLD, BLUE, "This text is in bold blue.\n", RESET; + + use Term::ANSIColor qw(:constants); $Term::ANSIColor::AUTORESET = 1; print BOLD BLUE "This text is in bold blue.\n"; print "This text is normal.\n"; + + (Ugh, that's obnoxiously long.) Try different spacing: + + Starting with a tab. + Not + starting + with + a + tab. But this should still be verbatim. + As should this. + + This isn't. + + This is. And this: is an internal tab. It should be: + |--| <= lined up with that. + + (Tricky, but tabs should be expanded before the translator starts in on + the text since otherwise text with mixed tabs and spaces will get messed + up.) + + And now we test verbatim paragraphs right before a heading. Older + versions of Pod::Man generated two spaces between paragraphs like this + and the heading. (In order to properly test this, one may have to + visually inspect the nroff output when run on the generated *roff + text, unfortunately.) + +CONCLUSION + That's all, folks! + diff --git a/cpan/podlators/t/color.t b/cpan/podlators/t/color.t new file mode 100644 index 0000000000..2f1668f88e --- /dev/null +++ b/cpan/podlators/t/color.t @@ -0,0 +1,88 @@ +#!/usr/bin/perl -w +# +# color.t -- Additional specialized tests for Pod::Text::Color. +# +# Copyright 2002, 2004, 2006 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..2\n"; +} + +END { + print "not ok 1\n" unless $loaded; +} + +eval { require Term::ANSIColor }; +if ($@) { + for (1..2) { + print "ok $_ # skip\n"; + } + $loaded = 1; + exit; +} +require Pod::Text::Color; + +$loaded = 1; +print "ok 1\n"; + +my $parser = Pod::Text::Color->new or die "Cannot create parser\n"; +my $n = 2; +while (<DATA>) { + next until $_ eq "###\n"; + open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; + while (<DATA>) { + last if $_ eq "###\n"; + print TMP $_; + } + close TMP; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + $parser->parse_from_file ('tmp.pod', \*OUT); + close OUT; + open (TMP, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + my $output; + { + local $/; + $output = <TMP>; + } + close TMP; + unlink ('tmp.pod', 'out.tmp'); + my $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; +} + +# Below the marker are bits of POD and corresponding expected output. This is +# used to test specific features or problems with Pod::Text::Termcap. The +# input and output are separated by lines containing only ###. + +__DATA__ + +### +=head1 WRAPPING + +B<I<Do>> I<B<not>> B<I<include>> B<I<formatting codes when>> B<I<wrapping>>. +### +[1mWRAPPING[0m + [1m[33mDo[0m[0m [33m[1mnot[0m[0m [1m[33minclude[0m[0m [1m[33mformatting codes when[0m[0m [1m[33mwrapping[0m[0m. + +### diff --git a/cpan/podlators/t/filehandle.t b/cpan/podlators/t/filehandle.t new file mode 100644 index 0000000000..a53884d50d --- /dev/null +++ b/cpan/podlators/t/filehandle.t @@ -0,0 +1,121 @@ +#!/usr/bin/perl -w +# +# filehandle.t -- Test the parse_from_filehandle interface. +# +# Copyright 2006 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..3\n"; +} + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::Man; +use Pod::Text; + +$loaded = 1; +print "ok 1\n"; + +my $man = Pod::Man->new or die "Cannot create parser\n"; +my $text = Pod::Text->new or die "Cannot create parser\n"; +my $n = 2; +while (<DATA>) { + next until $_ eq "###\n"; + open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; + while (<DATA>) { + last if $_ eq "###\n"; + print TMP $_; + } + close TMP; + open (IN, '< tmp.pod') or die "Cannot open tmp.pod: $!\n"; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + $man->parse_from_filehandle (\*IN, \*OUT); + close IN; + close OUT; + open (OUT, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + while (<OUT>) { last if /^\.nh/ } + my $output; + { + local $/; + $output = <OUT>; + } + close OUT; + my $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; + open (IN, '< tmp.pod') or die "Cannot open tmp.pod: $!\n"; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + $text->parse_from_filehandle (\*IN, \*OUT); + close IN; + close OUT; + open (OUT, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + { + local $/; + $output = <OUT>; + } + close OUT; + unlink ('tmp.pod', 'out.tmp'); + $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; +} + +# Below the marker are bits of POD, corresponding expected nroff output, and +# corresponding expected text output. The input and output are separated by +# lines containing only ###. + +__DATA__ + +### +=head1 NAME + +gcc - GNU project C and C++ compiler + +=head1 C++ NOTES + +Other mentions of C++. +### +.SH "NAME" +gcc \- GNU project C and C++ compiler +.SH "\*(C+ NOTES" +.IX Header " NOTES" +Other mentions of \*(C+. +### +NAME + gcc - GNU project C and C++ compiler + +C++ NOTES + Other mentions of C++. + +### diff --git a/cpan/podlators/t/man-options.t b/cpan/podlators/t/man-options.t new file mode 100644 index 0000000000..04895d539c --- /dev/null +++ b/cpan/podlators/t/man-options.t @@ -0,0 +1,175 @@ +#!/usr/bin/perl -w +# +# man-options.t -- Additional tests for Pod::Man options. +# +# Copyright 2002, 2004, 2006, 2008 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..7\n"; +} + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::Man; + +# Redirect stderr to a file. +sub stderr_save { + open (OLDERR, '>&STDERR') or die "Can't dup STDERR: $!\n"; + open (STDERR, '> out.err') or die "Can't redirect STDERR: $!\n"; +} + +# Restore stderr. +sub stderr_restore { + close STDERR; + open (STDERR, '>&OLDERR') or die "Can't dup STDERR: $!\n"; + close OLDERR; +} + +$loaded = 1; +print "ok 1\n"; + +my $n = 2; +while (<DATA>) { + my %options; + next until $_ eq "###\n"; + while (<DATA>) { + last if $_ eq "###\n"; + my ($option, $value) = split; + $options{$option} = $value; + } + open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; + while (<DATA>) { + last if $_ eq "###\n"; + print TMP $_; + } + close TMP; + my $parser = Pod::Man->new (%options) or die "Cannot create parser\n"; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + stderr_save; + $parser->parse_from_file ('tmp.pod', \*OUT); + stderr_restore; + close OUT; + my $accents = 0; + open (TMP, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + while (<TMP>) { + last if /^\.nh/; + } + my $output; + { + local $/; + $output = <TMP>; + } + close TMP; + unlink ('tmp.pod', 'out.tmp'); + my $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; + open (ERR, 'out.err') or die "Cannot open out.err: $!\n"; + my $errors; + { + local $/; + $errors = <ERR>; + } + close ERR; + unlink ('out.err'); + $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($errors eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected errors:\n ${expected}Errors:\n $errors"; + } + $n++; +} + +# Below the marker are bits of POD and corresponding expected text output. +# This is used to test specific features or problems with Pod::Man. The +# input and output are separated by lines containing only ###. + +__DATA__ + +### +fixed CR +fixedbold CY +fixeditalic CW +fixedbolditalic CX +### +=head1 FIXED FONTS + +C<foo B<bar I<baz>> I<bay>> +### +.SH "FIXED FONTS" +.IX Header "FIXED FONTS" +\&\f(CR\*(C`foo \f(CYbar \f(CXbaz\f(CY\f(CR \f(CWbay\f(CR\*(C'\fR +### +### + +### +### +=over 4 + +=item Foo + +Bar. + +=head1 NEXT +### +.IP "Foo" 4 +.IX Item "Foo" +Bar. +.SH "NEXT" +.IX Header "NEXT" +.SH "POD ERRORS" +.IX Header "POD ERRORS" +Hey! \fBThe above document had some coding errors, which are explained below:\fR +.IP "Around line 7:" 4 +.IX Item "Around line 7:" +You forgot a '=back' before '=head1' +### +### + +### +stderr 1 +### +=over 4 + +=item Foo + +Bar. + +=head1 NEXT +### +.IP "Foo" 4 +.IX Item "Foo" +Bar. +.SH "NEXT" +.IX Header "NEXT" +### +tmp.pod around line 7: You forgot a '=back' before '=head1' +### diff --git a/cpan/podlators/t/man-utf8.t b/cpan/podlators/t/man-utf8.t new file mode 100644 index 0000000000..8b44d6b290 --- /dev/null +++ b/cpan/podlators/t/man-utf8.t @@ -0,0 +1,141 @@ +#!/usr/bin/perl -w +# +# man-options.t -- Additional tests for Pod::Man options. +# +# Copyright 2002, 2004, 2006, 2008 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..5\n"; + + # UTF-8 support requires Perl 5.8 or later. + if ($] < 5.008) { + my $n; + for $n (1..5) { + print "ok $n # skip -- Perl 5.8 required for UTF-8 support\n"; + } + exit; + } +} + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::Man; + +$loaded = 1; +print "ok 1\n"; + +my $n = 2; +eval { binmode (\*DATA, ':encoding(utf-8)') }; +eval { binmode (\*STDOUT, ':encoding(utf-8)') }; +while (<DATA>) { + my %options; + next until $_ eq "###\n"; + while (<DATA>) { + last if $_ eq "###\n"; + my ($option, $value) = split; + $options{$option} = $value; + } + open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; + eval { binmode (\*TMP, ':encoding(utf-8)') }; + print TMP "=encoding utf-8\n\n"; + while (<DATA>) { + last if $_ eq "###\n"; + print TMP $_; + } + close TMP; + my $parser = Pod::Man->new (%options) or die "Cannot create parser\n"; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + $parser->parse_from_file ('tmp.pod', \*OUT); + close OUT; + my $accents = 0; + open (TMP, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + eval { binmode (\*TMP, ':encoding(utf-8)') }; + while (<TMP>) { + $accents = 1 if /Accent mark definitions/; + last if /^\.nh/; + } + my $output; + { + local $/; + $output = <TMP>; + } + close TMP; + unlink ('tmp.pod', 'out.tmp'); + if (($options{utf8} && !$accents) || (!$options{utf8} && $accents)) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print ($accents ? "Saw accents\n" : "Saw no accents\n"); + print ($options{utf8} ? "Wanted no accents\n" : "Wanted accents\n"); + } + $n++; + my $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; +} + +# Below the marker are bits of POD and corresponding expected text output. +# This is used to test specific features or problems with Pod::Man. The +# input and output are separated by lines containing only ###. + +__DATA__ + +### +utf8 1 +### +=head1 BEYONCÉ + +Beyoncé! Beyoncé! Beyoncé!! + + Beyoncé! Beyoncé! + Beyoncé! Beyoncé! + Beyoncé! Beyoncé! + +Older versions did not convert Beyoncé in verbatim. +### +.SH "BEYONCÉ" +.IX Header "BEYONCÉ" +Beyoncé! Beyoncé! Beyoncé!! +.PP +.Vb 3 +\& Beyoncé! Beyoncé! +\& Beyoncé! Beyoncé! +\& Beyoncé! Beyoncé! +.Ve +.PP +Older versions did not convert Beyoncé in verbatim. +### + +### +utf8 1 +### +=head1 SE<lt>E<gt> output with UTF-8 + +This is S<non-breaking output>. +### +.SH "S<> output with UTF\-8" +.IX Header "S<> output with UTF-8" +This is non-breaking output. +### diff --git a/cpan/podlators/t/man.t b/cpan/podlators/t/man.t new file mode 100644 index 0000000000..419cce3ee6 --- /dev/null +++ b/cpan/podlators/t/man.t @@ -0,0 +1,484 @@ +#!/usr/bin/perl -w +# +# man.t -- Additional specialized tests for Pod::Man. +# +# Copyright 2002, 2003, 2004, 2006, 2007, 2008 +# 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..25\n"; +} + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::Man; + +$loaded = 1; +print "ok 1\n"; + +# Test whether we can use binmode to set encoding. +my $have_encoding = (eval { require PerlIO::encoding; 1 } and not $@); + +my $parser = Pod::Man->new or die "Cannot create parser\n"; +my $n = 2; +while (<DATA>) { + next until $_ eq "###\n"; + open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; + + # We have a test in ISO 8859-1 encoding. Make sure that nothing strange + # happens if Perl thinks the world is Unicode. Wrap this in eval so that + # older versions of Perl don't croak. + eval { binmode (\*TMP, ':encoding(iso-8859-1)') if $have_encoding }; + + while (<DATA>) { + last if $_ eq "###\n"; + print TMP $_; + } + close TMP; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + $parser->parse_from_file ('tmp.pod', \*OUT); + close OUT; + open (OUT, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + while (<OUT>) { last if /^\.nh/ } + my $output; + { + local $/; + $output = <OUT>; + } + close OUT; + unlink ('tmp.pod', 'out.tmp'); + my $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; +} + +# Below the marker are bits of POD and corresponding expected nroff output. +# This is used to test specific features or problems with Pod::Man. The input +# and output are separated by lines containing only ###. + +__DATA__ + +### +=head1 NAME + +gcc - GNU project C and C++ compiler + +=head1 C++ NOTES + +Other mentions of C++. +### +.SH "NAME" +gcc \- GNU project C and C++ compiler +.SH "\*(C+ NOTES" +.IX Header " NOTES" +Other mentions of \*(C+. +### + +### +=head1 PERIODS + +This C<.> should be quoted. +### +.SH "PERIODS" +.IX Header "PERIODS" +This \f(CW\*(C`.\*(C'\fR should be quoted. +### + +### +=over 4 + +=item * + +A bullet. + +=item * + +Another bullet. + +=item * Also a bullet. + +=back +### +.IP "\(bu" 4 +A bullet. +.IP "\(bu" 4 +Another bullet. +.IP "\(bu" 4 +Also a bullet. +### + +### +=over 4 + +=item foo + +Not a bullet. + +=item * + +Also not a bullet. + +=back +### +.IP "foo" 4 +.IX Item "foo" +Not a bullet. +.IP "*" 4 +Also not a bullet. +### + +### +=encoding iso-8859-1 + +=head1 ACCENTS + +Beyonc! Beyonc! Beyonc!! + + Beyonc! Beyonc! + Beyonc! Beyonc! + Beyonc! Beyonc! + +Older versions didn't convert Beyonc in verbatim. +### +.SH "ACCENTS" +.IX Header "ACCENTS" +Beyonce\*'! Beyonce\*'! Beyonce\*'!! +.PP +.Vb 3 +\& Beyonce\*'! Beyonce\*'! +\& Beyonce\*'! Beyonce\*'! +\& Beyonce\*'! Beyonce\*'! +.Ve +.PP +Older versions didn't convert Beyonce\*' in verbatim. +### + +### +=over 4 + +=item 1. Not a number + +=item 2. Spaced right + +=back + +=over 2 + +=item 1 Not a number + +=item 2 Spaced right + +=back +### +.IP "1. Not a number" 4 +.IX Item "1. Not a number" +.PD 0 +.IP "2. Spaced right" 4 +.IX Item "2. Spaced right" +.IP "1 Not a number" 2 +.IX Item "1 Not a number" +.IP "2 Spaced right" 2 +.IX Item "2 Spaced right" +### + +### +=over 4 + +=item Z<>* + +Not bullet. + +=back +### +.IP "*" 4 +Not bullet. +### + +### +=head1 SEQS + +"=over ... Z<>=back" + +"SE<lt>...E<gt>" + +The quotes should be converted in the above to paired quotes. +### +.SH "SEQS" +.IX Header "SEQS" +\&\*(L"=over ... =back\*(R" +.PP +\&\*(L"S<...>\*(R" +.PP +The quotes should be converted in the above to paired quotes. +### + +### +=head1 YEN + +It cost me E<165>12345! That should be an X. +### +.SH "YEN" +.IX Header "YEN" +It cost me X12345! That should be an X. +### + +### +=head1 agrave + +Open E<agrave> la shell. Previous versions mapped it wrong. +### +.SH "agrave" +.IX Header "agrave" +Open a\*` la shell. Previous versions mapped it wrong. +### + +### +=over + +=item First level + +Blah blah blah.... + +=over + +=item * + +Should be a bullet. + +=back + +=back +### +.IP "First level" 4 +.IX Item "First level" +Blah blah blah.... +.RS 4 +.IP "\(bu" 4 +Should be a bullet. +.RE +.RS 4 +.RE +### + +### +=over 4 + +=item 1. Check fonts in @CARP_NOT test. + +=back +### +.ie n .IP "1. Check fonts in @CARP_NOT test." 4 +.el .IP "1. Check fonts in \f(CW@CARP_NOT\fR test." 4 +.IX Item "1. Check fonts in @CARP_NOT test." +### + +### +=head1 LINK QUOTING + +There should not be double quotes: L<C<< (?>pattern) >>>. +### +.SH "LINK QUOTING" +.IX Header "LINK QUOTING" +There should not be double quotes: \f(CW\*(C`(?>pattern)\*(C'\fR. +### + +### +=head1 SE<lt>E<gt> MAGIC + +Magic should be applied S<RISC OS> to that. +### +.SH "S<> MAGIC" +.IX Header "S<> MAGIC" +Magic should be applied \s-1RISC\s0\ \s-1OS\s0 to that. +### + +### +=head1 MAGIC MONEY + +These should be identical. + +Bippity boppity boo "The +price is $Z<>100." + +Bippity boppity boo "The +price is $100." +### +.SH "MAGIC MONEY" +.IX Header "MAGIC MONEY" +These should be identical. +.PP +Bippity boppity boo \*(L"The +price is \f(CW$100\fR.\*(R" +.PP +Bippity boppity boo \*(L"The +price is \f(CW$100\fR.\*(R" +### + +### +=head1 NAME + +"Stuff" (no guesswork) + +=head2 THINGS + +Oboy, is this C++ "fun" yet! (guesswork) +### +.SH "NAME" +"Stuff" (no guesswork) +.SS "\s-1THINGS\s0" +.IX Subsection "THINGS" +Oboy, is this \*(C+ \*(L"fun\*(R" yet! (guesswork) +### + +### +=head1 Newline C Quote Weirdness + +Blorp C<' +''>. Yes. +### +.SH "Newline C Quote Weirdness" +.IX Header "Newline C Quote Weirdness" +Blorp \f(CW\*(Aq +\&\*(Aq\*(Aq\fR. Yes. +### + +### +=head1 Soft Hypen Testing + +sigE<shy>action +manuE<shy>script +JarkE<shy>ko HieE<shy>taE<shy>nieE<shy>mi + +And again: + +sigE<173>action +manuE<173>script +JarkE<173>ko HieE<173>taE<173>nieE<173>mi + +And one more time: + +sigE<0x00AD>action +manuE<0x00AD>script +JarkE<0x00AD>ko HieE<0x00AD>taE<0x00AD>nieE<0x00AD>mi +### +.SH "Soft Hypen Testing" +.IX Header "Soft Hypen Testing" +sig\%action +manu\%script +Jark\%ko Hie\%ta\%nie\%mi +.PP +And again: +.PP +sig\%action +manu\%script +Jark\%ko Hie\%ta\%nie\%mi +.PP +And one more time: +.PP +sig\%action +manu\%script +Jark\%ko Hie\%ta\%nie\%mi +### + +### +=head1 XE<lt>E<gt> Whitespace + +Blorpy L<B<prok>|blap> X<bivav> wugga chachacha. +### +.SH "X<> Whitespace" +.IX Header "X<> Whitespace" +Blorpy \fBprok\fR wugga chachacha. +.IX Xref "bivav" +### + +### +=head1 Hyphen in SE<lt>E<gt> + +Don't S<transform even-this hyphen>. This "one's-fine!", as well. However, +$-0.13 should have a real hyphen. +### +.SH "Hyphen in S<>" +.IX Header "Hyphen in S<>" +Don't transform\ even-this\ hyphen. This \*(L"one's-fine!\*(R", as well. However, +$\-0.13 should have a real hyphen. +### + +### +=head1 Quote escaping + +Don't escape `this' but do escape C<`this'> (and don't surround it in quotes). +### +.SH "Quote escaping" +.IX Header "Quote escaping" +Don't escape `this' but do escape \f(CW\`this\*(Aq\fR (and don't surround it in quotes). +### + +### +=pod + +E<eth> +### +.PP +\&\*(d- +### + +### +=head1 C<one> and C<two> +### +.ie n .SH """one"" and ""two""" +.el .SH "\f(CWone\fP and \f(CWtwo\fP" +.IX Header "one and two" +### + +### +=pod + +Some text. + +=for man +Some raw nroff. + +=for roff \fBBold text.\fP + +=for html +Stuff that's hidden. + +=for MAN \fIItalic text.\fP + +=for ROFF +.PP +\&A paragraph. + +More text. +### +Some text. +Some raw nroff. +\fBBold text.\fP +\fIItalic text.\fP +.PP +\&A paragraph. +.PP +More text. +### diff --git a/cpan/podlators/t/parselink.t b/cpan/podlators/t/parselink.t new file mode 100644 index 0000000000..c5c2bb660b --- /dev/null +++ b/cpan/podlators/t/parselink.t @@ -0,0 +1,132 @@ +#!/usr/bin/perl -w +# +# parselink.t -- Tests for Pod::ParseLink. +# +# 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. + +# The format of each entry in this array is the L<> text followed by the +# five-element parse returned by parselink. When adding a new test, also +# increment the test count in the BEGIN block below. We don't use any of the +# fancy test modules intentionally for backward compatibility to older +# versions of Perl. +@TESTS = ( + [ 'foo', + undef, 'foo', 'foo', undef, 'pod' ], + + [ 'foo|bar', + 'foo', 'foo', 'bar', undef, 'pod' ], + + [ 'foo/bar', + undef, '"bar" in foo', 'foo', 'bar', 'pod' ], + + [ 'foo/"baz boo"', + undef, '"baz boo" in foo', 'foo', 'baz boo', 'pod' ], + + [ '/bar', + undef, '"bar"', undef, 'bar', 'pod' ], + + [ '/"baz boo"', + undef, '"baz boo"', undef, 'baz boo', 'pod' ], + + [ '/baz boo', + undef, '"baz boo"', undef, 'baz boo', 'pod' ], + + [ 'foo bar/baz boo', + undef, '"baz boo" in foo bar', 'foo bar', 'baz boo', 'pod' ], + + [ 'foo bar / baz boo', + undef, '"baz boo" in foo bar', 'foo bar', 'baz boo', 'pod' ], + + [ "foo\nbar\nbaz\n/\nboo", + undef, '"boo" in foo bar baz', 'foo bar baz', 'boo', 'pod' ], + + [ 'anchor|name/section', + 'anchor', 'anchor', 'name', 'section', 'pod' ], + + [ '"boo var baz"', + undef, '"boo var baz"', undef, 'boo var baz', 'pod' ], + + [ 'bar baz', + undef, '"bar baz"', undef, 'bar baz', 'pod' ], + + [ '"boo bar baz / baz boo"', + undef, '"boo bar baz / baz boo"', undef, 'boo bar baz / baz boo', + 'pod' ], + + [ 'fooZ<>bar', + undef, 'fooZ<>bar', 'fooZ<>bar', undef, 'pod' ], + + [ 'Testing I<italics>|foo/bar', + 'Testing I<italics>', 'Testing I<italics>', 'foo', 'bar', 'pod' ], + + [ 'foo/I<Italic> text', + undef, '"I<Italic> text" in foo', 'foo', 'I<Italic> text', 'pod' ], + + [ 'fooE<verbar>barZ<>/Section C<with> I<B<other> markup', + undef, '"Section C<with> I<B<other> markup" in fooE<verbar>barZ<>', + 'fooE<verbar>barZ<>', 'Section C<with> I<B<other> markup', 'pod' ], + + [ 'Nested L<http://www.perl.org/>|fooE<sol>bar', + 'Nested L<http://www.perl.org/>', 'Nested L<http://www.perl.org/>', + 'fooE<sol>bar', undef, 'pod' ], + + [ 'ls(1)', + undef, 'ls(1)', 'ls(1)', undef, 'man' ], + + [ ' perlfunc(1)/open ', + undef, '"open" in perlfunc(1)', 'perlfunc(1)', 'open', 'man' ], + + [ 'some manual page|perl(1)', + 'some manual page', 'some manual page', 'perl(1)', undef, 'man' ], + + [ 'http://www.perl.org/', + undef, 'http://www.perl.org/', 'http://www.perl.org/', undef, 'url' ], + + [ 'news:yld72axzc8.fsf@windlord.stanford.edu', + undef, 'news:yld72axzc8.fsf@windlord.stanford.edu', + 'news:yld72axzc8.fsf@windlord.stanford.edu', undef, 'url' ] +); + +BEGIN { + chdir 't' if -d 't'; + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..25\n"; +} + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::ParseLink; +$loaded = 1; +print "ok 1\n"; + +# Used for reporting test failures. +my @names = qw(text inferred name section type); + +my $n = 2; +for (@TESTS) { + my @expected = @$_; + my $link = shift @expected; + my @results = parselink ($link); + my $okay = 1; + for (0..4) { + # Make sure to check undef explicitly; we don't want undef to match + # the empty string because they're semantically different. + unless ((!defined ($results[$_]) && !defined ($expected[$_])) + || (defined ($results[$_]) && defined ($expected[$_]) + && $results[$_] eq $expected[$_])) { + print "not ok $n\n" if $okay; + print "# Incorrect $names[$_]:\n"; + print "# expected: $expected[$_]\n"; + print "# seen: $results[$_]\n"; + $okay = 0; + } + } + print "ok $n\n" if $okay; + $n++; +} diff --git a/cpan/podlators/t/pod-parser.t b/cpan/podlators/t/pod-parser.t new file mode 100644 index 0000000000..318a76bc15 --- /dev/null +++ b/cpan/podlators/t/pod-parser.t @@ -0,0 +1,102 @@ +#!/usr/bin/perl -w +# +# pod-parser.t -- Tests for backward compatibility with Pod::Parser. +# +# Copyright 2006, 2008 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..4\n"; +} + +my $loaded; + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::Man; +use Pod::Text; +use strict; + +$loaded = 1; +print "ok 1\n"; + +my $parser = Pod::Man->new or die "Cannot create parser\n"; +open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; +print TMP "Some random B<text>.\n"; +close TMP; +open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; +$parser->parse_from_file ({ -cutting => 0 }, 'tmp.pod', \*OUT); +close OUT; +open (OUT, 'out.tmp') or die "Cannot open out.tmp: $!\n"; +while (<OUT>) { last if /^\.nh/ } +my $output; +{ + local $/; + $output = <OUT>; +} +close OUT; +if ($output eq "Some random \\fBtext\\fR.\n") { + print "ok 2\n"; +} else { + print "not ok 2\n"; + print "Expected\n========\nSome random \\fBtext\\fR.\n\n"; + print "Output\n======\n$output\n"; +} + +$parser = Pod::Text->new or die "Cannot create parser\n"; +open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; +$parser->parse_from_file ({ -cutting => 0 }, 'tmp.pod', \*OUT); +close OUT; +open (OUT, 'out.tmp') or die "Cannot open out.tmp: $!\n"; +{ + local $/; + $output = <OUT>; +} +close OUT; +if ($output eq " Some random text.\n\n") { + print "ok 3\n"; +} else { + print "not ok 3\n"; + print "Expected\n========\n Some random text.\n\n\n"; + print "Output\n======\n$output\n"; +} + +# Test the pod2text function, particularly with only one argument. +open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; +print TMP "=pod\n\nSome random B<text>.\n"; +close TMP; +open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; +open (SAVE, '>&STDOUT') or die "Cannot dup stdout: $!\n"; +open (STDOUT, '>&OUT') or die "Cannot replace stdout: $!\n"; +pod2text ('tmp.pod'); +close OUT; +open (STDOUT, '>&SAVE') or die "Cannot fix stdout: $!\n"; +close SAVE; +open (OUT, 'out.tmp') or die "Cannot open out.tmp: $!\n"; +{ + local $/; + $output = <OUT>; +} +close OUT; +if ($output eq " Some random text.\n\n") { + print "ok 4\n"; +} else { + print "not ok 4\n"; + print "Expected\n========\n Some random text.\n\n\n"; + print "Output\n======\n$output\n"; +} + +unlink ('tmp.pod', 'out.tmp'); +exit 0; diff --git a/cpan/podlators/t/pod-spelling.t b/cpan/podlators/t/pod-spelling.t new file mode 100644 index 0000000000..41c902782e --- /dev/null +++ b/cpan/podlators/t/pod-spelling.t @@ -0,0 +1,76 @@ +#!/usr/bin/perl +# +# t/pod-spelling.t -- Test POD spelling. +# +# Copyright 2008 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. + +# Called to skip all tests with a reason. +sub skip_all { + print "1..0 # Skipped: @_\n"; + exit; +} + +# Skip all spelling tests unless flagged to run maintainer tests. +skip_all "Spelling tests only run for maintainer" + unless $ENV{RRA_MAINTAINER_TESTS}; + +# Make sure we have prerequisites. hunspell is currently not supported due to +# lack of support for contractions. +eval 'use Test::Pod 1.00'; +skip_all "Test::Pod 1.00 required for testing POD" if $@; +eval 'use Pod::Spell'; +skip_all "Pod::Spell required to test POD spelling" if $@; +my @spell; +my %options = (aspell => [ qw(-d en_US --home-dir=./ list) ], + ispell => [ qw(-d american -l -p /dev/null) ]); +SEARCH: for my $program (qw/aspell ispell/) { + for my $dir (split ':', $ENV{PATH}) { + if (-x "$dir/$program") { + @spell = ("$dir/$program", @{ $options{$program} }); + } + last SEARCH if @spell; + } +} +skip_all "aspell or ispell required to test POD spelling" unless @spell; + +# Run the test, one for each POD file. +$| = 1; +my @pod = all_pod_files (); +my $count = scalar @pod; +print "1..$count\n"; +my $n = 1; +for my $pod (@pod) { + my $child = open (CHILD, '-|'); + if (not defined $child) { + die "Cannot fork: $!\n"; + } elsif ($child == 0) { + my $pid = open (SPELL, '|-', @spell) + or die "Cannot run @spell: $!\n"; + open (POD, '<', $pod) or die "Cannot open $pod: $!\n"; + my $parser = Pod::Spell->new; + $parser->parse_from_filehandle (\*POD, \*SPELL); + close POD; + close SPELL; + exit ($? >> 8); + } else { + my @words = <CHILD>; + close CHILD; + if ($? != 0) { + print "ok $n # skip - @spell failed: $?\n"; + } elsif (@words) { + for (@words) { + s/^\s+//; + s/\s+$//; + } + print "not ok $n\n"; + print " - Misspelled words found in $pod\n"; + print " @words\n"; + } else { + print "ok $n\n"; + } + $n++; + } +} diff --git a/cpan/podlators/t/pod.t b/cpan/podlators/t/pod.t new file mode 100644 index 0000000000..ecb37a642c --- /dev/null +++ b/cpan/podlators/t/pod.t @@ -0,0 +1,11 @@ +#!/usr/bin/perl +# +# t/pod.t -- Test POD formatting. + +eval 'use Test::Pod 1.00'; +if ($@) { + print "1..1\n"; + print "ok 1 # skip - Test::Pod 1.00 required for testing POD\n"; + exit; +} +all_pod_files_ok (); diff --git a/cpan/podlators/t/termcap.t b/cpan/podlators/t/termcap.t new file mode 100644 index 0000000000..5ec98288f6 --- /dev/null +++ b/cpan/podlators/t/termcap.t @@ -0,0 +1,85 @@ +#!/usr/bin/perl -w +# +# termcap.t -- Additional specialized tests for Pod::Text::Termcap. +# +# Copyright 2002, 2004, 2006 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..2\n"; +} + +END { + print "not ok 1\n" unless $loaded; +} + +# Hard-code a few values to try to get reproducible results. +$ENV{COLUMNS} = 80; +$ENV{TERM} = 'xterm'; +$ENV{TERMCAP} = 'xterm:co=80:do=^J:md=\E[1m:us=\E[4m:me=\E[m'; + +use Pod::Text::Termcap; + +$loaded = 1; +print "ok 1\n"; + +my $parser = Pod::Text::Termcap->new or die "Cannot create parser\n"; +my $n = 2; +while (<DATA>) { + next until $_ eq "###\n"; + open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; + while (<DATA>) { + last if $_ eq "###\n"; + print TMP $_; + } + close TMP; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + $parser->parse_from_file ('tmp.pod', \*OUT); + close OUT; + open (TMP, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + my $output; + { + local $/; + $output = <TMP>; + } + close TMP; + unlink ('tmp.pod', 'out.tmp'); + my $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; +} + +# Below the marker are bits of POD and corresponding expected output. This is +# used to test specific features or problems with Pod::Text::Termcap. The +# input and output are separated by lines containing only ###. + +__DATA__ + +### +=head1 WRAPPING + +B<I<Do>> I<B<not>> B<I<include>> B<I<formatting codes when>> B<I<wrapping>>. +### +[1mWRAPPING[m + [1m[4mDo[m[m [4m[1mnot[m[m [1m[4minclude[m[m [1m[4mformatting codes when[m[m [1m[4mwrapping[m[m. + +### diff --git a/cpan/podlators/t/text-encoding.t b/cpan/podlators/t/text-encoding.t new file mode 100644 index 0000000000..c803cff1f9 --- /dev/null +++ b/cpan/podlators/t/text-encoding.t @@ -0,0 +1,142 @@ +#!/usr/bin/perl -w +# +# text-encoding.t -- Test Pod::Text with various weird encoding combinations. +# +# Copyright 2002, 2004, 2006, 2007, 2008 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..4\n"; + + # PerlIO encoding support requires Perl 5.8 or later. + if ($] < 5.008) { + my $n; + for $n (1..4) { + print "ok $n # skip -- Perl 5.8 required for UTF-8 support\n"; + } + exit; + } +} + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::Text; + +$loaded = 1; +print "ok 1\n"; + +my $n = 2; +eval { binmode (\*DATA, ':raw') }; +eval { binmode (\*STDOUT, ':raw') }; +while (<DATA>) { + my %opts; + $opts{utf8} = 1 if $n == 4; + my $parser = Pod::Text->new (%opts) or die "Cannot create parser\n"; + next until $_ eq "###\n"; + open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; + eval { binmode (\*TMP, ':raw') }; + while (<DATA>) { + last if $_ eq "###\n"; + print TMP $_; + } + close TMP; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + eval { binmode (\*OUT, ':raw') }; + $parser->parse_from_file ('tmp.pod', \*OUT); + close OUT; + open (TMP, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + eval { binmode (\*TMP, ':raw') }; + my $output; + { + local $/; + $output = <TMP>; + } + close TMP; + unlink ('tmp.pod', 'out.tmp'); + my $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; +} + +# Below the marker are bits of POD and corresponding expected text output. +# This is used to test specific features or problems with Pod::Text. The +# input and output are separated by lines containing only ###. + +__DATA__ + +### +=head1 Test of SE<lt>E<gt> + +This is S<some whitespace>. +### +Test of S<> + This is some whitespace. + +### + +### +=encoding utf-8 + +=head1 I can eat glass + +=over 4 + +=item Esperanto + +Mi povas manÄi vitron, Äi ne damaÄas min. + +=item Braille + +â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â â ¥â â â â â + +=item Hindi + +मà¥à¤ à¤à¤¾à¤à¤ à¤à¤¾ सà¤à¤¤à¤¾ हà¥à¤ à¤à¤° मà¥à¤à¥ à¤à¤¸à¤¸à¥ à¤à¥à¤ à¤à¥à¤ नहà¥à¤ पहà¥à¤à¤à¤¤à¥. + +=back + +See L<http://www.columbia.edu/kermit/utf8.html> +### +I can eat glass + Esperanto + Mi povas manÄi vitron, Äi ne damaÄas min. + + Braille + â â â â â â â â â â â â â â â â â â â â â â â + â â â â â â â â â ¥â â â â â + + Hindi + मà¥à¤ à¤à¤¾à¤à¤ à¤à¤¾ सà¤à¤¤à¤¾ हà¥à¤ à¤à¤° + मà¥à¤à¥ à¤à¤¸à¤¸à¥ à¤à¥à¤ à¤à¥à¤ नहà¥à¤ + पहà¥à¤à¤à¤¤à¥. + + See <http://www.columbia.edu/kermit/utf8.html> + +### + +### +=head1 Beyoncé +### +Beyoncé +### diff --git a/cpan/podlators/t/text-options.t b/cpan/podlators/t/text-options.t new file mode 100644 index 0000000000..8a115d83a5 --- /dev/null +++ b/cpan/podlators/t/text-options.t @@ -0,0 +1,271 @@ +#!/usr/bin/perl -w +# +# text-options.t -- Additional tests for Pod::Text options. +# +# Copyright 2002, 2004, 2006, 2008 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..13\n"; +} + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::Text; + +# Redirect stderr to a file. +sub stderr_save { + open (OLDERR, '>&STDERR') or die "Can't dup STDERR: $!\n"; + open (STDERR, '> out.err') or die "Can't redirect STDERR: $!\n"; +} + +# Restore stderr. +sub stderr_restore { + close STDERR; + open (STDERR, '>&OLDERR') or die "Can't dup STDERR: $!\n"; + close OLDERR; +} + +$loaded = 1; +print "ok 1\n"; + +my $n = 2; +while (<DATA>) { + my %options; + next until $_ eq "###\n"; + while (<DATA>) { + last if $_ eq "###\n"; + my ($option, $value) = split; + $options{$option} = $value; + } + open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; + while (<DATA>) { + last if $_ eq "###\n"; + print TMP $_; + } + close TMP; + my $parser = Pod::Text->new (%options) or die "Cannot create parser\n"; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + stderr_save; + $parser->parse_from_file ('tmp.pod', \*OUT); + stderr_restore; + close OUT; + open (TMP, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + my $output; + { + local $/; + $output = <TMP>; + } + close TMP; + 1 while unlink ('tmp.pod', 'out.tmp'); + my $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; + open (ERR, 'out.err') or die "Cannot open out.err: $!\n"; + my $errors; + { + local $/; + $errors = <ERR>; + } + close ERR; + unlink ('out.err'); + $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($errors eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected errors:\n ${expected}Errors:\n $errors"; + } + $n++; +} + +# Below the marker are bits of POD and corresponding expected text output. +# This is used to test specific features or problems with Pod::Text. The +# input and output are separated by lines containing only ###. + +__DATA__ + +### +alt 1 +### +=head1 SAMPLE + +=over 4 + +=item F + +Paragraph. + +=item Bar + +=item B + +Paragraph. + +=item Longer + +Paragraph. + +=back + +### + +==== SAMPLE ==== + +: F Paragraph. + +: Bar +: B Paragraph. + +: Longer + Paragraph. + +### +### + +### +margin 4 +### +=head1 SAMPLE + +This is some body text that is long enough to be a paragraph that wraps, +thereby testing margins with wrapped paragraphs. + + This is some verbatim text. + +=over 6 + +=item Test + +This is a test of an indented paragraph. + +This is another indented paragraph. + +=back +### + SAMPLE + This is some body text that is long enough to be a paragraph that + wraps, thereby testing margins with wrapped paragraphs. + + This is some verbatim text. + + Test This is a test of an indented paragraph. + + This is another indented paragraph. + +### +### + +### +code 1 +### +This is some random text. +This is more random text. + +This is some random text. +This is more random text. + +=head1 SAMPLE + +This is POD. + +=cut + +This is more random text. +### +This is some random text. +This is more random text. + +This is some random text. +This is more random text. + +SAMPLE + This is POD. + + +This is more random text. +### +### + +### +sentence 1 +### +=head1 EXAMPLE + +Whitespace around C<< this. >> must be ignored per perlpodspec. >> +needs to eat all of the space in front of it. + +=cut +### +EXAMPLE + Whitespace around "this." must be ignored per perlpodspec. >> needs to + eat all of the space in front of it. + +### +### + +### +### +=over 4 + +=item Foo + +Bar. + +=head1 NEXT +### + Foo Bar. + +NEXT +POD ERRORS + Hey! The above document had some coding errors, which are explained + below: + + Around line 7: + You forgot a '=back' before '=head1' + +### +### + +### +stderr 1 +### +=over 4 + +=item Foo + +Bar. + +=head1 NEXT +### + Foo Bar. + +NEXT +### +tmp.pod around line 7: You forgot a '=back' before '=head1' +### diff --git a/cpan/podlators/t/text-utf8.t b/cpan/podlators/t/text-utf8.t new file mode 100644 index 0000000000..806947827e --- /dev/null +++ b/cpan/podlators/t/text-utf8.t @@ -0,0 +1,129 @@ +#!/usr/bin/perl -w +# +# text-utf8.t -- Test Pod::Text with UTF-8 input. +# +# Copyright 2002, 2004, 2006, 2007, 2008 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..3\n"; + + # UTF-8 support requires Perl 5.8 or later. + if ($] < 5.008) { + my $n; + for $n (1..3) { + print "ok $n # skip -- Perl 5.8 required for UTF-8 support\n"; + } + exit; + } +} + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::Text; + +$loaded = 1; +print "ok 1\n"; + +my $parser = Pod::Text->new or die "Cannot create parser\n"; +my $n = 2; +eval { binmode (\*DATA, ':encoding(utf-8)') }; +eval { binmode (\*STDOUT, ':encoding(utf-8)') }; +while (<DATA>) { + next until $_ eq "###\n"; + open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; + eval { binmode (\*TMP, ':encoding(utf-8)') }; + print TMP "=encoding UTF-8\n\n"; + while (<DATA>) { + last if $_ eq "###\n"; + print TMP $_; + } + close TMP; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + $parser->parse_from_file ('tmp.pod', \*OUT); + close OUT; + open (TMP, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + eval { binmode (\*TMP, ':encoding(utf-8)') }; + my $output; + { + local $/; + $output = <TMP>; + } + close TMP; + unlink ('tmp.pod', 'out.tmp'); + my $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; +} + +# Below the marker are bits of POD and corresponding expected text output. +# This is used to test specific features or problems with Pod::Text. The +# input and output are separated by lines containing only ###. + +__DATA__ + +### +=head1 Test of SE<lt>E<gt> + +This is S<some whitespace>. +### +Test of S<> + This is some whitespace. + +### + +### +=head1 I can eat glass + +=over 4 + +=item Esperanto + +Mi povas manĝi vitron, ĝi ne damaĝas min. + +=item Braille + +⠊⠀⠉⠁⠝⠀⠑⠁⠞⠀⠛⠇⠁⠎⠎⠀⠁⠝⠙⠀⠊⠞⠀⠙⠕⠑⠎⠝⠞⠀⠓⠥⠗⠞⠀⠍⠑ + +=item Hindi + +मैं काँच खा सकता हूँ और मुझे उससे कोई चोट नहीं पहुंचती. + +=back + +See L<http://www.columbia.edu/kermit/utf8.html> +### +I can eat glass + Esperanto + Mi povas manĝi vitron, ĝi ne damaĝas min. + + Braille + ⠊⠀⠉⠁⠝⠀⠑⠁⠞⠀⠛⠇⠁⠎⠎⠀⠁⠝⠙⠀⠊⠞⠀⠙⠕⠑⠎⠝⠞⠀⠓⠥⠗⠞⠀⠍⠑ + + Hindi + मैं काँच खा सकता हूँ और मुझे उससे कोई चोट नहीं पहुंचती. + + See <http://www.columbia.edu/kermit/utf8.html> + +### diff --git a/cpan/podlators/t/text.t b/cpan/podlators/t/text.t new file mode 100644 index 0000000000..c96acba63d --- /dev/null +++ b/cpan/podlators/t/text.t @@ -0,0 +1,147 @@ +#!/usr/bin/perl -w +# +# text.t -- Additional specialized tests for Pod::Text. +# +# Copyright 2002, 2004, 2006, 2007, 2008, 2009 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. + +BEGIN { + chdir 't' if -d 't'; + if ($ENV{PERL_CORE}) { + @INC = '../lib'; + } else { + unshift (@INC, '../blib/lib'); + } + unshift (@INC, '../blib/lib'); + $| = 1; + print "1..6\n"; +} + +END { + print "not ok 1\n" unless $loaded; +} + +use Pod::Text; +use Pod::Simple; + +$loaded = 1; +print "ok 1\n"; + +my $parser = Pod::Text->new or die "Cannot create parser\n"; +my $n = 2; +while (<DATA>) { + next until $_ eq "###\n"; + open (TMP, '> tmp.pod') or die "Cannot create tmp.pod: $!\n"; + while (<DATA>) { + last if $_ eq "###\n"; + print TMP $_; + } + close TMP; + open (OUT, '> out.tmp') or die "Cannot create out.tmp: $!\n"; + $parser->parse_from_file ('tmp.pod', \*OUT); + close OUT; + open (TMP, 'out.tmp') or die "Cannot open out.tmp: $!\n"; + my $output; + { + local $/; + $output = <TMP>; + } + close TMP; + unlink ('tmp.pod', 'out.tmp'); + my $expected = ''; + while (<DATA>) { + last if $_ eq "###\n"; + $expected .= $_; + } + if ($output eq $expected) { + print "ok $n\n"; + } elsif ($n == 4 && $Pod::Simple::VERSION < 3.06) { + print "ok $n # skip Pod::Simple S<> parsing bug\n"; + } else { + print "not ok $n\n"; + print "Expected\n========\n$expected\nOutput\n======\n$output\n"; + } + $n++; +} + +# Below the marker are bits of POD and corresponding expected text output. +# This is used to test specific features or problems with Pod::Text. The +# input and output are separated by lines containing only ###. + +__DATA__ + +### +=head1 PERIODS + +This C<.> should be quoted. +### +PERIODS + This "." should be quoted. + +### + +### +=head1 CE<lt>E<gt> WITH SPACES + +What does C<< this. >> end up looking like? +### +C<> WITH SPACES + What does "this." end up looking like? + +### + +### +=head1 Test of SE<lt>E<gt> + +This is some S< > whitespace. +### +Test of S<> + This is some whitespace. + +### + +### +=head1 Test of =for + +=for comment +This won't be seen. + +Yes. + +=for text +This should be seen. + +=for TEXT As should this. + +=for man +But this shouldn't. + +Some more text. +### +Test of =for + Yes. + +This should be seen. +As should this. + Some more text. + +### + +### +=pod + +text + + line1 + + line3 +### + text + + line1 + + line3 + +### |