xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/Pod/Text.pm (revision 0:68f95e015346)
1*0Sstevel@tonic-gate# Pod::Text -- Convert POD data to formatted ASCII text.
2*0Sstevel@tonic-gate# $Id: Text.pm,v 2.21 2002/08/04 03:34:58 eagle Exp $
3*0Sstevel@tonic-gate#
4*0Sstevel@tonic-gate# Copyright 1999, 2000, 2001, 2002 by Russ Allbery <rra@stanford.edu>
5*0Sstevel@tonic-gate#
6*0Sstevel@tonic-gate# This program is free software; you may redistribute it and/or modify it
7*0Sstevel@tonic-gate# under the same terms as Perl itself.
8*0Sstevel@tonic-gate#
9*0Sstevel@tonic-gate# This module converts POD to formatted text.  It replaces the old Pod::Text
10*0Sstevel@tonic-gate# module that came with versions of Perl prior to 5.6.0 and attempts to match
11*0Sstevel@tonic-gate# its output except for some specific circumstances where other decisions
12*0Sstevel@tonic-gate# seemed to produce better output.  It uses Pod::Parser and is designed to be
13*0Sstevel@tonic-gate# very easy to subclass.
14*0Sstevel@tonic-gate#
15*0Sstevel@tonic-gate# Perl core hackers, please note that this module is also separately
16*0Sstevel@tonic-gate# maintained outside of the Perl core as part of the podlators.  Please send
17*0Sstevel@tonic-gate# me any patches at the address above in addition to sending them to the
18*0Sstevel@tonic-gate# standard Perl mailing lists.
19*0Sstevel@tonic-gate
20*0Sstevel@tonic-gate##############################################################################
21*0Sstevel@tonic-gate# Modules and declarations
22*0Sstevel@tonic-gate##############################################################################
23*0Sstevel@tonic-gate
24*0Sstevel@tonic-gatepackage Pod::Text;
25*0Sstevel@tonic-gate
26*0Sstevel@tonic-gaterequire 5.004;
27*0Sstevel@tonic-gate
28*0Sstevel@tonic-gateuse Carp qw(carp croak);
29*0Sstevel@tonic-gateuse Exporter ();
30*0Sstevel@tonic-gateuse Pod::ParseLink qw(parselink);
31*0Sstevel@tonic-gateuse Pod::Select ();
32*0Sstevel@tonic-gate
33*0Sstevel@tonic-gateuse strict;
34*0Sstevel@tonic-gateuse vars qw(@ISA @EXPORT %ESCAPES $VERSION);
35*0Sstevel@tonic-gate
36*0Sstevel@tonic-gate# We inherit from Pod::Select instead of Pod::Parser so that we can be used by
37*0Sstevel@tonic-gate# Pod::Usage.
38*0Sstevel@tonic-gate@ISA = qw(Pod::Select Exporter);
39*0Sstevel@tonic-gate
40*0Sstevel@tonic-gate# We have to export pod2text for backward compatibility.
41*0Sstevel@tonic-gate@EXPORT = qw(pod2text);
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gate# Don't use the CVS revision as the version, since this module is also in Perl
44*0Sstevel@tonic-gate# core and too many things could munge CVS magic revision strings.  This
45*0Sstevel@tonic-gate# number should ideally be the same as the CVS revision in podlators, however.
46*0Sstevel@tonic-gate$VERSION = 2.21;
47*0Sstevel@tonic-gate
48*0Sstevel@tonic-gate
49*0Sstevel@tonic-gate##############################################################################
50*0Sstevel@tonic-gate# Table of supported E<> escapes
51*0Sstevel@tonic-gate##############################################################################
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gate# This table is taken near verbatim from Pod::PlainText in Pod::Parser, which
54*0Sstevel@tonic-gate# got it near verbatim from the original Pod::Text.  It is therefore credited
55*0Sstevel@tonic-gate# to Tom Christiansen, and I'm glad I didn't have to write it.  :)  "iexcl" to
56*0Sstevel@tonic-gate# "divide" added by Tim Jenness.
57*0Sstevel@tonic-gate%ESCAPES = (
58*0Sstevel@tonic-gate    'amp'       =>    '&',      # ampersand
59*0Sstevel@tonic-gate    'apos'      =>    "'",      # apostrophe
60*0Sstevel@tonic-gate    'lt'        =>    '<',      # left chevron, less-than
61*0Sstevel@tonic-gate    'gt'        =>    '>',      # right chevron, greater-than
62*0Sstevel@tonic-gate    'quot'      =>    '"',      # double quote
63*0Sstevel@tonic-gate    'sol'       =>    '/',      # solidus (forward slash)
64*0Sstevel@tonic-gate    'verbar'    =>    '|',      # vertical bar
65*0Sstevel@tonic-gate
66*0Sstevel@tonic-gate    "Aacute"    =>    "\xC1",   # capital A, acute accent
67*0Sstevel@tonic-gate    "aacute"    =>    "\xE1",   # small a, acute accent
68*0Sstevel@tonic-gate    "Acirc"     =>    "\xC2",   # capital A, circumflex accent
69*0Sstevel@tonic-gate    "acirc"     =>    "\xE2",   # small a, circumflex accent
70*0Sstevel@tonic-gate    "AElig"     =>    "\xC6",   # capital AE diphthong (ligature)
71*0Sstevel@tonic-gate    "aelig"     =>    "\xE6",   # small ae diphthong (ligature)
72*0Sstevel@tonic-gate    "Agrave"    =>    "\xC0",   # capital A, grave accent
73*0Sstevel@tonic-gate    "agrave"    =>    "\xE0",   # small a, grave accent
74*0Sstevel@tonic-gate    "Aring"     =>    "\xC5",   # capital A, ring
75*0Sstevel@tonic-gate    "aring"     =>    "\xE5",   # small a, ring
76*0Sstevel@tonic-gate    "Atilde"    =>    "\xC3",   # capital A, tilde
77*0Sstevel@tonic-gate    "atilde"    =>    "\xE3",   # small a, tilde
78*0Sstevel@tonic-gate    "Auml"      =>    "\xC4",   # capital A, dieresis or umlaut mark
79*0Sstevel@tonic-gate    "auml"      =>    "\xE4",   # small a, dieresis or umlaut mark
80*0Sstevel@tonic-gate    "Ccedil"    =>    "\xC7",   # capital C, cedilla
81*0Sstevel@tonic-gate    "ccedil"    =>    "\xE7",   # small c, cedilla
82*0Sstevel@tonic-gate    "Eacute"    =>    "\xC9",   # capital E, acute accent
83*0Sstevel@tonic-gate    "eacute"    =>    "\xE9",   # small e, acute accent
84*0Sstevel@tonic-gate    "Ecirc"     =>    "\xCA",   # capital E, circumflex accent
85*0Sstevel@tonic-gate    "ecirc"     =>    "\xEA",   # small e, circumflex accent
86*0Sstevel@tonic-gate    "Egrave"    =>    "\xC8",   # capital E, grave accent
87*0Sstevel@tonic-gate    "egrave"    =>    "\xE8",   # small e, grave accent
88*0Sstevel@tonic-gate    "ETH"       =>    "\xD0",   # capital Eth, Icelandic
89*0Sstevel@tonic-gate    "eth"       =>    "\xF0",   # small eth, Icelandic
90*0Sstevel@tonic-gate    "Euml"      =>    "\xCB",   # capital E, dieresis or umlaut mark
91*0Sstevel@tonic-gate    "euml"      =>    "\xEB",   # small e, dieresis or umlaut mark
92*0Sstevel@tonic-gate    "Iacute"    =>    "\xCD",   # capital I, acute accent
93*0Sstevel@tonic-gate    "iacute"    =>    "\xED",   # small i, acute accent
94*0Sstevel@tonic-gate    "Icirc"     =>    "\xCE",   # capital I, circumflex accent
95*0Sstevel@tonic-gate    "icirc"     =>    "\xEE",   # small i, circumflex accent
96*0Sstevel@tonic-gate    "Igrave"    =>    "\xCC",   # capital I, grave accent
97*0Sstevel@tonic-gate    "igrave"    =>    "\xEC",   # small i, grave accent
98*0Sstevel@tonic-gate    "Iuml"      =>    "\xCF",   # capital I, dieresis or umlaut mark
99*0Sstevel@tonic-gate    "iuml"      =>    "\xEF",   # small i, dieresis or umlaut mark
100*0Sstevel@tonic-gate    "Ntilde"    =>    "\xD1",   # capital N, tilde
101*0Sstevel@tonic-gate    "ntilde"    =>    "\xF1",   # small n, tilde
102*0Sstevel@tonic-gate    "Oacute"    =>    "\xD3",   # capital O, acute accent
103*0Sstevel@tonic-gate    "oacute"    =>    "\xF3",   # small o, acute accent
104*0Sstevel@tonic-gate    "Ocirc"     =>    "\xD4",   # capital O, circumflex accent
105*0Sstevel@tonic-gate    "ocirc"     =>    "\xF4",   # small o, circumflex accent
106*0Sstevel@tonic-gate    "Ograve"    =>    "\xD2",   # capital O, grave accent
107*0Sstevel@tonic-gate    "ograve"    =>    "\xF2",   # small o, grave accent
108*0Sstevel@tonic-gate    "Oslash"    =>    "\xD8",   # capital O, slash
109*0Sstevel@tonic-gate    "oslash"    =>    "\xF8",   # small o, slash
110*0Sstevel@tonic-gate    "Otilde"    =>    "\xD5",   # capital O, tilde
111*0Sstevel@tonic-gate    "otilde"    =>    "\xF5",   # small o, tilde
112*0Sstevel@tonic-gate    "Ouml"      =>    "\xD6",   # capital O, dieresis or umlaut mark
113*0Sstevel@tonic-gate    "ouml"      =>    "\xF6",   # small o, dieresis or umlaut mark
114*0Sstevel@tonic-gate    "szlig"     =>    "\xDF",   # small sharp s, German (sz ligature)
115*0Sstevel@tonic-gate    "THORN"     =>    "\xDE",   # capital THORN, Icelandic
116*0Sstevel@tonic-gate    "thorn"     =>    "\xFE",   # small thorn, Icelandic
117*0Sstevel@tonic-gate    "Uacute"    =>    "\xDA",   # capital U, acute accent
118*0Sstevel@tonic-gate    "uacute"    =>    "\xFA",   # small u, acute accent
119*0Sstevel@tonic-gate    "Ucirc"     =>    "\xDB",   # capital U, circumflex accent
120*0Sstevel@tonic-gate    "ucirc"     =>    "\xFB",   # small u, circumflex accent
121*0Sstevel@tonic-gate    "Ugrave"    =>    "\xD9",   # capital U, grave accent
122*0Sstevel@tonic-gate    "ugrave"    =>    "\xF9",   # small u, grave accent
123*0Sstevel@tonic-gate    "Uuml"      =>    "\xDC",   # capital U, dieresis or umlaut mark
124*0Sstevel@tonic-gate    "uuml"      =>    "\xFC",   # small u, dieresis or umlaut mark
125*0Sstevel@tonic-gate    "Yacute"    =>    "\xDD",   # capital Y, acute accent
126*0Sstevel@tonic-gate    "yacute"    =>    "\xFD",   # small y, acute accent
127*0Sstevel@tonic-gate    "yuml"      =>    "\xFF",   # small y, dieresis or umlaut mark
128*0Sstevel@tonic-gate
129*0Sstevel@tonic-gate    "laquo"     =>    "\xAB",   # left pointing double angle quotation mark
130*0Sstevel@tonic-gate    "lchevron"  =>    "\xAB",   #  synonym (backwards compatibility)
131*0Sstevel@tonic-gate    "raquo"     =>    "\xBB",   # right pointing double angle quotation mark
132*0Sstevel@tonic-gate    "rchevron"  =>    "\xBB",   #  synonym (backwards compatibility)
133*0Sstevel@tonic-gate
134*0Sstevel@tonic-gate    "iexcl"     =>    "\xA1",   # inverted exclamation mark
135*0Sstevel@tonic-gate    "cent"      =>    "\xA2",   # cent sign
136*0Sstevel@tonic-gate    "pound"     =>    "\xA3",   # (UK) pound sign
137*0Sstevel@tonic-gate    "curren"    =>    "\xA4",   # currency sign
138*0Sstevel@tonic-gate    "yen"       =>    "\xA5",   # yen sign
139*0Sstevel@tonic-gate    "brvbar"    =>    "\xA6",   # broken vertical bar
140*0Sstevel@tonic-gate    "sect"      =>    "\xA7",   # section sign
141*0Sstevel@tonic-gate    "uml"       =>    "\xA8",   # diaresis
142*0Sstevel@tonic-gate    "copy"      =>    "\xA9",   # Copyright symbol
143*0Sstevel@tonic-gate    "ordf"      =>    "\xAA",   # feminine ordinal indicator
144*0Sstevel@tonic-gate    "not"       =>    "\xAC",   # not sign
145*0Sstevel@tonic-gate    "shy"       =>    '',       # soft (discretionary) hyphen
146*0Sstevel@tonic-gate    "reg"       =>    "\xAE",   # registered trademark
147*0Sstevel@tonic-gate    "macr"      =>    "\xAF",   # macron, overline
148*0Sstevel@tonic-gate    "deg"       =>    "\xB0",   # degree sign
149*0Sstevel@tonic-gate    "plusmn"    =>    "\xB1",   # plus-minus sign
150*0Sstevel@tonic-gate    "sup2"      =>    "\xB2",   # superscript 2
151*0Sstevel@tonic-gate    "sup3"      =>    "\xB3",   # superscript 3
152*0Sstevel@tonic-gate    "acute"     =>    "\xB4",   # acute accent
153*0Sstevel@tonic-gate    "micro"     =>    "\xB5",   # micro sign
154*0Sstevel@tonic-gate    "para"      =>    "\xB6",   # pilcrow sign = paragraph sign
155*0Sstevel@tonic-gate    "middot"    =>    "\xB7",   # middle dot = Georgian comma
156*0Sstevel@tonic-gate    "cedil"     =>    "\xB8",   # cedilla
157*0Sstevel@tonic-gate    "sup1"      =>    "\xB9",   # superscript 1
158*0Sstevel@tonic-gate    "ordm"      =>    "\xBA",   # masculine ordinal indicator
159*0Sstevel@tonic-gate    "frac14"    =>    "\xBC",   # vulgar fraction one quarter
160*0Sstevel@tonic-gate    "frac12"    =>    "\xBD",   # vulgar fraction one half
161*0Sstevel@tonic-gate    "frac34"    =>    "\xBE",   # vulgar fraction three quarters
162*0Sstevel@tonic-gate    "iquest"    =>    "\xBF",   # inverted question mark
163*0Sstevel@tonic-gate    "times"     =>    "\xD7",   # multiplication sign
164*0Sstevel@tonic-gate    "divide"    =>    "\xF7",   # division sign
165*0Sstevel@tonic-gate
166*0Sstevel@tonic-gate    "nbsp"      =>    "\x01",   # non-breaking space
167*0Sstevel@tonic-gate);
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate
170*0Sstevel@tonic-gate##############################################################################
171*0Sstevel@tonic-gate# Initialization
172*0Sstevel@tonic-gate##############################################################################
173*0Sstevel@tonic-gate
174*0Sstevel@tonic-gate# Initialize the object.  Must be sure to call our parent initializer.
175*0Sstevel@tonic-gatesub initialize {
176*0Sstevel@tonic-gate    my $self = shift;
177*0Sstevel@tonic-gate
178*0Sstevel@tonic-gate    $$self{alt}      = 0  unless defined $$self{alt};
179*0Sstevel@tonic-gate    $$self{indent}   = 4  unless defined $$self{indent};
180*0Sstevel@tonic-gate    $$self{margin}   = 0  unless defined $$self{margin};
181*0Sstevel@tonic-gate    $$self{loose}    = 0  unless defined $$self{loose};
182*0Sstevel@tonic-gate    $$self{sentence} = 0  unless defined $$self{sentence};
183*0Sstevel@tonic-gate    $$self{width}    = 76 unless defined $$self{width};
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gate    # Figure out what quotes we'll be using for C<> text.
186*0Sstevel@tonic-gate    $$self{quotes} ||= '"';
187*0Sstevel@tonic-gate    if ($$self{quotes} eq 'none') {
188*0Sstevel@tonic-gate        $$self{LQUOTE} = $$self{RQUOTE} = '';
189*0Sstevel@tonic-gate    } elsif (length ($$self{quotes}) == 1) {
190*0Sstevel@tonic-gate        $$self{LQUOTE} = $$self{RQUOTE} = $$self{quotes};
191*0Sstevel@tonic-gate    } elsif ($$self{quotes} =~ /^(.)(.)$/
192*0Sstevel@tonic-gate             || $$self{quotes} =~ /^(..)(..)$/) {
193*0Sstevel@tonic-gate        $$self{LQUOTE} = $1;
194*0Sstevel@tonic-gate        $$self{RQUOTE} = $2;
195*0Sstevel@tonic-gate    } else {
196*0Sstevel@tonic-gate        croak qq(Invalid quote specification "$$self{quotes}");
197*0Sstevel@tonic-gate    }
198*0Sstevel@tonic-gate
199*0Sstevel@tonic-gate    # Stack of indentations.
200*0Sstevel@tonic-gate    $$self{INDENTS}  = [];
201*0Sstevel@tonic-gate
202*0Sstevel@tonic-gate    # Current left margin.
203*0Sstevel@tonic-gate    $$self{MARGIN} = $$self{indent} + $$self{margin};
204*0Sstevel@tonic-gate
205*0Sstevel@tonic-gate    $self->SUPER::initialize;
206*0Sstevel@tonic-gate
207*0Sstevel@tonic-gate    # Tell Pod::Parser that we want the non-POD stuff too if code was set.
208*0Sstevel@tonic-gate    $self->parseopts ('-want_nonPODs' => 1) if $$self{code};
209*0Sstevel@tonic-gate}
210*0Sstevel@tonic-gate
211*0Sstevel@tonic-gate
212*0Sstevel@tonic-gate##############################################################################
213*0Sstevel@tonic-gate# Core overrides
214*0Sstevel@tonic-gate##############################################################################
215*0Sstevel@tonic-gate
216*0Sstevel@tonic-gate# Called for each command paragraph.  Gets the command, the associated
217*0Sstevel@tonic-gate# paragraph, the line number, and a Pod::Paragraph object.  Just dispatches
218*0Sstevel@tonic-gate# the command to a method named the same as the command.  =cut is handled
219*0Sstevel@tonic-gate# internally by Pod::Parser.
220*0Sstevel@tonic-gatesub command {
221*0Sstevel@tonic-gate    my $self = shift;
222*0Sstevel@tonic-gate    my $command = shift;
223*0Sstevel@tonic-gate    return if $command eq 'pod';
224*0Sstevel@tonic-gate    return if ($$self{EXCLUDE} && $command ne 'end');
225*0Sstevel@tonic-gate    if ($self->can ('cmd_' . $command)) {
226*0Sstevel@tonic-gate        $command = 'cmd_' . $command;
227*0Sstevel@tonic-gate        $self->$command (@_);
228*0Sstevel@tonic-gate    } else {
229*0Sstevel@tonic-gate        my ($text, $line, $paragraph) = @_;
230*0Sstevel@tonic-gate        my $file;
231*0Sstevel@tonic-gate        ($file, $line) = $paragraph->file_line;
232*0Sstevel@tonic-gate        $text =~ s/\n+\z//;
233*0Sstevel@tonic-gate        $text = " $text" if ($text =~ /^\S/);
234*0Sstevel@tonic-gate        warn qq($file:$line: Unknown command paragraph: =$command$text\n);
235*0Sstevel@tonic-gate        return;
236*0Sstevel@tonic-gate    }
237*0Sstevel@tonic-gate}
238*0Sstevel@tonic-gate
239*0Sstevel@tonic-gate# Called for a verbatim paragraph.  Gets the paragraph, the line number, and a
240*0Sstevel@tonic-gate# Pod::Paragraph object.  Just output it verbatim, but with tabs converted to
241*0Sstevel@tonic-gate# spaces.
242*0Sstevel@tonic-gatesub verbatim {
243*0Sstevel@tonic-gate    my $self = shift;
244*0Sstevel@tonic-gate    return if $$self{EXCLUDE};
245*0Sstevel@tonic-gate    $self->item if defined $$self{ITEM};
246*0Sstevel@tonic-gate    local $_ = shift;
247*0Sstevel@tonic-gate    return if /^\s*$/;
248*0Sstevel@tonic-gate    s/^(\s*\S+)/(' ' x $$self{MARGIN}) . $1/gme;
249*0Sstevel@tonic-gate    $self->output ($_);
250*0Sstevel@tonic-gate}
251*0Sstevel@tonic-gate
252*0Sstevel@tonic-gate# Called for a regular text block.  Gets the paragraph, the line number, and a
253*0Sstevel@tonic-gate# Pod::Paragraph object.  Perform interpolation and output the results.
254*0Sstevel@tonic-gatesub textblock {
255*0Sstevel@tonic-gate    my $self = shift;
256*0Sstevel@tonic-gate    return if $$self{EXCLUDE};
257*0Sstevel@tonic-gate    $self->output ($_[0]), return if $$self{VERBATIM};
258*0Sstevel@tonic-gate    local $_ = shift;
259*0Sstevel@tonic-gate    my $line = shift;
260*0Sstevel@tonic-gate
261*0Sstevel@tonic-gate    # Interpolate and output the paragraph.
262*0Sstevel@tonic-gate    $_ = $self->interpolate ($_, $line);
263*0Sstevel@tonic-gate    s/\s+$/\n/;
264*0Sstevel@tonic-gate    if (defined $$self{ITEM}) {
265*0Sstevel@tonic-gate        $self->item ($_ . "\n");
266*0Sstevel@tonic-gate    } else {
267*0Sstevel@tonic-gate        $self->output ($self->reformat ($_ . "\n"));
268*0Sstevel@tonic-gate    }
269*0Sstevel@tonic-gate}
270*0Sstevel@tonic-gate
271*0Sstevel@tonic-gate# Called for a formatting code.  Gets the command, argument, and a
272*0Sstevel@tonic-gate# Pod::InteriorSequence object and is expected to return the resulting text.
273*0Sstevel@tonic-gate# Calls methods for code, bold, italic, file, and link to handle those types
274*0Sstevel@tonic-gate# of codes, and handles S<>, E<>, X<>, and Z<> directly.
275*0Sstevel@tonic-gatesub interior_sequence {
276*0Sstevel@tonic-gate    local $_;
277*0Sstevel@tonic-gate    my ($self, $command, $seq);
278*0Sstevel@tonic-gate    ($self, $command, $_, $seq) = @_;
279*0Sstevel@tonic-gate
280*0Sstevel@tonic-gate    # We have to defer processing of the inside of an L<> formatting code.  If
281*0Sstevel@tonic-gate    # this code is nested inside an L<> code, return the literal raw text of
282*0Sstevel@tonic-gate    # it.
283*0Sstevel@tonic-gate    my $parent = $seq->nested;
284*0Sstevel@tonic-gate    while (defined $parent) {
285*0Sstevel@tonic-gate        return $seq->raw_text if ($parent->cmd_name eq 'L');
286*0Sstevel@tonic-gate        $parent = $parent->nested;
287*0Sstevel@tonic-gate    }
288*0Sstevel@tonic-gate
289*0Sstevel@tonic-gate    # Index entries are ignored in plain text.
290*0Sstevel@tonic-gate    return '' if ($command eq 'X' || $command eq 'Z');
291*0Sstevel@tonic-gate
292*0Sstevel@tonic-gate    # Expand escapes into the actual character now, warning if invalid.
293*0Sstevel@tonic-gate    if ($command eq 'E') {
294*0Sstevel@tonic-gate        if (/^\d+$/) {
295*0Sstevel@tonic-gate            return chr;
296*0Sstevel@tonic-gate        } else {
297*0Sstevel@tonic-gate            return $ESCAPES{$_} if defined $ESCAPES{$_};
298*0Sstevel@tonic-gate            my ($file, $line) = $seq->file_line;
299*0Sstevel@tonic-gate            warn "$file:$line: Unknown escape: E<$_>\n";
300*0Sstevel@tonic-gate            return "E<$_>";
301*0Sstevel@tonic-gate        }
302*0Sstevel@tonic-gate    }
303*0Sstevel@tonic-gate
304*0Sstevel@tonic-gate    # For all the other formatting codes, empty content produces no output.
305*0Sstevel@tonic-gate    return if $_ eq '';
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gate    # For S<>, compress all internal whitespace and then map spaces to \01.
308*0Sstevel@tonic-gate    # When we output the text, we'll map this back.
309*0Sstevel@tonic-gate    if ($command eq 'S') {
310*0Sstevel@tonic-gate        s/\s+/ /g;
311*0Sstevel@tonic-gate        tr/ /\01/;
312*0Sstevel@tonic-gate        return $_;
313*0Sstevel@tonic-gate    }
314*0Sstevel@tonic-gate
315*0Sstevel@tonic-gate    # Anything else needs to get dispatched to another method.
316*0Sstevel@tonic-gate    if    ($command eq 'B') { return $self->seq_b ($_) }
317*0Sstevel@tonic-gate    elsif ($command eq 'C') { return $self->seq_c ($_) }
318*0Sstevel@tonic-gate    elsif ($command eq 'F') { return $self->seq_f ($_) }
319*0Sstevel@tonic-gate    elsif ($command eq 'I') { return $self->seq_i ($_) }
320*0Sstevel@tonic-gate    elsif ($command eq 'L') { return $self->seq_l ($_, $seq) }
321*0Sstevel@tonic-gate    else {
322*0Sstevel@tonic-gate        my ($file, $line) = $seq->file_line;
323*0Sstevel@tonic-gate        warn "$file:$line: Unknown formatting code: $command<$_>\n";
324*0Sstevel@tonic-gate    }
325*0Sstevel@tonic-gate}
326*0Sstevel@tonic-gate
327*0Sstevel@tonic-gate# Called for each paragraph that's actually part of the POD.  We take
328*0Sstevel@tonic-gate# advantage of this opportunity to untabify the input.  Also, if given the
329*0Sstevel@tonic-gate# code option, we may see paragraphs that aren't part of the POD and need to
330*0Sstevel@tonic-gate# output them directly.
331*0Sstevel@tonic-gatesub preprocess_paragraph {
332*0Sstevel@tonic-gate    my $self = shift;
333*0Sstevel@tonic-gate    local $_ = shift;
334*0Sstevel@tonic-gate    1 while s/^(.*?)(\t+)/$1 . ' ' x (length ($2) * 8 - length ($1) % 8)/me;
335*0Sstevel@tonic-gate    $self->output_code ($_) if $self->cutting;
336*0Sstevel@tonic-gate    $_;
337*0Sstevel@tonic-gate}
338*0Sstevel@tonic-gate
339*0Sstevel@tonic-gate
340*0Sstevel@tonic-gate##############################################################################
341*0Sstevel@tonic-gate# Command paragraphs
342*0Sstevel@tonic-gate##############################################################################
343*0Sstevel@tonic-gate
344*0Sstevel@tonic-gate# All command paragraphs take the paragraph and the line number.
345*0Sstevel@tonic-gate
346*0Sstevel@tonic-gate# First level heading.
347*0Sstevel@tonic-gatesub cmd_head1 {
348*0Sstevel@tonic-gate    my ($self, $text, $line) = @_;
349*0Sstevel@tonic-gate    $self->heading ($text, $line, 0, '====');
350*0Sstevel@tonic-gate}
351*0Sstevel@tonic-gate
352*0Sstevel@tonic-gate# Second level heading.
353*0Sstevel@tonic-gatesub cmd_head2 {
354*0Sstevel@tonic-gate    my ($self, $text, $line) = @_;
355*0Sstevel@tonic-gate    $self->heading ($text, $line, $$self{indent} / 2, '==  ');
356*0Sstevel@tonic-gate}
357*0Sstevel@tonic-gate
358*0Sstevel@tonic-gate# Third level heading.
359*0Sstevel@tonic-gatesub cmd_head3 {
360*0Sstevel@tonic-gate    my ($self, $text, $line) = @_;
361*0Sstevel@tonic-gate    $self->heading ($text, $line, $$self{indent} * 2 / 3 + 0.5, '=   ');
362*0Sstevel@tonic-gate}
363*0Sstevel@tonic-gate
364*0Sstevel@tonic-gate# Third level heading.
365*0Sstevel@tonic-gatesub cmd_head4 {
366*0Sstevel@tonic-gate    my ($self, $text, $line) = @_;
367*0Sstevel@tonic-gate    $self->heading ($text, $line, $$self{indent} * 3 / 4 + 0.5, '-   ');
368*0Sstevel@tonic-gate}
369*0Sstevel@tonic-gate
370*0Sstevel@tonic-gate# Start a list.
371*0Sstevel@tonic-gatesub cmd_over {
372*0Sstevel@tonic-gate    my $self = shift;
373*0Sstevel@tonic-gate    local $_ = shift;
374*0Sstevel@tonic-gate    $self->item ("\n\n") if defined $$self{ITEM};
375*0Sstevel@tonic-gate    unless (/^[-+]?\d+\s+$/) { $_ = $$self{indent} }
376*0Sstevel@tonic-gate    push (@{ $$self{INDENTS} }, $$self{MARGIN});
377*0Sstevel@tonic-gate    $$self{MARGIN} += ($_ + 0);
378*0Sstevel@tonic-gate}
379*0Sstevel@tonic-gate
380*0Sstevel@tonic-gate# End a list.
381*0Sstevel@tonic-gatesub cmd_back {
382*0Sstevel@tonic-gate    my ($self, $text, $line, $paragraph) = @_;
383*0Sstevel@tonic-gate    $self->item ("\n\n") if defined $$self{ITEM};
384*0Sstevel@tonic-gate    $$self{MARGIN} = pop @{ $$self{INDENTS} };
385*0Sstevel@tonic-gate    unless (defined $$self{MARGIN}) {
386*0Sstevel@tonic-gate        my $file;
387*0Sstevel@tonic-gate        ($file, $line) = $paragraph->file_line;
388*0Sstevel@tonic-gate        warn "$file:$line: Unmatched =back\n";
389*0Sstevel@tonic-gate        $$self{MARGIN} = $$self{indent};
390*0Sstevel@tonic-gate    }
391*0Sstevel@tonic-gate}
392*0Sstevel@tonic-gate
393*0Sstevel@tonic-gate# An individual list item.
394*0Sstevel@tonic-gatesub cmd_item {
395*0Sstevel@tonic-gate    my $self = shift;
396*0Sstevel@tonic-gate    if (defined $$self{ITEM}) { $self->item }
397*0Sstevel@tonic-gate    local $_ = shift;
398*0Sstevel@tonic-gate    s/\s+$//;
399*0Sstevel@tonic-gate    $$self{ITEM} = $_ ? $self->interpolate ($_) : '*';
400*0Sstevel@tonic-gate}
401*0Sstevel@tonic-gate
402*0Sstevel@tonic-gate# Begin a block for a particular translator.  Setting VERBATIM triggers
403*0Sstevel@tonic-gate# special handling in textblock().
404*0Sstevel@tonic-gatesub cmd_begin {
405*0Sstevel@tonic-gate    my $self = shift;
406*0Sstevel@tonic-gate    local $_ = shift;
407*0Sstevel@tonic-gate    my ($kind) = /^(\S+)/ or return;
408*0Sstevel@tonic-gate    if ($kind eq 'text') {
409*0Sstevel@tonic-gate        $$self{VERBATIM} = 1;
410*0Sstevel@tonic-gate    } else {
411*0Sstevel@tonic-gate        $$self{EXCLUDE} = 1;
412*0Sstevel@tonic-gate    }
413*0Sstevel@tonic-gate}
414*0Sstevel@tonic-gate
415*0Sstevel@tonic-gate# End a block for a particular translator.  We assume that all =begin/=end
416*0Sstevel@tonic-gate# pairs are properly closed.
417*0Sstevel@tonic-gatesub cmd_end {
418*0Sstevel@tonic-gate    my $self = shift;
419*0Sstevel@tonic-gate    $$self{EXCLUDE} = 0;
420*0Sstevel@tonic-gate    $$self{VERBATIM} = 0;
421*0Sstevel@tonic-gate}
422*0Sstevel@tonic-gate
423*0Sstevel@tonic-gate# One paragraph for a particular translator.  Ignore it unless it's intended
424*0Sstevel@tonic-gate# for text, in which case we treat it as a verbatim text block.
425*0Sstevel@tonic-gatesub cmd_for {
426*0Sstevel@tonic-gate    my $self = shift;
427*0Sstevel@tonic-gate    local $_ = shift;
428*0Sstevel@tonic-gate    my $line = shift;
429*0Sstevel@tonic-gate    return unless s/^text\b[ \t]*\n?//;
430*0Sstevel@tonic-gate    $self->verbatim ($_, $line);
431*0Sstevel@tonic-gate}
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gate
434*0Sstevel@tonic-gate##############################################################################
435*0Sstevel@tonic-gate# Formatting codes
436*0Sstevel@tonic-gate##############################################################################
437*0Sstevel@tonic-gate
438*0Sstevel@tonic-gate# The simple ones.  These are here mostly so that subclasses can override them
439*0Sstevel@tonic-gate# and do more complicated things.
440*0Sstevel@tonic-gatesub seq_b { return $_[0]{alt} ? "``$_[1]''" : $_[1] }
441*0Sstevel@tonic-gatesub seq_f { return $_[0]{alt} ? "\"$_[1]\"" : $_[1] }
442*0Sstevel@tonic-gatesub seq_i { return '*' . $_[1] . '*' }
443*0Sstevel@tonic-gate
444*0Sstevel@tonic-gate# Apply a whole bunch of messy heuristics to not quote things that don't
445*0Sstevel@tonic-gate# benefit from being quoted.  These originally come from Barrie Slaymaker and
446*0Sstevel@tonic-gate# largely duplicate code in Pod::Man.
447*0Sstevel@tonic-gatesub seq_c {
448*0Sstevel@tonic-gate    my $self = shift;
449*0Sstevel@tonic-gate    local $_ = shift;
450*0Sstevel@tonic-gate
451*0Sstevel@tonic-gate    # A regex that matches the portion of a variable reference that's the
452*0Sstevel@tonic-gate    # array or hash index, separated out just because we want to use it in
453*0Sstevel@tonic-gate    # several places in the following regex.
454*0Sstevel@tonic-gate    my $index = '(?: \[.*\] | \{.*\} )?';
455*0Sstevel@tonic-gate
456*0Sstevel@tonic-gate    # Check for things that we don't want to quote, and if we find any of
457*0Sstevel@tonic-gate    # them, return the string with just a font change and no quoting.
458*0Sstevel@tonic-gate    m{
459*0Sstevel@tonic-gate      ^\s*
460*0Sstevel@tonic-gate      (?:
461*0Sstevel@tonic-gate         ( [\'\`\"] ) .* \1                             # already quoted
462*0Sstevel@tonic-gate       | \` .* \'                                       # `quoted'
463*0Sstevel@tonic-gate       | \$+ [\#^]? \S $index                           # special ($^Foo, $")
464*0Sstevel@tonic-gate       | [\$\@%&*]+ \#? [:\'\w]+ $index                 # plain var or func
465*0Sstevel@tonic-gate       | [\$\@%&*]* [:\'\w]+ (?: -> )? \(\s*[^\s,]\s*\) # 0/1-arg func call
466*0Sstevel@tonic-gate       | [+-]? ( \d[\d.]* | \.\d+ ) (?: [eE][+-]?\d+ )? # a number
467*0Sstevel@tonic-gate       | 0x [a-fA-F\d]+                                 # a hex constant
468*0Sstevel@tonic-gate      )
469*0Sstevel@tonic-gate      \s*\z
470*0Sstevel@tonic-gate     }xo && return $_;
471*0Sstevel@tonic-gate
472*0Sstevel@tonic-gate    # If we didn't return, go ahead and quote the text.
473*0Sstevel@tonic-gate    return $$self{alt} ? "``$_''" : "$$self{LQUOTE}$_$$self{RQUOTE}";
474*0Sstevel@tonic-gate}
475*0Sstevel@tonic-gate
476*0Sstevel@tonic-gate# Handle links.  Since this is plain text, we can't actually make any real
477*0Sstevel@tonic-gate# links, so this is all to figure out what text we print out.  Most of the
478*0Sstevel@tonic-gate# work is done by Pod::ParseLink.
479*0Sstevel@tonic-gatesub seq_l {
480*0Sstevel@tonic-gate    my ($self, $link, $seq) = @_;
481*0Sstevel@tonic-gate    my ($text, $type) = (parselink ($link))[1,4];
482*0Sstevel@tonic-gate    my ($file, $line) = $seq->file_line;
483*0Sstevel@tonic-gate    $text = $self->interpolate ($text, $line);
484*0Sstevel@tonic-gate    $text = '<' . $text . '>' if $type eq 'url';
485*0Sstevel@tonic-gate    return $text || '';
486*0Sstevel@tonic-gate}
487*0Sstevel@tonic-gate
488*0Sstevel@tonic-gate
489*0Sstevel@tonic-gate##############################################################################
490*0Sstevel@tonic-gate# Header handling
491*0Sstevel@tonic-gate##############################################################################
492*0Sstevel@tonic-gate
493*0Sstevel@tonic-gate# The common code for handling all headers.  Takes the interpolated header
494*0Sstevel@tonic-gate# text, the line number, the indentation, and the surrounding marker for the
495*0Sstevel@tonic-gate# alt formatting method.
496*0Sstevel@tonic-gatesub heading {
497*0Sstevel@tonic-gate    my ($self, $text, $line, $indent, $marker) = @_;
498*0Sstevel@tonic-gate    $self->item ("\n\n") if defined $$self{ITEM};
499*0Sstevel@tonic-gate    $text =~ s/\s+$//;
500*0Sstevel@tonic-gate    $text = $self->interpolate ($text, $line);
501*0Sstevel@tonic-gate    if ($$self{alt}) {
502*0Sstevel@tonic-gate        my $closemark = reverse (split (//, $marker));
503*0Sstevel@tonic-gate        my $margin = ' ' x $$self{margin};
504*0Sstevel@tonic-gate        $self->output ("\n" . "$margin$marker $text $closemark" . "\n\n");
505*0Sstevel@tonic-gate    } else {
506*0Sstevel@tonic-gate        $text .= "\n" if $$self{loose};
507*0Sstevel@tonic-gate        my $margin = ' ' x ($$self{margin} + $indent);
508*0Sstevel@tonic-gate        $self->output ($margin . $text . "\n");
509*0Sstevel@tonic-gate    }
510*0Sstevel@tonic-gate}
511*0Sstevel@tonic-gate
512*0Sstevel@tonic-gate
513*0Sstevel@tonic-gate##############################################################################
514*0Sstevel@tonic-gate# List handling
515*0Sstevel@tonic-gate##############################################################################
516*0Sstevel@tonic-gate
517*0Sstevel@tonic-gate# This method is called whenever an =item command is complete (in other words,
518*0Sstevel@tonic-gate# we've seen its associated paragraph or know for certain that it doesn't have
519*0Sstevel@tonic-gate# one).  It gets the paragraph associated with the item as an argument.  If
520*0Sstevel@tonic-gate# that argument is empty, just output the item tag; if it contains a newline,
521*0Sstevel@tonic-gate# output the item tag followed by the newline.  Otherwise, see if there's
522*0Sstevel@tonic-gate# enough room for us to output the item tag in the margin of the text or if we
523*0Sstevel@tonic-gate# have to put it on a separate line.
524*0Sstevel@tonic-gatesub item {
525*0Sstevel@tonic-gate    my $self = shift;
526*0Sstevel@tonic-gate    local $_ = shift;
527*0Sstevel@tonic-gate    my $tag = $$self{ITEM};
528*0Sstevel@tonic-gate    unless (defined $tag) {
529*0Sstevel@tonic-gate        carp "Item called without tag";
530*0Sstevel@tonic-gate        return;
531*0Sstevel@tonic-gate    }
532*0Sstevel@tonic-gate    undef $$self{ITEM};
533*0Sstevel@tonic-gate    my $indent = $$self{INDENTS}[-1];
534*0Sstevel@tonic-gate    unless (defined $indent) { $indent = $$self{indent} }
535*0Sstevel@tonic-gate    my $margin = ' ' x $$self{margin};
536*0Sstevel@tonic-gate    if (!$_ || /^\s+$/ || ($$self{MARGIN} - $indent < length ($tag) + 1)) {
537*0Sstevel@tonic-gate        my $realindent = $$self{MARGIN};
538*0Sstevel@tonic-gate        $$self{MARGIN} = $indent;
539*0Sstevel@tonic-gate        my $output = $self->reformat ($tag);
540*0Sstevel@tonic-gate        $output =~ s/^$margin /$margin:/ if ($$self{alt} && $indent > 0);
541*0Sstevel@tonic-gate        $output =~ s/\n*$/\n/;
542*0Sstevel@tonic-gate
543*0Sstevel@tonic-gate        # If the text is just whitespace, we have an empty item paragraph;
544*0Sstevel@tonic-gate        # this can result from =over/=item/=back without any intermixed
545*0Sstevel@tonic-gate        # paragraphs.  Insert some whitespace to keep the =item from merging
546*0Sstevel@tonic-gate        # into the next paragraph.
547*0Sstevel@tonic-gate        $output .= "\n" if $_ && $_ =~ /^\s*$/;
548*0Sstevel@tonic-gate
549*0Sstevel@tonic-gate        $self->output ($output);
550*0Sstevel@tonic-gate        $$self{MARGIN} = $realindent;
551*0Sstevel@tonic-gate        $self->output ($self->reformat ($_)) if $_ && /\S/;
552*0Sstevel@tonic-gate    } else {
553*0Sstevel@tonic-gate        my $space = ' ' x $indent;
554*0Sstevel@tonic-gate        $space =~ s/^$margin /$margin:/ if $$self{alt};
555*0Sstevel@tonic-gate        $_ = $self->reformat ($_);
556*0Sstevel@tonic-gate        s/^$margin /$margin:/ if ($$self{alt} && $indent > 0);
557*0Sstevel@tonic-gate        my $tagspace = ' ' x length $tag;
558*0Sstevel@tonic-gate        s/^($space)$tagspace/$1$tag/ or warn "Bizarre space in item";
559*0Sstevel@tonic-gate        $self->output ($_);
560*0Sstevel@tonic-gate    }
561*0Sstevel@tonic-gate}
562*0Sstevel@tonic-gate
563*0Sstevel@tonic-gate
564*0Sstevel@tonic-gate##############################################################################
565*0Sstevel@tonic-gate# Output formatting
566*0Sstevel@tonic-gate##############################################################################
567*0Sstevel@tonic-gate
568*0Sstevel@tonic-gate# Wrap a line, indenting by the current left margin.  We can't use Text::Wrap
569*0Sstevel@tonic-gate# because it plays games with tabs.  We can't use formline, even though we'd
570*0Sstevel@tonic-gate# really like to, because it screws up non-printing characters.  So we have to
571*0Sstevel@tonic-gate# do the wrapping ourselves.
572*0Sstevel@tonic-gatesub wrap {
573*0Sstevel@tonic-gate    my $self = shift;
574*0Sstevel@tonic-gate    local $_ = shift;
575*0Sstevel@tonic-gate    my $output = '';
576*0Sstevel@tonic-gate    my $spaces = ' ' x $$self{MARGIN};
577*0Sstevel@tonic-gate    my $width = $$self{width} - $$self{MARGIN};
578*0Sstevel@tonic-gate    while (length > $width) {
579*0Sstevel@tonic-gate        if (s/^([^\n]{0,$width})\s+// || s/^([^\n]{$width})//) {
580*0Sstevel@tonic-gate            $output .= $spaces . $1 . "\n";
581*0Sstevel@tonic-gate        } else {
582*0Sstevel@tonic-gate            last;
583*0Sstevel@tonic-gate        }
584*0Sstevel@tonic-gate    }
585*0Sstevel@tonic-gate    $output .= $spaces . $_;
586*0Sstevel@tonic-gate    $output =~ s/\s+$/\n\n/;
587*0Sstevel@tonic-gate    $output;
588*0Sstevel@tonic-gate}
589*0Sstevel@tonic-gate
590*0Sstevel@tonic-gate# Reformat a paragraph of text for the current margin.  Takes the text to
591*0Sstevel@tonic-gate# reformat and returns the formatted text.
592*0Sstevel@tonic-gatesub reformat {
593*0Sstevel@tonic-gate    my $self = shift;
594*0Sstevel@tonic-gate    local $_ = shift;
595*0Sstevel@tonic-gate
596*0Sstevel@tonic-gate    # If we're trying to preserve two spaces after sentences, do some munging
597*0Sstevel@tonic-gate    # to support that.  Otherwise, smash all repeated whitespace.
598*0Sstevel@tonic-gate    if ($$self{sentence}) {
599*0Sstevel@tonic-gate        s/ +$//mg;
600*0Sstevel@tonic-gate        s/\.\n/. \n/g;
601*0Sstevel@tonic-gate        s/\n/ /g;
602*0Sstevel@tonic-gate        s/   +/  /g;
603*0Sstevel@tonic-gate    } else {
604*0Sstevel@tonic-gate        s/\s+/ /g;
605*0Sstevel@tonic-gate    }
606*0Sstevel@tonic-gate    $self->wrap ($_);
607*0Sstevel@tonic-gate}
608*0Sstevel@tonic-gate
609*0Sstevel@tonic-gate# Output text to the output device.
610*0Sstevel@tonic-gatesub output { $_[1] =~ tr/\01/ /; print { $_[0]->output_handle } $_[1] }
611*0Sstevel@tonic-gate
612*0Sstevel@tonic-gate# Output a block of code (something that isn't part of the POD text).  Called
613*0Sstevel@tonic-gate# by preprocess_paragraph only if we were given the code option.  Exists here
614*0Sstevel@tonic-gate# only so that it can be overridden by subclasses.
615*0Sstevel@tonic-gatesub output_code { $_[0]->output ($_[1]) }
616*0Sstevel@tonic-gate
617*0Sstevel@tonic-gate
618*0Sstevel@tonic-gate##############################################################################
619*0Sstevel@tonic-gate# Backwards compatibility
620*0Sstevel@tonic-gate##############################################################################
621*0Sstevel@tonic-gate
622*0Sstevel@tonic-gate# The old Pod::Text module did everything in a pod2text() function.  This
623*0Sstevel@tonic-gate# tries to provide the same interface for legacy applications.
624*0Sstevel@tonic-gatesub pod2text {
625*0Sstevel@tonic-gate    my @args;
626*0Sstevel@tonic-gate
627*0Sstevel@tonic-gate    # This is really ugly; I hate doing option parsing in the middle of a
628*0Sstevel@tonic-gate    # module.  But the old Pod::Text module supported passing flags to its
629*0Sstevel@tonic-gate    # entry function, so handle -a and -<number>.
630*0Sstevel@tonic-gate    while ($_[0] =~ /^-/) {
631*0Sstevel@tonic-gate        my $flag = shift;
632*0Sstevel@tonic-gate        if    ($flag eq '-a')       { push (@args, alt => 1)    }
633*0Sstevel@tonic-gate        elsif ($flag =~ /^-(\d+)$/) { push (@args, width => $1) }
634*0Sstevel@tonic-gate        else {
635*0Sstevel@tonic-gate            unshift (@_, $flag);
636*0Sstevel@tonic-gate            last;
637*0Sstevel@tonic-gate        }
638*0Sstevel@tonic-gate    }
639*0Sstevel@tonic-gate
640*0Sstevel@tonic-gate    # Now that we know what arguments we're using, create the parser.
641*0Sstevel@tonic-gate    my $parser = Pod::Text->new (@args);
642*0Sstevel@tonic-gate
643*0Sstevel@tonic-gate    # If two arguments were given, the second argument is going to be a file
644*0Sstevel@tonic-gate    # handle.  That means we want to call parse_from_filehandle(), which means
645*0Sstevel@tonic-gate    # we need to turn the first argument into a file handle.  Magic open will
646*0Sstevel@tonic-gate    # handle the <&STDIN case automagically.
647*0Sstevel@tonic-gate    if (defined $_[1]) {
648*0Sstevel@tonic-gate        my @fhs = @_;
649*0Sstevel@tonic-gate        local *IN;
650*0Sstevel@tonic-gate        unless (open (IN, $fhs[0])) {
651*0Sstevel@tonic-gate            croak ("Can't open $fhs[0] for reading: $!\n");
652*0Sstevel@tonic-gate            return;
653*0Sstevel@tonic-gate        }
654*0Sstevel@tonic-gate        $fhs[0] = \*IN;
655*0Sstevel@tonic-gate        return $parser->parse_from_filehandle (@fhs);
656*0Sstevel@tonic-gate    } else {
657*0Sstevel@tonic-gate        return $parser->parse_from_file (@_);
658*0Sstevel@tonic-gate    }
659*0Sstevel@tonic-gate}
660*0Sstevel@tonic-gate
661*0Sstevel@tonic-gate
662*0Sstevel@tonic-gate##############################################################################
663*0Sstevel@tonic-gate# Module return value and documentation
664*0Sstevel@tonic-gate##############################################################################
665*0Sstevel@tonic-gate
666*0Sstevel@tonic-gate1;
667*0Sstevel@tonic-gate__END__
668*0Sstevel@tonic-gate
669*0Sstevel@tonic-gate=head1 NAME
670*0Sstevel@tonic-gate
671*0Sstevel@tonic-gatePod::Text - Convert POD data to formatted ASCII text
672*0Sstevel@tonic-gate
673*0Sstevel@tonic-gate=head1 SYNOPSIS
674*0Sstevel@tonic-gate
675*0Sstevel@tonic-gate    use Pod::Text;
676*0Sstevel@tonic-gate    my $parser = Pod::Text->new (sentence => 0, width => 78);
677*0Sstevel@tonic-gate
678*0Sstevel@tonic-gate    # Read POD from STDIN and write to STDOUT.
679*0Sstevel@tonic-gate    $parser->parse_from_filehandle;
680*0Sstevel@tonic-gate
681*0Sstevel@tonic-gate    # Read POD from file.pod and write to file.txt.
682*0Sstevel@tonic-gate    $parser->parse_from_file ('file.pod', 'file.txt');
683*0Sstevel@tonic-gate
684*0Sstevel@tonic-gate=head1 DESCRIPTION
685*0Sstevel@tonic-gate
686*0Sstevel@tonic-gatePod::Text is a module that can convert documentation in the POD format (the
687*0Sstevel@tonic-gatepreferred language for documenting Perl) into formatted ASCII.  It uses no
688*0Sstevel@tonic-gatespecial formatting controls or codes whatsoever, and its output is therefore
689*0Sstevel@tonic-gatesuitable for nearly any device.
690*0Sstevel@tonic-gate
691*0Sstevel@tonic-gateAs a derived class from Pod::Parser, Pod::Text supports the same methods and
692*0Sstevel@tonic-gateinterfaces.  See L<Pod::Parser> for all the details; briefly, one creates a
693*0Sstevel@tonic-gatenew parser with C<< Pod::Text->new() >> and then calls either
694*0Sstevel@tonic-gateparse_from_filehandle() or parse_from_file().
695*0Sstevel@tonic-gate
696*0Sstevel@tonic-gatenew() can take options, in the form of key/value pairs, that control the
697*0Sstevel@tonic-gatebehavior of the parser.  The currently recognized options are:
698*0Sstevel@tonic-gate
699*0Sstevel@tonic-gate=over 4
700*0Sstevel@tonic-gate
701*0Sstevel@tonic-gate=item alt
702*0Sstevel@tonic-gate
703*0Sstevel@tonic-gateIf set to a true value, selects an alternate output format that, among other
704*0Sstevel@tonic-gatethings, uses a different heading style and marks C<=item> entries with a
705*0Sstevel@tonic-gatecolon in the left margin.  Defaults to false.
706*0Sstevel@tonic-gate
707*0Sstevel@tonic-gate=item code
708*0Sstevel@tonic-gate
709*0Sstevel@tonic-gateIf set to a true value, the non-POD parts of the input file will be included
710*0Sstevel@tonic-gatein the output.  Useful for viewing code documented with POD blocks with the
711*0Sstevel@tonic-gatePOD rendered and the code left intact.
712*0Sstevel@tonic-gate
713*0Sstevel@tonic-gate=item indent
714*0Sstevel@tonic-gate
715*0Sstevel@tonic-gateThe number of spaces to indent regular text, and the default indentation for
716*0Sstevel@tonic-gateC<=over> blocks.  Defaults to 4.
717*0Sstevel@tonic-gate
718*0Sstevel@tonic-gate=item loose
719*0Sstevel@tonic-gate
720*0Sstevel@tonic-gateIf set to a true value, a blank line is printed after a C<=head1> heading.
721*0Sstevel@tonic-gateIf set to false (the default), no blank line is printed after C<=head1>,
722*0Sstevel@tonic-gatealthough one is still printed after C<=head2>.  This is the default because
723*0Sstevel@tonic-gateit's the expected formatting for manual pages; if you're formatting
724*0Sstevel@tonic-gatearbitrary text documents, setting this to true may result in more pleasing
725*0Sstevel@tonic-gateoutput.
726*0Sstevel@tonic-gate
727*0Sstevel@tonic-gate=item margin
728*0Sstevel@tonic-gate
729*0Sstevel@tonic-gateThe width of the left margin in spaces.  Defaults to 0.  This is the margin
730*0Sstevel@tonic-gatefor all text, including headings, not the amount by which regular text is
731*0Sstevel@tonic-gateindented; for the latter, see the I<indent> option.  To set the right
732*0Sstevel@tonic-gatemargin, see the I<width> option.
733*0Sstevel@tonic-gate
734*0Sstevel@tonic-gate=item quotes
735*0Sstevel@tonic-gate
736*0Sstevel@tonic-gateSets the quote marks used to surround CE<lt>> text.  If the value is a
737*0Sstevel@tonic-gatesingle character, it is used as both the left and right quote; if it is two
738*0Sstevel@tonic-gatecharacters, the first character is used as the left quote and the second as
739*0Sstevel@tonic-gatethe right quoted; and if it is four characters, the first two are used as
740*0Sstevel@tonic-gatethe left quote and the second two as the right quote.
741*0Sstevel@tonic-gate
742*0Sstevel@tonic-gateThis may also be set to the special value C<none>, in which case no quote
743*0Sstevel@tonic-gatemarks are added around CE<lt>> text.
744*0Sstevel@tonic-gate
745*0Sstevel@tonic-gate=item sentence
746*0Sstevel@tonic-gate
747*0Sstevel@tonic-gateIf set to a true value, Pod::Text will assume that each sentence ends in two
748*0Sstevel@tonic-gatespaces, and will try to preserve that spacing.  If set to false, all
749*0Sstevel@tonic-gateconsecutive whitespace in non-verbatim paragraphs is compressed into a
750*0Sstevel@tonic-gatesingle space.  Defaults to true.
751*0Sstevel@tonic-gate
752*0Sstevel@tonic-gate=item width
753*0Sstevel@tonic-gate
754*0Sstevel@tonic-gateThe column at which to wrap text on the right-hand side.  Defaults to 76.
755*0Sstevel@tonic-gate
756*0Sstevel@tonic-gate=back
757*0Sstevel@tonic-gate
758*0Sstevel@tonic-gateThe standard Pod::Parser method parse_from_filehandle() takes up to two
759*0Sstevel@tonic-gatearguments, the first being the file handle to read POD from and the second
760*0Sstevel@tonic-gatebeing the file handle to write the formatted output to.  The first defaults
761*0Sstevel@tonic-gateto STDIN if not given, and the second defaults to STDOUT.  The method
762*0Sstevel@tonic-gateparse_from_file() is almost identical, except that its two arguments are the
763*0Sstevel@tonic-gateinput and output disk files instead.  See L<Pod::Parser> for the specific
764*0Sstevel@tonic-gatedetails.
765*0Sstevel@tonic-gate
766*0Sstevel@tonic-gate=head1 DIAGNOSTICS
767*0Sstevel@tonic-gate
768*0Sstevel@tonic-gate=over 4
769*0Sstevel@tonic-gate
770*0Sstevel@tonic-gate=item Bizarre space in item
771*0Sstevel@tonic-gate
772*0Sstevel@tonic-gate=item Item called without tag
773*0Sstevel@tonic-gate
774*0Sstevel@tonic-gate(W) Something has gone wrong in internal C<=item> processing.  These
775*0Sstevel@tonic-gatemessages indicate a bug in Pod::Text; you should never see them.
776*0Sstevel@tonic-gate
777*0Sstevel@tonic-gate=item Can't open %s for reading: %s
778*0Sstevel@tonic-gate
779*0Sstevel@tonic-gate(F) Pod::Text was invoked via the compatibility mode pod2text() interface
780*0Sstevel@tonic-gateand the input file it was given could not be opened.
781*0Sstevel@tonic-gate
782*0Sstevel@tonic-gate=item Invalid quote specification "%s"
783*0Sstevel@tonic-gate
784*0Sstevel@tonic-gate(F) The quote specification given (the quotes option to the constructor) was
785*0Sstevel@tonic-gateinvalid.  A quote specification must be one, two, or four characters long.
786*0Sstevel@tonic-gate
787*0Sstevel@tonic-gate=item %s:%d: Unknown command paragraph: %s
788*0Sstevel@tonic-gate
789*0Sstevel@tonic-gate(W) The POD source contained a non-standard command paragraph (something of
790*0Sstevel@tonic-gatethe form C<=command args>) that Pod::Man didn't know about.  It was ignored.
791*0Sstevel@tonic-gate
792*0Sstevel@tonic-gate=item %s:%d: Unknown escape: %s
793*0Sstevel@tonic-gate
794*0Sstevel@tonic-gate(W) The POD source contained an C<EE<lt>E<gt>> escape that Pod::Text didn't
795*0Sstevel@tonic-gateknow about.
796*0Sstevel@tonic-gate
797*0Sstevel@tonic-gate=item %s:%d: Unknown formatting code: %s
798*0Sstevel@tonic-gate
799*0Sstevel@tonic-gate(W) The POD source contained a non-standard formatting code (something of
800*0Sstevel@tonic-gatethe form C<XE<lt>E<gt>>) that Pod::Text didn't know about.
801*0Sstevel@tonic-gate
802*0Sstevel@tonic-gate=item %s:%d: Unmatched =back
803*0Sstevel@tonic-gate
804*0Sstevel@tonic-gate(W) Pod::Text encountered a C<=back> command that didn't correspond to an
805*0Sstevel@tonic-gateC<=over> command.
806*0Sstevel@tonic-gate
807*0Sstevel@tonic-gate=back
808*0Sstevel@tonic-gate
809*0Sstevel@tonic-gate=head1 RESTRICTIONS
810*0Sstevel@tonic-gate
811*0Sstevel@tonic-gateEmbedded Ctrl-As (octal 001) in the input will be mapped to spaces on
812*0Sstevel@tonic-gateoutput, due to an internal implementation detail.
813*0Sstevel@tonic-gate
814*0Sstevel@tonic-gate=head1 NOTES
815*0Sstevel@tonic-gate
816*0Sstevel@tonic-gateThis is a replacement for an earlier Pod::Text module written by Tom
817*0Sstevel@tonic-gateChristiansen.  It has a revamped interface, since it now uses Pod::Parser,
818*0Sstevel@tonic-gatebut an interface roughly compatible with the old Pod::Text::pod2text()
819*0Sstevel@tonic-gatefunction is still available.  Please change to the new calling convention,
820*0Sstevel@tonic-gatethough.
821*0Sstevel@tonic-gate
822*0Sstevel@tonic-gateThe original Pod::Text contained code to do formatting via termcap
823*0Sstevel@tonic-gatesequences, although it wasn't turned on by default and it was problematic to
824*0Sstevel@tonic-gateget it to work at all.  This rewrite doesn't even try to do that, but a
825*0Sstevel@tonic-gatesubclass of it does.  Look for L<Pod::Text::Termcap>.
826*0Sstevel@tonic-gate
827*0Sstevel@tonic-gate=head1 SEE ALSO
828*0Sstevel@tonic-gate
829*0Sstevel@tonic-gateL<Pod::Parser>, L<Pod::Text::Termcap>, L<pod2text(1)>
830*0Sstevel@tonic-gate
831*0Sstevel@tonic-gateThe current version of this module is always available from its web site at
832*0Sstevel@tonic-gateL<http://www.eyrie.org/~eagle/software/podlators/>.  It is also part of the
833*0Sstevel@tonic-gatePerl core distribution as of 5.6.0.
834*0Sstevel@tonic-gate
835*0Sstevel@tonic-gate=head1 AUTHOR
836*0Sstevel@tonic-gate
837*0Sstevel@tonic-gateRuss Allbery <rra@stanford.edu>, based I<very> heavily on the original
838*0Sstevel@tonic-gatePod::Text by Tom Christiansen <tchrist@mox.perl.com> and its conversion to
839*0Sstevel@tonic-gatePod::Parser by Brad Appleton <bradapp@enteract.com>.
840*0Sstevel@tonic-gate
841*0Sstevel@tonic-gate=head1 COPYRIGHT AND LICENSE
842*0Sstevel@tonic-gate
843*0Sstevel@tonic-gateCopyright 1999, 2000, 2001, 2002 by Russ Allbery <rra@stanford.edu>.
844*0Sstevel@tonic-gate
845*0Sstevel@tonic-gateThis program is free software; you may redistribute it and/or modify it
846*0Sstevel@tonic-gateunder the same terms as Perl itself.
847*0Sstevel@tonic-gate
848*0Sstevel@tonic-gate=cut
849