1
2require 5;
3package Pod::Simple::RTF;
4
5#sub DEBUG () {4};
6#sub Pod::Simple::DEBUG () {4};
7#sub Pod::Simple::PullParser::DEBUG () {4};
8
9use strict;
10use vars qw($VERSION @ISA %Escape $WRAP %Tagmap);
11$VERSION = '3.20';
12use Pod::Simple::PullParser ();
13BEGIN {@ISA = ('Pod::Simple::PullParser')}
14
15use Carp ();
16BEGIN { *DEBUG = \&Pod::Simple::DEBUG unless defined &DEBUG }
17
18$WRAP = 1 unless defined $WRAP;
19
20#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21
22sub _openclose {
23 return map {;
24   m/^([-A-Za-z]+)=(\w[^\=]*)$/s or die "what's <$_>?";
25   ( $1,  "{\\$2\n",   "/$1",  "}" );
26 } @_;
27}
28
29my @_to_accept;
30
31%Tagmap = (
32 # 'foo=bar' means ('foo' => '{\bar'."\n", '/foo' => '}')
33 _openclose(
34  'B=cs18\b',
35  'I=cs16\i',
36  'C=cs19\f1\lang1024\noproof',
37  'F=cs17\i\lang1024\noproof',
38
39  'VerbatimI=cs26\i',
40  'VerbatimB=cs27\b',
41  'VerbatimBI=cs28\b\i',
42
43  map {; m/^([-a-z]+)/s && push @_to_accept, $1; $_ }
44   qw[
45       underline=ul         smallcaps=scaps  shadow=shad
46       superscript=super    subscript=sub    strikethrough=strike
47       outline=outl         emboss=embo      engrave=impr
48       dotted-underline=uld          dash-underline=uldash
49       dot-dash-underline=uldashd    dot-dot-dash-underline=uldashdd
50       double-underline=uldb         thick-underline=ulth
51       word-underline=ulw            wave-underline=ulwave
52   ]
53   # But no double-strikethrough, because MSWord can't agree with the
54   #  RTF spec on whether it's supposed to be \strikedl or \striked1 (!!!)
55 ),
56
57 # Bit of a hack here:
58 'L=pod' => '{\cs22\i'."\n",
59 'L=url' => '{\cs23\i'."\n",
60 'L=man' => '{\cs24\i'."\n",
61 '/L' => '}',
62
63 'Data'  => "\n",
64 '/Data' => "\n",
65
66 'Verbatim'  => "\n{\\pard\\li#rtfindent##rtfkeep#\\plain\\s20\\sa180\\f1\\fs18\\lang1024\\noproof\n",
67 '/Verbatim' => "\n\\par}\n",
68 'VerbatimFormatted'  => "\n{\\pard\\li#rtfindent##rtfkeep#\\plain\\s20\\sa180\\f1\\fs18\\lang1024\\noproof\n",
69 '/VerbatimFormatted' => "\n\\par}\n",
70 'Para'    => "\n{\\pard\\li#rtfindent#\\sa180\n",
71 '/Para'   => "\n\\par}\n",
72 'head1'   => "\n{\\pard\\li#rtfindent#\\s31\\keepn\\sb90\\sa180\\f2\\fs#head1_halfpoint_size#\\ul{\n",
73 '/head1'  => "\n}\\par}\n",
74 'head2'   => "\n{\\pard\\li#rtfindent#\\s32\\keepn\\sb90\\sa180\\f2\\fs#head2_halfpoint_size#\\ul{\n",
75 '/head2'  => "\n}\\par}\n",
76 'head3'   => "\n{\\pard\\li#rtfindent#\\s33\\keepn\\sb90\\sa180\\f2\\fs#head3_halfpoint_size#\\ul{\n",
77 '/head3'  => "\n}\\par}\n",
78 'head4'   => "\n{\\pard\\li#rtfindent#\\s34\\keepn\\sb90\\sa180\\f2\\fs#head4_halfpoint_size#\\ul{\n",
79 '/head4'  => "\n}\\par}\n",
80   # wordpad borks on \tc\tcl1, or I'd put that in =head1 and =head2
81
82 'item-bullet'  => "\n{\\pard\\li#rtfindent##rtfitemkeepn#\\sb60\\sa150\\fi-120\n",
83 '/item-bullet' => "\n\\par}\n",
84 'item-number'  => "\n{\\pard\\li#rtfindent##rtfitemkeepn#\\sb60\\sa150\\fi-120\n",
85 '/item-number' => "\n\\par}\n",
86 'item-text'    => "\n{\\pard\\li#rtfindent##rtfitemkeepn#\\sb60\\sa150\\fi-120\n",
87 '/item-text'   => "\n\\par}\n",
88
89 # we don't need any styles for over-* and /over-*
90);
91
92
93#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
94sub new {
95  my $new = shift->SUPER::new(@_);
96  $new->nix_X_codes(1);
97  $new->nbsp_for_S(1);
98  $new->accept_targets( 'rtf', 'RTF' );
99
100  $new->{'Tagmap'} = {%Tagmap};
101
102  $new->accept_codes(@_to_accept);
103  $new->accept_codes('VerbatimFormatted');
104  DEBUG > 2 and print "To accept: ", join(' ',@_to_accept), "\n";
105  $new->doc_lang(
106    (  $ENV{'RTFDEFLANG'} || '') =~ m/^(\d{1,10})$/s ? $1
107    : ($ENV{'RTFDEFLANG'} || '') =~ m/^0?x([a-fA-F0-9]{1,10})$/s ? hex($1)
108                                      # yes, tolerate hex!
109    : ($ENV{'RTFDEFLANG'} || '') =~ m/^([a-fA-F0-9]{4})$/s ? hex($1)
110                                      # yes, tolerate even more hex!
111    : '1033'
112  );
113
114  $new->head1_halfpoint_size(32);
115  $new->head2_halfpoint_size(28);
116  $new->head3_halfpoint_size(25);
117  $new->head4_halfpoint_size(22);
118  $new->codeblock_halfpoint_size(18);
119  $new->header_halfpoint_size(17);
120  $new->normal_halfpoint_size(25);
121
122  return $new;
123}
124
125#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
126
127__PACKAGE__->_accessorize(
128 'doc_lang',
129 'head1_halfpoint_size',
130 'head2_halfpoint_size',
131 'head3_halfpoint_size',
132 'head4_halfpoint_size',
133 'codeblock_halfpoint_size',
134 'header_halfpoint_size',
135 'normal_halfpoint_size',
136 'no_proofing_exemptions',
137);
138
139
140#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
141sub run {
142  my $self = $_[0];
143  return $self->do_middle if $self->bare_output;
144  return
145   $self->do_beginning && $self->do_middle && $self->do_end;
146}
147
148
149#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
150
151sub do_middle {      # the main work
152  my $self = $_[0];
153  my $fh = $self->{'output_fh'};
154
155  my($token, $type, $tagname, $scratch);
156  my @stack;
157  my @indent_stack;
158  $self->{'rtfindent'} = 0 unless defined $self->{'rtfindent'};
159
160  while($token = $self->get_token) {
161
162    if( ($type = $token->type) eq 'text' ) {
163      if( $self->{'rtfverbatim'} ) {
164        DEBUG > 1 and print "  $type " , $token->text, " in verbatim!\n";
165        rtf_esc_codely($scratch = $token->text);
166        print $fh $scratch;
167        next;
168      }
169
170      DEBUG > 1 and print "  $type " , $token->text, "\n";
171
172      $scratch = $token->text;
173      $scratch =~ tr/\t\cb\cc/ /d;
174
175      $self->{'no_proofing_exemptions'} or $scratch =~
176       s/(?:
177           ^
178           |
179           (?<=[\cm\cj\t "\[\<\(])
180         )   # start on whitespace, sequence-start, or quote
181         ( # something looking like a Perl token:
182          (?:
183           [\$\@\:\<\*\\_]\S+  # either starting with a sigil, etc.
184          )
185          |
186          # or starting alpha, but containing anything strange:
187          (?:
188           [a-zA-Z'\x80-\xFF]+[\$\@\:_<>\(\\\*]\S+
189          )
190         )
191        /\cb$1\cc/xsg
192      ;
193
194      rtf_esc($scratch);
195      $scratch =~
196         s/(
197            [^\cm\cj\n]{65}        # Snare 65 characters from a line
198            [^\cm\cj\n\x20]{0,50}  #  and finish any current word
199           )
200           (\x20{1,10})(?![\cm\cj\n]) # capture some spaces not at line-end
201          /$1$2\n/gx     # and put a NL before those spaces
202        if $WRAP;
203        # This may wrap at well past the 65th column, but not past the 120th.
204
205      print $fh $scratch;
206
207    } elsif( $type eq 'start' ) {
208      DEBUG > 1 and print "  +$type ",$token->tagname,
209        " (", map("<$_> ", %{$token->attr_hash}), ")\n";
210
211      if( ($tagname = $token->tagname) eq 'Verbatim'
212          or $tagname eq 'VerbatimFormatted'
213      ) {
214        ++$self->{'rtfverbatim'};
215        my $next = $self->get_token;
216        next unless defined $next;
217        my $line_count = 1;
218        if($next->type eq 'text') {
219          my $t = $next->text_r;
220          while( $$t =~ m/$/mg ) {
221            last if  ++$line_count  > 15; # no point in counting further
222          }
223          DEBUG > 3 and print "    verbatim line count: $line_count\n";
224        }
225        $self->unget_token($next);
226        $self->{'rtfkeep'} = ($line_count > 15) ? '' : '\keepn' ;
227
228      } elsif( $tagname =~ m/^item-/s ) {
229        my @to_unget;
230        my $text_count_here = 0;
231        $self->{'rtfitemkeepn'} = '';
232        # Some heuristics to stop item-*'s functioning as subheadings
233        #  from getting split from the things they're subheadings for.
234        #
235        # It's not terribly pretty, but it really does make things pretty.
236        #
237        while(1) {
238          push @to_unget, $self->get_token;
239          pop(@to_unget), last unless defined $to_unget[-1];
240           # Erroneously used to be "unshift" instead of pop!  Adds instead
241           # of removes, and operates on the beginning instead of the end!
242
243          if($to_unget[-1]->type eq 'text') {
244            if( ($text_count_here += length ${$to_unget[-1]->text_r}) > 150 ){
245              DEBUG > 1 and print "    item-* is too long to be keepn'd.\n";
246              last;
247            }
248          } elsif (@to_unget > 1 and
249            $to_unget[-2]->type eq 'end' and
250            $to_unget[-2]->tagname =~ m/^item-/s
251          ) {
252            # Bail out here, after setting rtfitemkeepn yea or nay.
253            $self->{'rtfitemkeepn'} = '\keepn' if
254              $to_unget[-1]->type eq 'start' and
255              $to_unget[-1]->tagname eq 'Para';
256
257            DEBUG > 1 and printf "    item-* before %s(%s) %s keepn'd.\n",
258              $to_unget[-1]->type,
259              $to_unget[-1]->can('tagname') ? $to_unget[-1]->tagname : '',
260              $self->{'rtfitemkeepn'} ? "gets" : "doesn't get";
261            last;
262          } elsif (@to_unget > 40) {
263            DEBUG > 1 and print "    item-* now has too many tokens (",
264              scalar(@to_unget),
265              (DEBUG > 4) ? (q<: >, map($_->dump, @to_unget)) : (),
266              ") to be keepn'd.\n";
267            last; # give up
268          }
269          # else keep while'ing along
270        }
271        # Now put it aaaaall back...
272        $self->unget_token(@to_unget);
273
274      } elsif( $tagname =~ m/^over-/s ) {
275        push @stack, $1;
276        push @indent_stack,
277         int($token->attr('indent') * 4 * $self->normal_halfpoint_size);
278        DEBUG and print "Indenting over $indent_stack[-1] twips.\n";
279        $self->{'rtfindent'} += $indent_stack[-1];
280
281      } elsif ($tagname eq 'L') {
282        $tagname .= '=' . ($token->attr('type') || 'pod');
283
284      } elsif ($tagname eq 'Data') {
285        my $next = $self->get_token;
286        next unless defined $next;
287        unless( $next->type eq 'text' ) {
288          $self->unget_token($next);
289          next;
290        }
291        DEBUG and print "    raw text ", $next->text, "\n";
292        printf $fh "\n" . $next->text . "\n";
293        next;
294      }
295
296      defined($scratch = $self->{'Tagmap'}{$tagname}) or next;
297      $scratch =~ s/\#([^\#]+)\#/${$self}{$1}/g; # interpolate
298      print $fh $scratch;
299
300      if ($tagname eq 'item-number') {
301        print $fh $token->attr('number'), ". \n";
302      } elsif ($tagname eq 'item-bullet') {
303        print $fh "\\'95 \n";
304        #for funky testing: print $fh '', rtf_esc("\x{4E4B}\x{9053}");
305      }
306
307    } elsif( $type eq 'end' ) {
308      DEBUG > 1 and print "  -$type ",$token->tagname,"\n";
309      if( ($tagname = $token->tagname) =~ m/^over-/s ) {
310        DEBUG and print "Indenting back $indent_stack[-1] twips.\n";
311        $self->{'rtfindent'} -= pop @indent_stack;
312        pop @stack;
313      } elsif( $tagname eq 'Verbatim' or $tagname eq 'VerbatimFormatted') {
314        --$self->{'rtfverbatim'};
315      }
316      defined($scratch = $self->{'Tagmap'}{"/$tagname"}) or next;
317      $scratch =~ s/\#([^\#]+)\#/${$self}{$1}/g; # interpolate
318      print $fh $scratch;
319    }
320  }
321  return 1;
322}
323
324#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
325sub do_beginning {
326  my $self = $_[0];
327  my $fh = $self->{'output_fh'};
328  return print $fh join '',
329    $self->doc_init,
330    $self->font_table,
331    $self->stylesheet,
332    $self->color_table,
333    $self->doc_info,
334    $self->doc_start,
335    "\n"
336  ;
337}
338
339sub do_end {
340  my $self = $_[0];
341  my $fh = $self->{'output_fh'};
342  return print $fh '}'; # that should do it
343}
344
345###########################################################################
346
347sub stylesheet {
348  return sprintf <<'END',
349{\stylesheet
350{\snext0 Normal;}
351{\*\cs10 \additive Default Paragraph Font;}
352{\*\cs16 \additive \i \sbasedon10 pod-I;}
353{\*\cs17 \additive \i\lang1024\noproof \sbasedon10 pod-F;}
354{\*\cs18 \additive \b \sbasedon10 pod-B;}
355{\*\cs19 \additive \f1\lang1024\noproof\sbasedon10 pod-C;}
356{\s20\ql \li0\ri0\sa180\widctlpar\f1\fs%s\lang1024\noproof\sbasedon0 \snext0 pod-codeblock;}
357{\*\cs21 \additive \lang1024\noproof \sbasedon10 pod-computerese;}
358{\*\cs22 \additive \i\lang1024\noproof\sbasedon10 pod-L-pod;}
359{\*\cs23 \additive \i\lang1024\noproof\sbasedon10 pod-L-url;}
360{\*\cs24 \additive \i\lang1024\noproof\sbasedon10 pod-L-man;}
361
362{\*\cs25 \additive \f1\lang1024\noproof\sbasedon0 pod-codelbock-plain;}
363{\*\cs26 \additive \f1\lang1024\noproof\sbasedon25 pod-codelbock-ital;}
364{\*\cs27 \additive \f1\lang1024\noproof\sbasedon25 pod-codelbock-bold;}
365{\*\cs28 \additive \f1\lang1024\noproof\sbasedon25 pod-codelbock-bold-ital;}
366
367{\s31\ql \keepn\sb90\sa180\f2\fs%s\ul\sbasedon0 \snext0 pod-head1;}
368{\s32\ql \keepn\sb90\sa180\f2\fs%s\ul\sbasedon0 \snext0 pod-head2;}
369{\s33\ql \keepn\sb90\sa180\f2\fs%s\ul\sbasedon0 \snext0 pod-head3;}
370{\s34\ql \keepn\sb90\sa180\f2\fs%s\ul\sbasedon0 \snext0 pod-head4;}
371}
372
373END
374
375   $_[0]->codeblock_halfpoint_size(),
376   $_[0]->head1_halfpoint_size(),
377   $_[0]->head2_halfpoint_size(),
378   $_[0]->head3_halfpoint_size(),
379   $_[0]->head4_halfpoint_size(),
380  ;
381}
382
383###########################################################################
384# Override these as necessary for further customization
385
386sub font_table {
387  return <<'END';  # text font, code font, heading font
388{\fonttbl
389{\f0\froman Times New Roman;}
390{\f1\fmodern Courier New;}
391{\f2\fswiss Arial;}
392}
393
394END
395}
396
397sub doc_init {
398   return <<'END';
399{\rtf1\ansi\deff0
400
401END
402}
403
404sub color_table {
405   return <<'END';
406{\colortbl;\red255\green0\blue0;\red0\green0\blue255;}
407END
408}
409
410
411sub doc_info {
412   my $self = $_[0];
413
414   my $class = ref($self) || $self;
415
416   my $tag = __PACKAGE__ . ' ' . $VERSION;
417
418   unless($class eq __PACKAGE__) {
419     $tag = " ($tag)";
420     $tag = " v" . $self->VERSION . $tag   if   defined $self->VERSION;
421     $tag = $class . $tag;
422   }
423
424   return sprintf <<'END',
425{\info{\doccomm
426%s
427 using %s v%s
428 under Perl v%s at %s GMT}
429{\author [see doc]}{\company [see doc]}{\operator [see doc]}
430}
431
432END
433
434  # None of the following things should need escaping, I dare say!
435    $tag,
436    $ISA[0], $ISA[0]->VERSION(),
437    $], scalar(gmtime),
438  ;
439}
440
441sub doc_start {
442  my $self = $_[0];
443  my $title = $self->get_short_title();
444  DEBUG and print "Short Title: <$title>\n";
445  $title .= ' ' if length $title;
446
447  $title =~ s/ *$/ /s;
448  $title =~ s/^ //s;
449  $title =~ s/ $/, /s;
450   # make sure it ends in a comma and a space, unless it's 0-length
451
452  my $is_obviously_module_name;
453  $is_obviously_module_name = 1
454   if $title =~ m/^\S+$/s and $title =~ m/::/s;
455    # catches the most common case, at least
456
457  DEBUG and print "Title0: <$title>\n";
458  $title = rtf_esc($title);
459  DEBUG and print "Title1: <$title>\n";
460  $title = '\lang1024\noproof ' . $title
461   if $is_obviously_module_name;
462
463  return sprintf <<'END',
464\deflang%s\plain\lang%s\widowctrl
465{\header\pard\qr\plain\f2\fs%s
466%s
467p.\chpgn\par}
468\fs%s
469
470END
471    ($self->doc_lang) x 2,
472    $self->header_halfpoint_size,
473    $title,
474    $self->normal_halfpoint_size,
475  ;
476}
477
478#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
479#-------------------------------------------------------------------------
480
481use integer;
482sub rtf_esc {
483  my $x; # scratch
484  if(!defined wantarray) { # void context: alter in-place!
485    for(@_) {
486      s/([F\x00-\x1F\-\\\{\}\x7F-\xFF])/$Escape{$1}/g;  # ESCAPER
487      s/([^\x00-\xFF])/'\\uc1\\u'.((ord($1)<32768)?ord($1):(ord($1)-65536)).'?'/eg;
488    }
489    return;
490  } elsif(wantarray) {  # return an array
491    return map {; ($x = $_) =~
492      s/([F\x00-\x1F\-\\\{\}\x7F-\xFF])/$Escape{$1}/g;  # ESCAPER
493      $x =~ s/([^\x00-\xFF])/'\\uc1\\u'.((ord($1)<32768)?ord($1):(ord($1)-65536)).'?'/eg;
494      $x;
495    } @_;
496  } else { # return a single scalar
497    ($x = ((@_ == 1) ? $_[0] : join '', @_)
498    ) =~ s/([F\x00-\x1F\-\\\{\}\x7F-\xFF])/$Escape{$1}/g;  # ESCAPER
499             # Escape \, {, }, -, control chars, and 7f-ff.
500    $x =~ s/([^\x00-\xFF])/'\\uc1\\u'.((ord($1)<32768)?ord($1):(ord($1)-65536)).'?'/eg;
501    return $x;
502  }
503}
504
505sub rtf_esc_codely {
506  # Doesn't change "-" to hard-hyphen, nor apply computerese style-smarts.
507  # We don't want to change the "-" to hard-hyphen, because we want to
508  #  be able to paste this into a file and run it without there being
509  #  dire screaming about the mysterious hard-hyphen character (which
510  #  looks just like a normal dash character).
511
512  my $x; # scratch
513  if(!defined wantarray) { # void context: alter in-place!
514    for(@_) {
515      s/([F\x00-\x1F\\\{\}\x7F-\xFF])/$Escape{$1}/g;  # ESCAPER
516      s/([^\x00-\xFF])/'\\uc1\\u'.((ord($1)<32768)?ord($1):(ord($1)-65536)).'?'/eg;
517    }
518    return;
519  } elsif(wantarray) {  # return an array
520    return map {; ($x = $_) =~
521      s/([F\x00-\x1F\\\{\}\x7F-\xFF])/$Escape{$1}/g;  # ESCAPER
522      $x =~ s/([^\x00-\xFF])/'\\uc1\\u'.((ord($1)<32768)?ord($1):(ord($1)-65536)).'?'/eg;
523      $x;
524    } @_;
525  } else { # return a single scalar
526    ($x = ((@_ == 1) ? $_[0] : join '', @_)
527    ) =~ s/([F\x00-\x1F\\\{\}\x7F-\xFF])/$Escape{$1}/g;  # ESCAPER
528             # Escape \, {, }, -, control chars, and 7f-ff.
529    $x =~ s/([^\x00-\xFF])/'\\uc1\\u'.((ord($1)<32768)?ord($1):(ord($1)-65536)).'?'/eg;
530    return $x;
531  }
532}
533
534%Escape = (
535  map( (chr($_),chr($_)),       # things not apparently needing escaping
536       0x20 .. 0x7E ),
537  map( (chr($_),sprintf("\\'%02x", $_)),    # apparently escapeworthy things
538       0x00 .. 0x1F, 0x5c, 0x7b, 0x7d, 0x7f .. 0xFF, 0x46),
539
540  # We get to escape out 'F' so that we can send RTF files thru the mail
541  # without the slightest worry that paragraphs beginning with "From"
542  # will get munged.
543
544  # And some refinements:
545  "\cm"  => "\n",
546  "\cj"  => "\n",
547  "\n"   => "\n\\line ",
548
549  "\t"   => "\\tab ",     # Tabs (altho theoretically raw \t's are okay)
550  "\f"   => "\n\\page\n", # Formfeed
551  "-"    => "\\_",        # Turn plaintext '-' into a non-breaking hyphen
552  "\xA0" => "\\~",        # Latin-1 non-breaking space
553  "\xAD" => "\\-",        # Latin-1 soft (optional) hyphen
554
555  # CRAZY HACKS:
556  "\n" => "\\line\n",
557  "\r" => "\n",
558  "\cb" => "{\n\\cs21\\lang1024\\noproof ",  # \\cf1
559  "\cc" => "}",
560);
5611;
562
563__END__
564
565=head1 NAME
566
567Pod::Simple::RTF -- format Pod as RTF
568
569=head1 SYNOPSIS
570
571  perl -MPod::Simple::RTF -e \
572   "exit Pod::Simple::RTF->filter(shift)->any_errata_seen" \
573   thingy.pod > thingy.rtf
574
575=head1 DESCRIPTION
576
577This class is a formatter that takes Pod and renders it as RTF, good for
578viewing/printing in MSWord, WordPad/write.exe, TextEdit, etc.
579
580This is a subclass of L<Pod::Simple> and inherits all its methods.
581
582=head1 FORMAT CONTROL ATTRIBUTES
583
584You can set these attributes on the parser object before you
585call C<parse_file> (or a similar method) on it:
586
587=over
588
589=item $parser->head1_halfpoint_size( I<halfpoint_integer> );
590
591=item $parser->head2_halfpoint_size( I<halfpoint_integer> );
592
593=item $parser->head3_halfpoint_size( I<halfpoint_integer> );
594
595=item $parser->head4_halfpoint_size( I<halfpoint_integer> );
596
597These methods set the size (in half-points, like 52 for 26-point)
598that these heading levels will appear as.
599
600=item $parser->codeblock_halfpoint_size( I<halfpoint_integer> );
601
602This method sets the size (in half-points, like 21 for 10.5-point)
603that codeblocks ("verbatim sections") will appear as.
604
605=item $parser->header_halfpoint_size( I<halfpoint_integer> );
606
607This method sets the size (in half-points, like 15 for 7.5-point)
608that the header on each page will appear in.  The header
609is usually just "I<modulename> p. I<pagenumber>".
610
611=item $parser->normal_halfpoint_size( I<halfpoint_integer> );
612
613This method sets the size (in half-points, like 26 for 13-point)
614that normal paragraphic text will appear in.
615
616=item $parser->no_proofing_exemptions( I<true_or_false> );
617
618Set this value to true if you don't want the formatter to try
619putting a hidden code on all Perl symbols (as best as it can
620notice them) that labels them as being not in English, and
621so not worth spellchecking.
622
623=item $parser->doc_lang( I<microsoft_decimal_language_code> )
624
625This sets the language code to tag this document as being in. By
626default, it is currently the value of the environment variable
627C<RTFDEFLANG>, or if that's not set, then the value
6281033 (for US English).
629
630Setting this appropriately is useful if you want to use the RTF
631to spellcheck, and/or if you want it to hyphenate right.
632
633Here are some notable values:
634
635  1033  US English
636  2057  UK English
637  3081  Australia English
638  4105  Canada English
639  1034  Spain Spanish
640  2058  Mexico Spanish
641  1031  Germany German
642  1036  France French
643  3084  Canada French
644  1035  Finnish
645  1044  Norwegian (Bokmal)
646  2068  Norwegian (Nynorsk)
647
648=back
649
650If you are particularly interested in customizing this module's output
651even more, see the source and/or write to me.
652
653=head1 SEE ALSO
654
655L<Pod::Simple>, L<RTF::Writer>, L<RTF::Cookbook>, L<RTF::Document>,
656L<RTF::Generator>
657
658=head1 SUPPORT
659
660Questions or discussion about POD and Pod::Simple should be sent to the
661pod-people@perl.org mail list. Send an empty email to
662pod-people-subscribe@perl.org to subscribe.
663
664This module is managed in an open GitHub repository,
665L<http://github.com/theory/pod-simple/>. Feel free to fork and contribute, or
666to clone L<git://github.com/theory/pod-simple.git> and send patches!
667
668Patches against Pod::Simple are welcome. Please send bug reports to
669<bug-pod-simple@rt.cpan.org>.
670
671=head1 COPYRIGHT AND DISCLAIMERS
672
673Copyright (c) 2002 Sean M. Burke.
674
675This library is free software; you can redistribute it and/or modify it
676under the same terms as Perl itself.
677
678This program is distributed in the hope that it will be useful, but
679without any warranty; without even the implied warranty of
680merchantability or fitness for a particular purpose.
681
682=head1 AUTHOR
683
684Pod::Simple was created by Sean M. Burke <sburke@cpan.org>.
685But don't bother him, he's retired.
686
687Pod::Simple is maintained by:
688
689=over
690
691=item * Allison Randal C<allison@perl.org>
692
693=item * Hans Dieter Pearcey C<hdp@cpan.org>
694
695=item * David E. Wheeler C<dwheeler@cpan.org>
696
697=back
698
699=cut
700