Subversion Repositories DevTools

Rev

Rev 311 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
311 dpurdie 1
# Pod::PlainText -- Convert POD data to formatted ASCII text.
2
# $Id: Text.pm,v 2.1 1999/09/20 11:53:33 eagle Exp $
3
#
4
# Copyright 1999-2000 by Russ Allbery <rra@stanford.edu>
5
#
6
# This program is free software; you can redistribute it and/or modify it
7
# under the same terms as Perl itself.
8
#
9
# This module is intended to be a replacement for Pod::Text, and attempts to
10
# match its output except for some specific circumstances where other
11
# decisions seemed to produce better output.  It uses Pod::Parser and is
12
# designed to be very easy to subclass.
13
 
14
############################################################################
15
# Modules and declarations
16
############################################################################
17
 
18
package Pod::PlainText;
19
use strict;
313 dpurdie 20
use JatsError;
311 dpurdie 21
 
22
require 5.005;
23
 
24
use Carp qw(carp croak);
25
use Pod::Select ();
26
 
27
use vars qw(@ISA %ESCAPES $VERSION);
28
 
29
# We inherit from Pod::Select instead of Pod::Parser so that we can be used
30
# by Pod::Usage.
31
@ISA = qw(Pod::Select);
32
 
33
$VERSION = '2.04';
34
 
35
BEGIN {
36
   if ($] < 5.006) {
37
      require Symbol;
38
      import Symbol;
39
   }
40
}
41
 
42
############################################################################
43
# Table of supported E<> escapes
44
############################################################################
45
 
46
# This table is taken near verbatim from Pod::PlainText in Pod::Parser,
47
# which got it near verbatim from the original Pod::Text.  It is therefore
48
# credited to Tom Christiansen, and I'm glad I didn't have to write it.  :)
49
%ESCAPES = (
50
    'amp'       =>    '&',      # ampersand
51
    'lt'        =>    '<',      # left chevron, less-than
52
    'gt'        =>    '>',      # right chevron, greater-than
53
    'quot'      =>    '"',      # double quote
54
 
55
    "Aacute"    =>    "\xC1",   # capital A, acute accent
56
    "aacute"    =>    "\xE1",   # small a, acute accent
57
    "Acirc"     =>    "\xC2",   # capital A, circumflex accent
58
    "acirc"     =>    "\xE2",   # small a, circumflex accent
59
    "AElig"     =>    "\xC6",   # capital AE diphthong (ligature)
60
    "aelig"     =>    "\xE6",   # small ae diphthong (ligature)
61
    "Agrave"    =>    "\xC0",   # capital A, grave accent
62
    "agrave"    =>    "\xE0",   # small a, grave accent
63
    "Aring"     =>    "\xC5",   # capital A, ring
64
    "aring"     =>    "\xE5",   # small a, ring
65
    "Atilde"    =>    "\xC3",   # capital A, tilde
66
    "atilde"    =>    "\xE3",   # small a, tilde
67
    "Auml"      =>    "\xC4",   # capital A, dieresis or umlaut mark
68
    "auml"      =>    "\xE4",   # small a, dieresis or umlaut mark
69
    "Ccedil"    =>    "\xC7",   # capital C, cedilla
70
    "ccedil"    =>    "\xE7",   # small c, cedilla
71
    "Eacute"    =>    "\xC9",   # capital E, acute accent
72
    "eacute"    =>    "\xE9",   # small e, acute accent
73
    "Ecirc"     =>    "\xCA",   # capital E, circumflex accent
74
    "ecirc"     =>    "\xEA",   # small e, circumflex accent
75
    "Egrave"    =>    "\xC8",   # capital E, grave accent
76
    "egrave"    =>    "\xE8",   # small e, grave accent
77
    "ETH"       =>    "\xD0",   # capital Eth, Icelandic
78
    "eth"       =>    "\xF0",   # small eth, Icelandic
79
    "Euml"      =>    "\xCB",   # capital E, dieresis or umlaut mark
80
    "euml"      =>    "\xEB",   # small e, dieresis or umlaut mark
81
    "Iacute"    =>    "\xCD",   # capital I, acute accent
82
    "iacute"    =>    "\xED",   # small i, acute accent
83
    "Icirc"     =>    "\xCE",   # capital I, circumflex accent
84
    "icirc"     =>    "\xEE",   # small i, circumflex accent
85
    "Igrave"    =>    "\xCD",   # capital I, grave accent
86
    "igrave"    =>    "\xED",   # small i, grave accent
87
    "Iuml"      =>    "\xCF",   # capital I, dieresis or umlaut mark
88
    "iuml"      =>    "\xEF",   # small i, dieresis or umlaut mark
89
    "Ntilde"    =>    "\xD1",   # capital N, tilde
90
    "ntilde"    =>    "\xF1",   # small n, tilde
91
    "Oacute"    =>    "\xD3",   # capital O, acute accent
92
    "oacute"    =>    "\xF3",   # small o, acute accent
93
    "Ocirc"     =>    "\xD4",   # capital O, circumflex accent
94
    "ocirc"     =>    "\xF4",   # small o, circumflex accent
95
    "Ograve"    =>    "\xD2",   # capital O, grave accent
96
    "ograve"    =>    "\xF2",   # small o, grave accent
97
    "Oslash"    =>    "\xD8",   # capital O, slash
98
    "oslash"    =>    "\xF8",   # small o, slash
99
    "Otilde"    =>    "\xD5",   # capital O, tilde
100
    "otilde"    =>    "\xF5",   # small o, tilde
101
    "Ouml"      =>    "\xD6",   # capital O, dieresis or umlaut mark
102
    "ouml"      =>    "\xF6",   # small o, dieresis or umlaut mark
103
    "szlig"     =>    "\xDF",   # small sharp s, German (sz ligature)
104
    "THORN"     =>    "\xDE",   # capital THORN, Icelandic
105
    "thorn"     =>    "\xFE",   # small thorn, Icelandic
106
    "Uacute"    =>    "\xDA",   # capital U, acute accent
107
    "uacute"    =>    "\xFA",   # small u, acute accent
108
    "Ucirc"     =>    "\xDB",   # capital U, circumflex accent
109
    "ucirc"     =>    "\xFB",   # small u, circumflex accent
110
    "Ugrave"    =>    "\xD9",   # capital U, grave accent
111
    "ugrave"    =>    "\xF9",   # small u, grave accent
112
    "Uuml"      =>    "\xDC",   # capital U, dieresis or umlaut mark
113
    "uuml"      =>    "\xFC",   # small u, dieresis or umlaut mark
114
    "Yacute"    =>    "\xDD",   # capital Y, acute accent
115
    "yacute"    =>    "\xFD",   # small y, acute accent
116
    "yuml"      =>    "\xFF",   # small y, dieresis or umlaut mark
117
 
118
    "lchevron"  =>    "\xAB",   # left chevron (double less than)
119
    "rchevron"  =>    "\xBB",   # right chevron (double greater than)
120
);
121
 
