7 Pod::Text - convert POD data to formatted ASCII text
13 pod2text("perlfunc.pod");
21 Pod::Text is a module that can convert documentation in the POD format (such
22 as can be found throughout the Perl distribution) into formatted ASCII.
23 Termcap is optionally supported for boldface/underline, and can enabled via
24 C<$Pod::Text::termcap=1>. If termcap has not been enabled, then backspaces
25 will be used to simulate bold and underlined text.
27 A separate F<pod2text> program is included that is primarily a wrapper for
30 The single function C<pod2text()> can take one or two arguments. The first
31 should be the name of a file to read the pod from, or "E<lt>&STDIN" to read from
32 STDIN. A second argument, if provided, should be a filehandle glob where
33 output should be sent.
37 Tom Christiansen E<lt>F<tchrist@mox.perl.com>E<gt>
41 Cleanup work. The input and output locations need to be more flexible,
42 termcap shouldn't be a global variable, and the terminal speed needs to
43 be properly calculated.
50 @EXPORT = qw(pod2text);
62 local($file,*OUTPUT) = @_;
63 *OUTPUT = *STDOUT if @_<2;
65 if($termcap and !$setuptermcap) {
68 my($term) = Tgetent Term::Cap { TERM => undef, OSPEED => 9600 };
69 $UNDL = $term->{'_us'};
70 $INV = $term->{'_mr'};
71 $BOLD = $term->{'_md'};
72 $NORM = $term->{'_me'};
75 $SCREEN = ($_[0] =~ /^-(\d+)/ && (shift, $1))
76 || ($ENV{TERMCAP} =~ /co#(\d+)/)[0]
78 || (`stty -a 2>/dev/null` =~ /(\d+) columns/)[0]
87 $indent = $DEF_INDENT;
90 open(IN, $file) || die "Couldn't open $file: $!";
92 POD_DIRECTIVE: while (<IN>) {
97 1 while s{^(.*?)(\t+)(.*)$}{
99 . (' ' x (length($2) * 8 - length($1) % 8))
102 # Translate verbatim paragraph
109 sub prepare_for_output {
114 # need to hide E<> first; they're processed in clear_noremap
115 s/(E<[^<>]+>)/noremap($1)/ge;
117 while ($maxnest-- && /[A-Z]</) {
121 s/C<(.*?)>/noremap("E<lchevron>${1}E<rchevron>")/ge;
123 # s/[IF]<(.*?)>/italic($1)/ge;
125 # s/[CB]<(.*?)>/bold($1)/ge;
127 # LREF: a manpage(3f)
128 s:L<([a-zA-Z][^\s\/]+)(\([^\)]+\))?>:the $1$2 manpage:g;
129 # LREF: an =item on another manpage
139 } {the "$2" entry in the $1 manpage}gx;
141 # LREF: an =item on this manpage
153 } { internal_lrefs($1) }gex;
155 # LREF: a =head2 (head1?), maybe on a manpage, maybe right here
156 # the "func" can disambiguate
166 $1 # if no $1, assume it means on this page.
167 ? "the section on \"$2\" in the $1 manpage"
168 : "the section on \"$2\""
180 # $needspace = 0; # Assume this.
182 ($Cmd, $_) = split(' ', $_, 2);
187 elsif ($Cmd eq 'head1') {
190 # print OUTPUT uc($_);
192 elsif ($Cmd eq 'head2') {
195 #print ' ' x $DEF_INDENT, $_;
197 s/(\w)/\xA7 $1/ if $FANCY;
198 print OUTPUT ' ' x ($DEF_INDENT/2), $_, "\n";
200 elsif ($Cmd eq 'over') {
201 push(@indent,$indent);
202 $indent += ($_ + 0) || $DEF_INDENT;
204 elsif ($Cmd eq 'back') {
205 $indent = pop(@indent);
206 warn "Unmatched =back\n" unless defined $indent;
209 elsif ($Cmd eq 'item') {
211 # s/\A(\s*)\*/$1\xb7/ if $FANCY;
212 # s/^(\s*\*\s+)/$1 /;
214 if (length() + 3 < $indent) {
217 if (/^=/) { # tricked!
218 local($indent) = $indent[$#index - 1] || $DEF_INDENT;
223 IP_output($paratag, $_);
225 local($indent) = $indent[$#index - 1] || $DEF_INDENT;
231 warn "Unrecognized directive: $Cmd\n";
245 #########################################################################
256 return $line if $use_format;
258 $line = "$BOLD$line$NORM";
260 $line =~ s/(.)/$1\b$1/g;
262 # $line = "$BOLD$line$NORM" if $ansify;
268 return $line if $use_format;
270 $line = "$UNDL$line$NORM";
272 $line =~ s/(.)/$1\b_/g;
274 # $line = "$UNDL$line$NORM" if $ansify;
278 # Fill a paragraph including underlined and overstricken chars.
279 # It's not perfect for words longer than the margin, and it's probably
280 # slow, but it works.
284 my $indent_space = " " x $indent;
285 my $marg = $SCREEN-$indent;
286 my $line = $indent_space;
289 my $word_length = length;
290 $word_length -= 2 while /\010/g; # Subtract backspaces
292 if ($line_length + $word_length > $marg) {
293 $par .= $line . "\n";
294 $line= $indent_space . $_;
295 $line_length = $word_length;
302 $line_length += $word_length;
306 $par .= "$line\n" if $line;
312 local($tag, $_) = @_;
313 local($tag_indent) = $indent[$#index - 1] || $DEF_INDENT;
314 $tag_cols = $SCREEN - $tag_indent;
315 $cols = $SCREEN - $indent;
319 $str = "format OUTPUT = \n"
320 . (" " x ($tag_indent))
321 . '@' . ('<' x ($indent - $tag_indent - 1))
322 . "^" . ("<" x ($cols - 1)) . "\n"
325 . (" " x ($indent-2))
326 . "^" . ("<" x ($cols - 5)) . "\n"
328 #warn $str; warn "tag is $tag, _ is $_";
334 local($_, $reformat) = @_;
336 $cols = $SCREEN - $indent;
339 $str = "format OUTPUT = \n~~"
340 . (" " x ($indent-2))
341 . "^" . ("<" x ($cols - 5)) . "\n"
346 s/^/' ' x $indent/gem;
353 local($thing_to_hide) = shift;
354 $thing_to_hide =~ tr/\000-\177/\200-\377/;
355 return $thing_to_hide;
359 die "unmatched init" if $mapready++;
360 #mask off high bit characters in input stream
361 s/([\200-\377])/"E<".ord($1).">"/ge;
365 my $ready_to_print = $_[0];
366 die "unmatched clear" unless $mapready--;
367 tr/\200-\377/\000-\177/;
368 # now for the E<>s, which have been hidden until now
369 # otherwise the interative \w<> processing would have
370 # been hosed by the E<gt>
383 defined $HTML_Escapes{$3}
384 ? do { $HTML_Escapes{$3} }
386 warn "Unknown escape: $& in $_";
390 }egx if $ready_to_print;
396 my(@items) = split( /(?:,?\s+(?:and\s+)?)/ );
399 for ($i = 0; $i <= $#items; $i++) {
400 $retstr .= "C<$items[$i]>";
401 $retstr .= ", " if @items > 2 && $i != $#items;
402 $retstr .= " and " if $i+2 == @items;
405 $retstr .= " entr" . ( @items > 1 ? "ies" : "y" )
406 . " elsewhere in this document ";
415 'amp' => '&', # ampersand
416 'lt' => '<', # left chevron, less-than
417 'gt' => '>', # right chevron, greater-than
418 'quot' => '"', # double quote
420 "Aacute" => "\xC1", # capital A, acute accent
421 "aacute" => "\xE1", # small a, acute accent
422 "Acirc" => "\xC2", # capital A, circumflex accent
423 "acirc" => "\xE2", # small a, circumflex accent
424 "AElig" => "\xC6", # capital AE diphthong (ligature)
425 "aelig" => "\xE6", # small ae diphthong (ligature)
426 "Agrave" => "\xC0", # capital A, grave accent
427 "agrave" => "\xE0", # small a, grave accent
428 "Aring" => "\xC5", # capital A, ring
429 "aring" => "\xE5", # small a, ring
430 "Atilde" => "\xC3", # capital A, tilde
431 "atilde" => "\xE3", # small a, tilde
432 "Auml" => "\xC4", # capital A, dieresis or umlaut mark
433 "auml" => "\xE4", # small a, dieresis or umlaut mark
434 "Ccedil" => "\xC7", # capital C, cedilla
435 "ccedil" => "\xE7", # small c, cedilla
436 "Eacute" => "\xC9", # capital E, acute accent
437 "eacute" => "\xE9", # small e, acute accent
438 "Ecirc" => "\xCA", # capital E, circumflex accent
439 "ecirc" => "\xEA", # small e, circumflex accent
440 "Egrave" => "\xC8", # capital E, grave accent
441 "egrave" => "\xE8", # small e, grave accent
442 "ETH" => "\xD0", # capital Eth, Icelandic
443 "eth" => "\xF0", # small eth, Icelandic
444 "Euml" => "\xCB", # capital E, dieresis or umlaut mark
445 "euml" => "\xEB", # small e, dieresis or umlaut mark
446 "Iacute" => "\xCD", # capital I, acute accent
447 "iacute" => "\xED", # small i, acute accent
448 "Icirc" => "\xCE", # capital I, circumflex accent
449 "icirc" => "\xEE", # small i, circumflex accent
450 "Igrave" => "\xCD", # capital I, grave accent
451 "igrave" => "\xED", # small i, grave accent
452 "Iuml" => "\xCF", # capital I, dieresis or umlaut mark
453 "iuml" => "\xEF", # small i, dieresis or umlaut mark
454 "Ntilde" => "\xD1", # capital N, tilde
455 "ntilde" => "\xF1", # small n, tilde
456 "Oacute" => "\xD3", # capital O, acute accent
457 "oacute" => "\xF3", # small o, acute accent
458 "Ocirc" => "\xD4", # capital O, circumflex accent
459 "ocirc" => "\xF4", # small o, circumflex accent
460 "Ograve" => "\xD2", # capital O, grave accent
461 "ograve" => "\xF2", # small o, grave accent
462 "Oslash" => "\xD8", # capital O, slash
463 "oslash" => "\xF8", # small o, slash
464 "Otilde" => "\xD5", # capital O, tilde
465 "otilde" => "\xF5", # small o, tilde
466 "Ouml" => "\xD6", # capital O, dieresis or umlaut mark
467 "ouml" => "\xF6", # small o, dieresis or umlaut mark
468 "szlig" => "\xDF", # small sharp s, German (sz ligature)
469 "THORN" => "\xDE", # capital THORN, Icelandic
470 "thorn" => "\xFE", # small thorn, Icelandic
471 "Uacute" => "\xDA", # capital U, acute accent
472 "uacute" => "\xFA", # small u, acute accent
473 "Ucirc" => "\xDB", # capital U, circumflex accent
474 "ucirc" => "\xFB", # small u, circumflex accent
475 "Ugrave" => "\xD9", # capital U, grave accent
476 "ugrave" => "\xF9", # small u, grave accent
477 "Uuml" => "\xDC", # capital U, dieresis or umlaut mark
478 "uuml" => "\xFC", # small u, dieresis or umlaut mark
479 "Yacute" => "\xDD", # capital Y, acute accent
480 "yacute" => "\xFD", # small y, acute accent
481 "yuml" => "\xFF", # small y, dieresis or umlaut mark
483 "lchevron" => "\xAB", # left chevron (double less than)
484 "rchevron" => "\xBB", # right chevron (double greater than)