5 Pod::Text - convert POD data to formatted ASCII text
11 pod2text("perlfunc.pod");
15 pod2text [B<-a>] [B<->I<width>] < input.pod
19 Pod::Text is a module that can convert documentation in the POD format (such
20 as can be found throughout the Perl distribution) into formatted ASCII.
21 Termcap is optionally supported for boldface/underline, and can enabled via
22 C<$Pod::Text::termcap=1>. If termcap has not been enabled, then backspaces
23 will be used to simulate bold and underlined text.
25 A separate F<pod2text> program is included that is primarily a wrapper for
28 The single function C<pod2text()> can take the optional options B<-a>
29 for an alternative output format, then a B<->I<width> option with the
30 max terminal width, followed by 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);
52 use vars qw($VERSION);
55 use locale; # make \w work right in non-ASCII lands
69 shift if $opt_alt_format = ($_[0] eq '-a');
71 if($termcap and !$setuptermcap) {
74 my($term) = Tgetent Term::Cap { TERM => undef, OSPEED => 9600 };
75 $UNDL = $term->{'_us'};
76 $INV = $term->{'_mr'};
77 $BOLD = $term->{'_md'};
78 $NORM = $term->{'_me'};
81 $SCREEN = ($_[0] =~ /^-(\d+)/ && (shift, $1))
83 || ($ENV{TERMCAP} =~ /co#(\d+)/)[0]
84 || ($^O ne 'MSWin32' && $^O ne 'dos' && (`stty -a 2>/dev/null` =~ /(\d+) columns/)[0])
87 @_ = ("<&STDIN") unless @_;
88 local($file,*OUTPUT) = @_;
89 *OUTPUT = *STDOUT if @_<2;
92 $: = " \n" if $opt_alt_format; # Do not break ``-L/lib/'' into ``- L/lib/''.
100 $indent = $DEF_INDENT;
104 open(IN, $file) || die "Couldn't open $file: $!";
106 POD_DIRECTIVE: while (<IN>) {
112 if (/^=end\s+$begun/) {
115 elsif ($begun eq "text") {
120 1 while s{^(.*?)(\t+)(.*)$}{
122 . (' ' x (length($2) * 8 - length($1) % 8))
125 # Translate verbatim paragraph
131 if (/^=for\s+(\S+)\s*(.*)/s) {
139 elsif (/^=begin\s+(\S+)\s*(.*)/s) {
147 sub prepare_for_output {
152 # need to hide E<> first; they're processed in clear_noremap
153 s/(E<[^<>]+>)/noremap($1)/ge;
155 while ($maxnest-- && /[A-Z]</) {
157 if ($opt_alt_format) {
158 s/[BC]<(.*?)>/``$1''/sg;
164 s/C<(.*?)>/noremap("E<lchevron>${1}E<rchevron>")/sge;
166 # s/[IF]<(.*?)>/italic($1)/ge;
168 # s/[CB]<(.*?)>/bold($1)/ge;
171 # LREF: a la HREF L<show this text|man/section>
172 s:L<([^|>]+)\|[^>]+>:$1:g;
174 # LREF: a manpage(3f)
175 s:L<([a-zA-Z][^\s\/]+)(\([^\)]+\))?>:the $1$2 manpage:g;
176 # LREF: an =item on another manpage
186 } {the "$2" entry in the $1 manpage}gx;
188 # LREF: an =item on this manpage
200 } { internal_lrefs($1) }gex;
202 # LREF: a =head2 (head1?), maybe on a manpage, maybe right here
203 # the "func" can disambiguate
213 $1 # if no $1, assume it means on this page.
214 ? "the section on \"$2\" in the $1 manpage"
215 : "the section on \"$2\""
219 s/[A-Z]<(.*?)>/$1/sg;
227 # $needspace = 0; # Assume this.
229 ($Cmd, $_) = split(' ', $_, 2);
234 elsif ($Cmd eq 'pod') {
237 elsif ($Cmd eq 'head1') {
239 if ($opt_alt_format) {
241 s/^(.+?)[ \t]*$/==== $1 ====/;
244 # print OUTPUT uc($_);
245 $needspace = $opt_alt_format;
247 elsif ($Cmd eq 'head2') {
250 #print ' ' x $DEF_INDENT, $_;
252 s/(\w)/\xA7 $1/ if $FANCY;
253 if ($opt_alt_format) {
254 s/^(.+?)[ \t]*$/== $1 ==/;
255 print OUTPUT "\n", $_;
257 print OUTPUT ' ' x ($DEF_INDENT/2), $_, "\n";
259 $needspace = $opt_alt_format;
261 elsif ($Cmd eq 'over') {
262 push(@indent,$indent);
263 $indent += ($_ + 0) || $DEF_INDENT;
265 elsif ($Cmd eq 'back') {
266 $indent = pop(@indent);
267 warn "Unmatched =back\n" unless defined $indent;
269 elsif ($Cmd eq 'item') {
271 # s/\A(\s*)\*/$1\xb7/ if $FANCY;
272 # s/^(\s*\*\s+)/$1 /;
274 if (length() + 3 < $indent) {
277 if (/^[=\s]/) { # tricked!, or verbatim paragraph
278 local($indent) = $indent[$#indent - 1] || $DEF_INDENT;
283 IP_output($paratag, $_);
285 local($indent) = $indent[$#indent - 1] || $DEF_INDENT;
291 warn "Unrecognized directive: $Cmd\n";
305 #########################################################################
316 return $line if $use_format;
318 $line = "$BOLD$line$NORM";
320 $line =~ s/(.)/$1\b$1/g;
322 # $line = "$BOLD$line$NORM" if $ansify;
328 return $line if $use_format;
330 $line = "$UNDL$line$NORM";
332 $line =~ s/(.)/$1\b_/g;
334 # $line = "$UNDL$line$NORM" if $ansify;
338 # Fill a paragraph including underlined and overstricken chars.
339 # It's not perfect for words longer than the margin, and it's probably
340 # slow, but it works.
344 my $indent_space = " " x $indent;
345 my $marg = $SCREEN-$indent;
346 my $line = $indent_space;
349 my $word_length = length;
350 $word_length -= 2 while /\010/g; # Subtract backspaces
352 if ($line_length + $word_length > $marg) {
353 $par .= $line . "\n";
354 $line= $indent_space . $_;
355 $line_length = $word_length;
362 $line_length += $word_length;
366 $par .= "$line\n" if $line;
372 local($tag, $_) = @_;
373 local($tag_indent) = $indent[$#indent - 1] || $DEF_INDENT;
374 $tag_cols = $SCREEN - $tag_indent;
375 $cols = $SCREEN - $indent;
379 $str = "format OUTPUT = \n"
380 . (($opt_alt_format && $tag_indent > 1)
381 ? ":" . " " x ($tag_indent - 1)
382 : " " x ($tag_indent))
383 . '@' . ('<' x ($indent - $tag_indent - 1))
384 . "^" . ("<" x ($cols - 1)) . "\n"
387 . (" " x ($indent-2))
388 . "^" . ("<" x ($cols - 5)) . "\n"
390 #warn $str; warn "tag is $tag, _ is $_";
396 local($_, $reformat) = @_;
398 $cols = $SCREEN - $indent;
401 $str = "format OUTPUT = \n~~"
402 . (" " x ($indent-2))
403 . "^" . ("<" x ($cols - 5)) . "\n"
408 s/^/' ' x $indent/gem;
410 s/^ /: /s if defined($reformat) && $opt_alt_format;
416 local($thing_to_hide) = shift;
417 $thing_to_hide =~ tr/\000-\177/\200-\377/;
418 return $thing_to_hide;
422 die "unmatched init" if $mapready++;
423 #mask off high bit characters in input stream
424 s/([\200-\377])/"E<".ord($1).">"/ge;
428 my $ready_to_print = $_[0];
429 die "unmatched clear" unless $mapready--;
430 tr/\200-\377/\000-\177/;
431 # now for the E<>s, which have been hidden until now
432 # otherwise the interative \w<> processing would have
433 # been hosed by the E<gt>
446 defined $HTML_Escapes{$3}
447 ? do { $HTML_Escapes{$3} }
449 warn "Unknown escape: E<$1> in $_";
453 }egx if $ready_to_print;
459 my(@items) = split( /(?:,?\s+(?:and\s+)?)/ );
462 for ($i = 0; $i <= $#items; $i++) {
463 $retstr .= "C<$items[$i]>";
464 $retstr .= ", " if @items > 2 && $i != $#items;
465 $retstr .= " and " if $i+2 == @items;
468 $retstr .= " entr" . ( @items > 1 ? "ies" : "y" )
469 . " elsewhere in this document ";
477 if (ord("\t") == 9) {
479 'amp' => '&', # ampersand
480 'lt' => '<', # left chevron, less-than
481 'gt' => '>', # right chevron, greater-than
482 'quot' => '"', # double quote
484 "Aacute" => "\xC1", # capital A, acute accent
485 "aacute" => "\xE1", # small a, acute accent
486 "Acirc" => "\xC2", # capital A, circumflex accent
487 "acirc" => "\xE2", # small a, circumflex accent
488 "AElig" => "\xC6", # capital AE diphthong (ligature)
489 "aelig" => "\xE6", # small ae diphthong (ligature)
490 "Agrave" => "\xC0", # capital A, grave accent
491 "agrave" => "\xE0", # small a, grave accent
492 "Aring" => "\xC5", # capital A, ring
493 "aring" => "\xE5", # small a, ring
494 "Atilde" => "\xC3", # capital A, tilde
495 "atilde" => "\xE3", # small a, tilde
496 "Auml" => "\xC4", # capital A, dieresis or umlaut mark
497 "auml" => "\xE4", # small a, dieresis or umlaut mark
498 "Ccedil" => "\xC7", # capital C, cedilla
499 "ccedil" => "\xE7", # small c, cedilla
500 "Eacute" => "\xC9", # capital E, acute accent
501 "eacute" => "\xE9", # small e, acute accent
502 "Ecirc" => "\xCA", # capital E, circumflex accent
503 "ecirc" => "\xEA", # small e, circumflex accent
504 "Egrave" => "\xC8", # capital E, grave accent
505 "egrave" => "\xE8", # small e, grave accent
506 "ETH" => "\xD0", # capital Eth, Icelandic
507 "eth" => "\xF0", # small eth, Icelandic
508 "Euml" => "\xCB", # capital E, dieresis or umlaut mark
509 "euml" => "\xEB", # small e, dieresis or umlaut mark
510 "Iacute" => "\xCD", # capital I, acute accent
511 "iacute" => "\xED", # small i, acute accent
512 "Icirc" => "\xCE", # capital I, circumflex accent
513 "icirc" => "\xEE", # small i, circumflex accent
514 "Igrave" => "\xCD", # capital I, grave accent
515 "igrave" => "\xED", # small i, grave accent
516 "Iuml" => "\xCF", # capital I, dieresis or umlaut mark
517 "iuml" => "\xEF", # small i, dieresis or umlaut mark
518 "Ntilde" => "\xD1", # capital N, tilde
519 "ntilde" => "\xF1", # small n, tilde
520 "Oacute" => "\xD3", # capital O, acute accent
521 "oacute" => "\xF3", # small o, acute accent
522 "Ocirc" => "\xD4", # capital O, circumflex accent
523 "ocirc" => "\xF4", # small o, circumflex accent
524 "Ograve" => "\xD2", # capital O, grave accent
525 "ograve" => "\xF2", # small o, grave accent
526 "Oslash" => "\xD8", # capital O, slash
527 "oslash" => "\xF8", # small o, slash
528 "Otilde" => "\xD5", # capital O, tilde
529 "otilde" => "\xF5", # small o, tilde
530 "Ouml" => "\xD6", # capital O, dieresis or umlaut mark
531 "ouml" => "\xF6", # small o, dieresis or umlaut mark
532 "szlig" => "\xDF", # small sharp s, German (sz ligature)
533 "THORN" => "\xDE", # capital THORN, Icelandic
534 "thorn" => "\xFE", # small thorn, Icelandic
535 "Uacute" => "\xDA", # capital U, acute accent
536 "uacute" => "\xFA", # small u, acute accent
537 "Ucirc" => "\xDB", # capital U, circumflex accent
538 "ucirc" => "\xFB", # small u, circumflex accent
539 "Ugrave" => "\xD9", # capital U, grave accent
540 "ugrave" => "\xF9", # small u, grave accent
541 "Uuml" => "\xDC", # capital U, dieresis or umlaut mark
542 "uuml" => "\xFC", # small u, dieresis or umlaut mark
543 "Yacute" => "\xDD", # capital Y, acute accent
544 "yacute" => "\xFD", # small y, acute accent
545 "yuml" => "\xFF", # small y, dieresis or umlaut mark
547 "lchevron" => "\xAB", # left chevron (double less than)
548 "rchevron" => "\xBB", # right chevron (double greater than)
554 # This hash assumes code page IBM-1047:
556 'amp' => '&', # ampersand
557 'lt' => '<', # left chevron, less-than
558 'gt' => '>', # right chevron, greater-than
559 'quot' => '"', # double quote
561 "Aacute" => "\x65", # capital A, acute accent
562 "aacute" => "\x45", # small a, acute accent
563 "Acirc" => "\x62", # capital A, circumflex accent
564 "acirc" => "\x42", # small a, circumflex accent
565 "AElig" => "\x9E", # capital AE diphthong (ligature)
566 "aelig" => "\x9C", # small ae diphthong (ligature)
567 "Agrave" => "\x64", # capital A, grave accent
568 "agrave" => "\x44", # small a, grave accent
569 "Aring" => "\x67", # capital A, ring
570 "aring" => "\x47", # small a, ring
571 "Atilde" => "\x66", # capital A, tilde
572 "atilde" => "\x46", # small a, tilde
573 "Auml" => "\x63", # capital A, dieresis or umlaut mark
574 "auml" => "\x43", # small a, dieresis or umlaut mark
575 "Ccedil" => "\x68", # capital C, cedilla
576 "ccedil" => "\x48", # small c, cedilla
577 "Eacute" => "\x71", # capital E, acute accent
578 "eacute" => "\x51", # small e, acute accent
579 "Ecirc" => "\x72", # capital E, circumflex accent
580 "ecirc" => "\x52", # small e, circumflex accent
581 "Egrave" => "\x74", # capital E, grave accent
582 "egrave" => "\x54", # small e, grave accent
583 "ETH" => "\xAC", # capital Eth, Icelandic
584 "eth" => "\x8C", # small eth, Icelandic
585 "Euml" => "\x73", # capital E, dieresis or umlaut mark
586 "euml" => "\x53", # small e, dieresis or umlaut mark
587 "Iacute" => "\x75", # capital I, acute accent
588 "iacute" => "\x55", # small i, acute accent
589 "Icirc" => "\x76", # capital I, circumflex accent
590 "icirc" => "\x56", # small i, circumflex accent
591 "Igrave" => "\x75", # capital I, grave accent
592 "igrave" => "\x55", # small i, grave accent
593 "Iuml" => "\x77", # capital I, dieresis or umlaut mark
594 "iuml" => "\x57", # small i, dieresis or umlaut mark
595 "Ntilde" => "\x69", # capital N, tilde
596 "ntilde" => "\x49", # small n, tilde
597 "Oacute" => "\xEE", # capital O, acute accent
598 "oacute" => "\xCE", # small o, acute accent
599 "Ocirc" => "\xEB", # capital O, circumflex accent
600 "ocirc" => "\xCB", # small o, circumflex accent
601 "Ograve" => "\xED", # capital O, grave accent
602 "ograve" => "\xCD", # small o, grave accent
603 "Oslash" => "\x80", # capital O, slash
604 "oslash" => "\x70", # small o, slash
605 "Otilde" => "\xEF", # capital O, tilde
606 "otilde" => "\xCF", # small o, tilde
607 "Ouml" => "\xEC", # capital O, dieresis or umlaut mark
608 "ouml" => "\xCC", # small o, dieresis or umlaut mark
609 "szlig" => "\x59", # small sharp s, German (sz ligature)
610 "THORN" => "\xAE", # capital THORN, Icelandic
611 "thorn" => "\x8E", # small thorn, Icelandic
612 "Uacute" => "\xFE", # capital U, acute accent
613 "uacute" => "\xDE", # small u, acute accent
614 "Ucirc" => "\xFB", # capital U, circumflex accent
615 "ucirc" => "\xDB", # small u, circumflex accent
616 "Ugrave" => "\xFD", # capital U, grave accent
617 "ugrave" => "\xDD", # small u, grave accent
618 "Uuml" => "\xFC", # capital U, dieresis or umlaut mark
619 "uuml" => "\xDC", # small u, dieresis or umlaut mark
620 "Yacute" => "\xBA", # capital Y, acute accent
621 "yacute" => "\x8D", # small y, acute accent
622 "yuml" => "\xDF", # small y, dieresis or umlaut mark
624 "lchevron" => "\x8A", # left chevron (double less than)
625 "rchevron" => "\x8B", # right chevron (double greater than)