122
 
123
############################################################################
124
# Initialization
125
############################################################################
126
 
127
# Initialize the object.  Must be sure to call our parent initializer.
128
sub initialize {
129
    my $self = shift;
130
 
131
    $$self{alt}      = 0  unless defined $$self{alt};
132
    $$self{indent}   = 4  unless defined $$self{indent};
133
    $$self{loose}    = 0  unless defined $$self{loose};
134
    $$self{sentence} = 0  unless defined $$self{sentence};
135
    $$self{width}    = 76 unless defined $$self{width};
136
 
137
    $$self{INDENTS}  = [];              # Stack of indentations.
138
    $$self{MARGIN}   = $$self{indent};  # Current left margin in spaces.
139
 
140
    return $self->SUPER::initialize;
141
}
142
 
143
 
144
############################################################################
145
# Core overrides
146
############################################################################
147
 
148
# Called for each command paragraph.  Gets the command, the associated
149
# paragraph, the line number, and a Pod::Paragraph object.  Just dispatches
150
# the command to a method named the same as the command.  =cut is handled
151
# internally by Pod::Parser.
152
sub command {
153
    my $self = shift;
154
    my $command = shift;
155
    return if $command eq 'pod';
156
    return if ($$self{EXCLUDE} && $command ne 'end');
157
    if (defined $$self{ITEM}) {
158
      $self->item ("\n");
159
      local $_ = "\n";
160
      $self->output($_) if($command eq 'back');
161
    }
162
    $command = 'cmd_' . $command;
163
    return $self->$command (@_);
164
}
165
 
166
# Called for a verbatim paragraph.  Gets the paragraph, the line number, and
167
# a Pod::Paragraph object.  Just output it verbatim, but with tabs converted
168
# to spaces.
169
sub verbatim {
170
    my $self = shift;
171
    return if $$self{EXCLUDE};
172
    $self->item if defined $$self{ITEM};
173
    local $_ = shift;
174
    return if /^\s*$/;
175
    s/^(\s*\S+)/(' ' x $$self{MARGIN}) . $1/gme;
176
    return $self->output($_);
177
}
178
 
179
# Called for a regular text block.  Gets the paragraph, the line number, and
180
# a Pod::Paragraph object.  Perform interpolation and output the results.
181
sub textblock {
182
    my $self = shift;
183
    return if $$self{EXCLUDE};
184
    if($$self{VERBATIM}) {
185
      $self->output($_[0]);
186
      return;
187
    }
188
    local $_ = shift;
189
    my $line = shift;
190
 
191
    # Perform a little magic to collapse multiple L<> references.  This is
192
    # here mostly for backwards-compatibility.  We'll just rewrite the whole
193
    # thing into actual text at this part, bypassing the whole internal
194
    # sequence parsing thing.
195
    s{
196
        (
197
          L<                    # A link of the form L</something>.
198
              /
199
              (
200
                  [:\w]+        # The item has to be a simple word...
201
                  (\(\))?       # ...or simple function.
202
              )
203
          >
204
          (
205
              ,?\s+(and\s+)?    # Allow lots of them, conjuncted.
206
              L<  
207
                  /
208
                  (
209
                      [:\w]+
210
                      (\(\))?
211
                  )
212
              >
213
          )+
214
        )
215
    } {
216
        local $_ = $1;
217
        s%L</([^>]+)>%$1%g;
218
        my @items = split /(?:,?\s+(?:and\s+)?)/;
219
        my $string = "the ";
220
        my $i;
221
        for ($i = 0; $i < @items; $i++) {
222
            $string .= $items[$i];
223
            $string .= ", " if @items > 2 && $i != $#items;
224
            $string .= " and " if ($i == $#items - 1);
225
        }
226
        $string .= " entries elsewhere in this document";
227
        $string;
228
    }gex;
229
 
230
    # Now actually interpolate and output the paragraph.
231
    $_ = $self->interpolate ($_, $line);
232
    s/\s*$/\n/s;
233
    if (defined $$self{ITEM}) {
234
        $self->item ($_ . "\n");
235
    } else {
236
        $self->output ($self->reformat ($_ . "\n"));
237
    }
238
}
239
 
240
# Called for an interior sequence.  Gets the command, argument, and a
241
# Pod::InteriorSequence object and is expected to return the resulting text.
242
# Calls code, bold, italic, file, and link to handle those types of
243
# sequences, and handles S<>, E<>, X<>, and Z<> directly.
244
sub interior_sequence {
245
    my $self = shift;
246
    my $command = shift;
247
    local $_ = shift;
248
    return '' if ($command eq 'X' || $command eq 'Z');
249
 
250
    # Expand escapes into the actual character now, carping if invalid.
251
    if ($command eq 'E') {
252
        return $ESCAPES{$_} if defined $ESCAPES{$_};
253
        carp "Unknown escape: E<$_>";
254
        return "E<$_>";
255
    }
256
 
257
    # For all the other sequences, empty content produces no output.
258
    return if $_ eq '';
259
 
260
    # For S<>, compress all internal whitespace and then map spaces to \01.
261
    # When we output the text, we'll map this back.
262
    if ($command eq 'S') {
263
        s/\s{2,}/ /g;
264
        tr/ /\01/;
265
        return $_;
266
    }
267
 
268
    # Anything else needs to get dispatched to another method.
269
    if    ($command eq 'B') { return $self->seq_b ($_) }
270
    elsif ($command eq 'C') { return $self->seq_c ($_) }
271
    elsif ($command eq 'F') { return $self->seq_f ($_) }
272
    elsif ($command eq 'I') { return $self->seq_i ($_) }
273
    elsif ($command eq 'L') { return $self->seq_l ($_) }
274
    else { carp "Unknown sequence $command<$_>" }
275
}
276
 
277
# Called for each paragraph that's actually part of the POD.  We take
278
# advantage of this opportunity to untabify the input.
279
sub preprocess_paragraph {
280
    my $self = shift;
281
    local $_ = shift;
282
    1 while s/^(.*?)(\t+)/$1 . ' ' x (length ($2) * 8 - length ($1) % 8)/me;
283
    return $_;
284
}
285
 
286
 
287
############################################################################
288
# Command paragraphs
289
############################################################################
290
 
291
# All command paragraphs take the paragraph and the line number.
292
 
293
# First level heading.
294
sub cmd_head1 {
295
    my $self = shift;
296
    local $_ = shift;
297
    s/\s+$//s;
298
    $_ = $self->interpolate ($_, shift);
299
    if ($$self{alt}) {
300
        $self->output ("\n==== $_ ====\n\n");
301
    } else {
302
        $_ .= "\n" if $$self{loose};
303
        $self->output ($_ . "\n");
304
    }
305
}
306
 
307
# Second level heading.
308
sub cmd_head2 {
309
    my $self = shift;
310
    local $_ = shift;
311
    s/\s+$//s;
312
    $_ = $self->interpolate ($_, shift);
313
    if ($$self{alt}) {
314
        $self->output ("\n==   $_   ==\n\n");
315
    } else {
316
        $_ .= "\n" if $$self{loose};
317
        $self->output (' ' x ($$self{indent} / 2) . $_ . "\n");
318
    }
319
}
320
 
321
# third level heading - not strictly perlpodspec compliant
322
sub cmd_head3 {
323
    my $self = shift;
324
    local $_ = shift;
325
    s/\s+$//s;
326
    $_ = $self->interpolate ($_, shift);
327
    if ($$self{alt}) {
328
        $self->output ("\n= $_ =\n");
329
    } else {
330
        $_ .= "\n" if $$self{loose};
331
        $self->output (' ' x ($$self{indent}) . $_ . "\n");
332
    }
333
}
334
 
335
# fourth level heading - not strictly perlpodspec compliant
336
# just like head3
337
*cmd_head4 = \&cmd_head3;
338
 
339
# Start a list.
340
sub cmd_over {
341
    my $self = shift;
342
    local $_ = shift;
343
    unless (/^[-+]?\d+\s+$/) { $_ = $$self{indent} }
344
    push (@{ $$self{INDENTS} }, $$self{MARGIN});
345
    $$self{MARGIN} += ($_ + 0);
346
}
347
 
348
# End a list.
349
sub cmd_back {
350
    my $self = shift;
351
    $$self{MARGIN} = pop @{ $$self{INDENTS} };
352
    unless (defined $$self{MARGIN}) {
353
        carp 'Unmatched =back';
354
        $$self{MARGIN} = $$self{indent};
355
    }
356
}
357
 
358
# An individual list item.
359
sub cmd_item {
360
    my $self = shift;
361
    if (defined $$self{ITEM}) { $self->item }
362
    local $_ = shift;
363
    s/\s+$//s;
364
    $$self{ITEM} = $self->interpolate ($_);
365
}
366
 
367
# Begin a block for a particular translator.  Setting VERBATIM triggers
368
# special handling in textblock().
369
sub cmd_begin {
370
    my $self = shift;
371
    local $_ = shift;
372
    my ($kind) = /^(\S+)/ or return;
373
    if ($kind eq 'text') {
374
        $$self{VERBATIM} = 1;
375
    } else {
376
        $$self{EXCLUDE} = 1;
377
    }
378
}
379
 
380
# End a block for a particular translator.  We assume that all =begin/=end
381
# pairs are properly closed.
382
sub cmd_end {
383
    my $self = shift;
384
    $$self{EXCLUDE} = 0;
385
    $$self{VERBATIM} = 0;
386
}
387
 
388
# One paragraph for a particular translator.  Ignore it unless it's intended
389
# for text, in which case we treat it as a verbatim text block.
390
sub cmd_for {
391
    my $self = shift;
392
    local $_ = shift;
393
    my $line = shift;
394
    return unless s/^text\b[ \t]*\n?//;
395
    $self->verbatim ($_, $line);
396
}
397
 
398
 
399
############################################################################
400
# Interior sequences
401
############################################################################
402
 
403
# The simple formatting ones.  These are here mostly so that subclasses can
404
# override them and do more complicated things.
405
sub seq_b { return $_[0]{alt} ? "``$_[1]''" : $_[1] }
406
sub seq_c { return $_[0]{alt} ? "``$_[1]''" : "`$_[1]'" }
407
sub seq_f { return $_[0]{alt} ? "\"$_[1]\"" : $_[1] }
408
sub seq_i { return '*' . $_[1] . '*' }
409
 
410
# The complicated one.  Handle links.  Since this is plain text, we can't
411
# actually make any real links, so this is all to figure out what text we
412
# print out.
413
sub seq_l {
414
    my $self = shift;
415
    local $_ = shift;
416
 
417
    # Smash whitespace in case we were split across multiple lines.
418
    s/\s+/ /g;
419
 
420
    # If we were given any explicit text, just output it.
421
    if (/^([^|]+)\|/) { return $1 }
422
 
423
    # Okay, leading and trailing whitespace isn't important; get rid of it.
424
    s/^\s+//;
425
    s/\s+$//;
426
 
427
    # Default to using the whole content of the link entry as a section
428
    # name.  Note that L<manpage/> forces a manpage interpretation, as does
429
    # something looking like L<manpage(section)>.  The latter is an
430
    # enhancement over the original Pod::Text.
431
    my ($manpage, $section) = ('', $_);
432
    if (/^(?:https?|ftp|news):/) {
433
        # a URL
434
        return $_;
435
    } elsif (/^"\s*(.*?)\s*"$/) {
436
        $section = '"' . $1 . '"';
437
    } elsif (m/^[-:.\w]+(?:\(\S+\))?$/) {
438
        ($manpage, $section) = ($_, '');
439
    } elsif (m{/}) {
440
        ($manpage, $section) = split (/\s*\/\s*/, $_, 2);
441
    }
442
 
443
    my $text = '';
444
    # Now build the actual output text.
445
    if (!length $section) {
446
        $text = "the $manpage manpage" if length $manpage;
447
    } elsif ($section =~ /^[:\w]+(?:\(\))?/) {
448
        $text .= 'the ' . $section . ' entry';
449
        $text .= (length $manpage) ? " in the $manpage manpage"
450
                                   : ' elsewhere in this document';
451
    } else {
452
        $section =~ s/^\"\s*//;
453
        $section =~ s/\s*\"$//;
454
        $text .= 'the section on "' . $section . '"';
455
        $text .= " in the $manpage manpage" if length $manpage;
456
    }
457
    return $text;
458
}
459
 
460
 
461
############################################################################
462
# List handling
463
############################################################################
464
 
465
# This method is called whenever an =item command is complete (in other
466
# words, we've seen its associated paragraph or know for certain that it
467
# doesn't have one).  It gets the paragraph associated with the item as an
468
# argument.  If that argument is empty, just output the item tag; if it
469
# contains a newline, output the item tag followed by the newline.
470
# Otherwise, see if there's enough room for us to output the item tag in the
471
# margin of the text or if we have to put it on a separate line.
472
sub item {
473
    my $self = shift;
474
    local $_ = shift;
475
    my $tag = $$self{ITEM};
476
    unless (defined $tag) {
477
        carp 'item called without tag';
478
        return;
479
    }
480
    undef $$self{ITEM};
481
    my $indent = $$self{INDENTS}[-1];
482
    unless (defined $indent) { $indent = $$self{indent} }
483
    my $space = ' ' x $indent;
484
    $space =~ s/^ /:/ if $$self{alt};
485
    if (!$_ || /^\s+$/ || ($$self{MARGIN} - $indent < length ($tag) + 1)) {
486
        my $margin = $$self{MARGIN};
313 dpurdie 487
#        $$self{MARGIN} = $indent;  # ERG Deleted. Appears to get the first one wrong
311 dpurdie 488
        my $output = $self->reformat ($tag);
489
        $output =~ s/\n*$/\n/;
490
        $self->output ($output);
491
        $$self{MARGIN} = $margin;
492
        $self->output ($self->reformat ($_)) if /\S/;
493
    } else {
494
        $_ = $self->reformat ($_);
495
        s/^ /:/ if ($$self{alt} && $indent > 0);
496
        my $tagspace = ' ' x length $tag;
497
        s/^($space)$tagspace/$1$tag/ or carp 'Bizarre space in item';
498
        $self->output ($_);
499
    }
500
}
501
 
502
 
503
############################################################################
504
# Output formatting
505
############################################################################
506
 
507
# Wrap a line, indenting by the current left margin.  We can't use
508
# Text::Wrap because it plays games with tabs.  We can't use formline, even
509
# though we'd really like to, because it screws up non-printing characters.
510
# So we have to do the wrapping ourselves.
511
sub wrap {
512
    my $self = shift;
513
    local $_ = shift;
514
    my $output = '';
515
    my $spaces = ' ' x $$self{MARGIN};
516
    my $width = $$self{width} - $$self{MARGIN};
517
    while (length > $width) {
518
        if (s/^([^\n]{0,$width})\s+// || s/^([^\n]{$width})//) {
519
            $output .= $spaces . $1 . "\n";
520
        } else {
521
            last;
522
        }
523
    }
524
    $output .= $spaces . $_;
525
    $output =~ s/\s+$/\n\n/;
526
    return $output;
527
}
528
 
529
# Reformat a paragraph of text for the current margin.  Takes the text to
530
# reformat and returns the formatted text.
531
sub reformat {
532
    my $self = shift;
533
    local $_ = shift;
534
 
535
    # If we're trying to preserve two spaces after sentences, do some
536
    # munging to support that.  Otherwise, smash all repeated whitespace.
537
    if ($$self{sentence}) {
538
        s/ +$//mg;
539
        s/\.\n/. \n/g;
540
        s/\n/ /g;
541
        s/   +/  /g;
542
    } else {
543
        s/\s+/ /g;
544
    }
545
    return $self->wrap($_);
546
}
547
 
548
# Output text to the output device.
549
sub output { $_[1] =~ tr/\01/ /; print { $_[0]->output_handle } $_[1] }
550
 
551
 
552
############################################################################
553
# Backwards compatibility
554
############################################################################
555
 
556
# The old Pod::Text module did everything in a pod2text() function.  This
557
# tries to provide the same interface for legacy applications.
558
sub pod2text {
559
    my @args;
560
 
561
    # This is really ugly; I hate doing option parsing in the middle of a
562
    # module.  But the old Pod::Text module supported passing flags to its
563
    # entry function, so handle -a and -<number>.
564
    while ($_[0] =~ /^-/) {
565
        my $flag = shift;
566
        if    ($flag eq '-a')       { push (@args, alt => 1)    }
567
        elsif ($flag =~ /^-(\d+)$/) { push (@args, width => $1) }
568
        else {
569
            unshift (@_, $flag);
570
            last;
571
        }
572
    }
573
 
574
    # Now that we know what arguments we're using, create the parser.
575
    my $parser = Pod::PlainText->new (@args);
576
 
577
    # If two arguments were given, the second argument is going to be a file
578
    # handle.  That means we want to call parse_from_filehandle(), which
579
    # means we need to turn the first argument into a file handle.  Magic
580
    # open will handle the <&STDIN case automagically.
581
    if (defined $_[1]) {
582
        my $infh;
583
        if ($] < 5.006) {
584
          $infh = gensym();
585
        }
586
        unless (open ($infh, $_[0])) {
587
            croak ("Can't open $_[0] for reading: $!\n");
588
        }
589
        $_[0] = $infh;
590
        return $parser->parse_from_filehandle (@_);
591
    } else {
592
        return $parser->parse_from_file (@_);
593
    }
594
}
595
 
596
 
597
############################################################################
598
# Module return value and documentation
599
############################################################################
600
 
601
1;
602
__END__
603
 
604
=head1 NAME
605
 
606
Pod::PlainText - Convert POD data to formatted ASCII text
607
 
608
=head1 SYNOPSIS
609
 
610
    use Pod::PlainText;
611
    my $parser = Pod::PlainText->new (sentence => 0, width => 78);
612
 
613
    # Read POD from STDIN and write to STDOUT.
614
    $parser->parse_from_filehandle;
615
 
616
    # Read POD from file.pod and write to file.txt.
617
    $parser->parse_from_file ('file.pod', 'file.txt');
618
 
619
=head1 DESCRIPTION
620
 
621
Pod::PlainText is a module that can convert documentation in the POD format (the
622
preferred language for documenting Perl) into formatted ASCII.  It uses no
623
special formatting controls or codes whatsoever, and its output is therefore
624
suitable for nearly any device.
625
 
626
As a derived class from Pod::Parser, Pod::PlainText supports the same methods and
627
interfaces.  See L<Pod::Parser> for all the details; briefly, one creates a
628
new parser with C<Pod::PlainText-E<gt>new()> and then calls either
629
parse_from_filehandle() or parse_from_file().
630
 
631
new() can take options, in the form of key/value pairs, that control the
632
behavior of the parser.  The currently recognized options are:
633
 
634
=over 4
635
 
636
=item alt
637
 
638
If set to a true value, selects an alternate output format that, among other
639
things, uses a different heading style and marks C<=item> entries with a
640
colon in the left margin.  Defaults to false.
641
 
642
=item indent
643
 
644
The number of spaces to indent regular text, and the default indentation for
645
C<=over> blocks.  Defaults to 4.
646
 
647
=item loose
648
 
649
If set to a true value, a blank line is printed after a C<=headN> headings.
650
If set to false (the default), no blank line is printed after C<=headN>.
651
This is the default because it's the expected formatting for manual pages;
652
if you're formatting arbitrary text documents, setting this to true may
653
result in more pleasing output.
654
 
655
=item sentence
656
 
657
If set to a true value, Pod::PlainText will assume that each sentence ends in two
658
spaces, and will try to preserve that spacing.  If set to false, all
659
consecutive whitespace in non-verbatim paragraphs is compressed into a
660
single space.  Defaults to true.
661
 
662
=item width
663
 
664
The column at which to wrap text on the right-hand side.  Defaults to 76.
665
 
666
=back
667
 
668
The standard Pod::Parser method parse_from_filehandle() takes up to two
669
arguments, the first being the file handle to read POD from and the second
670
being the file handle to write the formatted output to.  The first defaults
671
to STDIN if not given, and the second defaults to STDOUT.  The method
672
parse_from_file() is almost identical, except that its two arguments are the
673
input and output disk files instead.  See L<Pod::Parser> for the specific
674
details.
675
 
676
=head1 DIAGNOSTICS
677
 
678
=over 4
679
 
680
=item Bizarre space in item
681
 
682
(W) Something has gone wrong in internal C<=item> processing.  This message
683
indicates a bug in Pod::PlainText; you should never see it.
684
 
685
=item Can't open %s for reading: %s
686
 
687
(F) Pod::PlainText was invoked via the compatibility mode pod2text() interface
688
and the input file it was given could not be opened.
689
 
690
=item Unknown escape: %s
691
 
692
(W) The POD source contained an C<EE<lt>E<gt>> escape that Pod::PlainText didn't
693
know about.
694
 
695
=item Unknown sequence: %s
696
 
697
(W) The POD source contained a non-standard internal sequence (something of
698
the form C<XE<lt>E<gt>>) that Pod::PlainText didn't know about.
699
 
700
=item Unmatched =back
701
 
702
(W) Pod::PlainText encountered a C<=back> command that didn't correspond to an
703
C<=over> command.
704
 
705
=back
706
 
707
=head1 RESTRICTIONS
708
 
709
Embedded Ctrl-As (octal 001) in the input will be mapped to spaces on
710
output, due to an internal implementation detail.
711
 
712
=head1 NOTES
713
 
714
This is a replacement for an earlier Pod::Text module written by Tom
715
Christiansen.  It has a revamped interface, since it now uses Pod::Parser,
716
but an interface roughly compatible with the old Pod::Text::pod2text()
717
function is still available.  Please change to the new calling convention,
718
though.
719
 
720
The original Pod::Text contained code to do formatting via termcap
721
sequences, although it wasn't turned on by default and it was problematic to
722
get it to work at all.  This rewrite doesn't even try to do that, but a
723
subclass of it does.  Look for L<Pod::Text::Termcap|Pod::Text::Termcap>.
724
 
725
=head1 SEE ALSO
726
 
727
L<Pod::Parser|Pod::Parser>, L<Pod::Text::Termcap|Pod::Text::Termcap>,
728
pod2text(1)
729
 
730
=head1 AUTHOR
731
 
732
Please report bugs using L<http://rt.cpan.org>.
733
 
734
Russ Allbery E<lt>rra@stanford.eduE<gt>, based I<very> heavily on the
735
original Pod::Text by Tom Christiansen E<lt>tchrist@mox.perl.comE<gt> and
736
its conversion to Pod::Parser by Brad Appleton
737
E<lt>bradapp@enteract.comE<gt>.
738
 
739
=cut