perl5.001 patch.1c
[p5sagit/p5-mst-13.2.git] / pod / pod2man
1 #!/usr/bin/perl
2
3 $/ = "";
4 $cutting = 1;
5
6 $CFont = 'CW';
7 if ($ARGV[0] =~ s/-fc(.*)//) {
8     shift;
9     $CFont = $1 || shift;
10 }
11
12 if (length($CFont) == 2) {
13     $CFont_embed = "\\f($CFont";
14
15 elsif (length($CFont) == 1) {
16     $CFont_embed = "\\f$CFont";
17
18 else {
19     die "Roff font should be 1 or 2 chars, not `$CFont_embed'";
20
21
22 $name = @ARGV ? $ARGV[0] : "something";
23 $name =~ s/\..*//;
24
25 print <<"END";
26 .rn '' }`
27 ''' \$RCSfile\$\$Revision\$\$Date\$
28 ''' 
29 ''' \$Log\$
30 ''' 
31 .de Sh
32 .br
33 .if t .Sp
34 .ne 5
35 .PP
36 \\fB\\\\\$1\\fR
37 .PP
38 ..
39 .de Sp
40 .if t .sp .5v
41 .if n .sp
42 ..
43 .de Ip
44 .br
45 .ie \\\\n(.\$>=3 .ne \\\\\$3
46 .el .ne 3
47 .IP "\\\\\$1" \\\\\$2
48 ..
49 .de Vb
50 .ft $CFont
51 .nf
52 .ne \\\\\$1
53 ..
54 .de Ve
55 .ft R
56
57 .fi
58 ..
59 '''
60 '''
61 '''     Set up \\*(-- to give an unbreakable dash;
62 '''     string Tr holds user defined translation string.
63 '''     Bell System Logo is used as a dummy character.
64 '''
65 .tr \\(*W-|\\(bv\\*(Tr
66 .ie n \\{\\
67 .ds -- \\(*W-
68 .if (\\n(.H=4u)&(1m=24u) .ds -- \\(*W\\h'-12u'\\(*W\\h'-12u'-\\" diablo 10 pitch
69 .if (\\n(.H=4u)&(1m=20u) .ds -- \\(*W\\h'-12u'\\(*W\\h'-8u'-\\" diablo 12 pitch
70 .ds L" ""
71 .ds R" ""
72 .ds L' '
73 .ds R' '
74 'br\\}
75 .el\\{\\
76 .ds -- \\(em\\|
77 .tr \\*(Tr
78 .ds L" ``
79 .ds R" ''
80 .ds L' `
81 .ds R' '
82 .if t .ds PI \\(*p
83 .if n .ds PI PI
84 'br\\}
85 .TH \U$name\E 1 "\\*(RP"
86 .UC
87 END
88
89 print <<'END';
90 .if n .hy 0 
91 .if n .na
92 .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
93 .de CQ          \" put $1 in typewriter font
94 END
95 print ".ft $CFont\n";
96 print <<'END';
97 'if n "\c
98 'if t \\&\\$1\c
99 'if n \\&\\$1\c
100 'if n \&"
101 \\&\\$2 \\$3 \\$4 \\$5 \\$6 \\$7
102 '.ft R
103 ..
104 .\" @(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2
105 .       \" AM - accent mark definitions
106 .bd S B 3
107 .       \" fudge factors for nroff and troff
108 .if n \{\
109 .       ds #H 0
110 .       ds #V .8m
111 .       ds #F .3m
112 .       ds #[ \f1
113 .       ds #] \fP
114 .\}
115 .if t \{\
116 .       ds #H ((1u-(\\\\n(.fu%2u))*.13m)
117 .       ds #V .6m
118 .       ds #F 0
119 .       ds #[ \&
120 .       ds #] \&
121 .\}
122 .       \" simple accents for nroff and troff
123 .if n \{\
124 .       ds ' \&
125 .       ds ` \&
126 .       ds ^ \&
127 .       ds , \&
128 .       ds ~ ~
129 .       ds ? ?
130 .       ds ! !
131 .       ds / 
132 .       ds q 
133 .\}
134 .if t \{\
135 .       ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
136 .       ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
137 .       ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
138 .       ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
139 .       ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
140 .       ds ? \s-2c\h'-\w'c'u*7/10'\u\h'\*(#H'\zi\d\s+2\h'\w'c'u*8/10'
141 .       ds ! \s-2\(or\s+2\h'-\w'\(or'u'\v'-.8m'.\v'.8m'
142 .       ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
143 .       ds q o\h'-\w'o'u*8/10'\s-4\v'.4m'\z\(*i\v'-.4m'\s+4\h'\w'o'u*8/10'
144 .\}
145 .       \" troff and (daisy-wheel) nroff accents
146 .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
147 .ds 8 \h'\*(#H'\(*b\h'-\*(#H'
148 .ds v \\k:\h'-(\\n(.wu*9/10-\*(#H)'\v'-\*(#V'\*(#[\s-4v\s0\v'\*(#V'\h'|\\n:u'\*(#]
149 .ds _ \\k:\h'-(\\n(.wu*9/10-\*(#H+(\*(#F*2/3))'\v'-.4m'\z\(hy\v'.4m'\h'|\\n:u'
150 .ds . \\k:\h'-(\\n(.wu*8/10)'\v'\*(#V*4/10'\z.\v'-\*(#V*4/10'\h'|\\n:u'
151 .ds 3 \*(#[\v'.2m'\s-2\&3\s0\v'-.2m'\*(#]
152 .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
153 .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
154 .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
155 .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
156 .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
157 .ds ae a\h'-(\w'a'u*4/10)'e
158 .ds Ae A\h'-(\w'A'u*4/10)'E
159 .ds oe o\h'-(\w'o'u*4/10)'e
160 .ds Oe O\h'-(\w'O'u*4/10)'E
161 .       \" corrections for vroff
162 .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
163 .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
164 .       \" for low resolution devices (crt and lpr)
165 .if \n(.H>23 .if \n(.V>19 \
166 \{\
167 .       ds : e
168 .       ds 8 ss
169 .       ds v \h'-1'\o'\(aa\(ga'
170 .       ds _ \h'-1'^
171 .       ds . \h'-1'.
172 .       ds 3 3
173 .       ds o a
174 .       ds d- d\h'-1'\(ga
175 .       ds D- D\h'-1'\(hy
176 .       ds th \o'bp'
177 .       ds Th \o'LP'
178 .       ds ae ae
179 .       ds Ae AE
180 .       ds oe oe
181 .       ds Oe OE
182 .\}
183 .rm #[ #] #H #V #F C
184 END
185
186 $indent = 0;
187
188 while (<>) {
189     if ($cutting) {
190         next unless /^=/;
191         $cutting = 0;
192     }
193     chomp;
194
195     # Translate verbatim paragraph
196
197     if (/^\s/) {
198         @lines = split(/\n/);
199         for (@lines) {
200             1 while s
201                 {^( [^\t]* ) \t ( \t* ) }
202                 { $1 . ' ' x (8 - (length($1)%8) + 8 * (length($2))) }ex;
203             s/\\/\\e/g;
204             s/\A/\\&/s;
205         }
206         $lines = @lines;
207         makespace() unless $verbatim++;
208         print ".Vb $lines\n";
209         print join("\n", @lines), "\n";
210         print ".Ve\n";
211         $needspace = 0;
212         next;
213     }
214
215     $verbatim = 0;
216
217     # check for things that'll hosed our noremap scheme; affects $_
218     init_noremap();
219
220     if (!/^=item/) {
221
222         # trofficate backslashes; must do it before what happens below
223         s/\\/noremap('\\e')/ge;
224
225         # first hide the escapes in case we need to 
226         # intuit something and get it wrong due to fmting
227
228         s/([A-Z]<[^<>]*>)/noremap($1)/ge;
229
230         # func() is a reference to a perl function
231         s{
232             \b
233             (
234                 [:\w]+ \(\)
235             )
236         } {I<$1>}gx;
237
238         # func(n) is a reference to a man page
239         s{
240             (\w+)
241             (
242                 \(
243                     [^\s,\051]+
244                 \)
245             )
246         } {I<$1>\\|$2}gx;
247
248         # convert simple variable references
249         s/(\s+)([\$\@%][\w:]+)/${1}C<$2>/g;
250
251         if (m{ (
252                     [\-\w]+
253                     \(
254                         [^\051]*?
255                         [\@\$,]
256                         [^\051]*?
257                     \)
258                 )
259             }x && $` !~ /([LCI]<[^<>]*|-)$/ && !/^=\w/) 
260         {
261             warn "``$1'' should be a [LCI]<$1> ref";
262         } 
263
264         while (/(-[a-zA-Z])\b/g && $` !~ /[\w\-]$/) {
265             warn "``$1'' should be [CB]<$1> ref";
266         } 
267
268         # put it back so we get the <> processed again;
269         clear_noremap(0); # 0 means leave the E's
270
271     } else {
272         # trofficate backslashes
273         s/\\/noremap('\\e')/ge;
274
275     } 
276
277     # need to hide E<> first; they're processed in clear_noremap
278     s/(E<[^<>]+>)/noremap($1)/ge;
279
280
281     $maxnest = 10;
282     while ($maxnest-- && /[A-Z]</) {
283
284         # can't do C font here
285         s/([BI])<([^<>]*)>/font($1) . $2 . font('R')/eg;
286
287         # files and filelike refs in italics
288         s/F<([^<>]*)>/I<$1>/g;
289
290         # no break -- usually we want C<> for this
291         s/S<([^<>]*)>/nobreak($1)/eg;
292
293         # LREF: a manpage(3f) 
294         s:L<([a-zA-Z][^\s\/]+)(\([^\)]+\))?>:the I<$1>$2 manpage:g;
295
296         # LREF: an =item on another manpage
297         s{
298             L<
299                 ([^/]+)
300                 /
301                 (
302                     [:\w]+
303                     (\(\))?
304                 )
305             >
306         } {the C<$2> entry in the I<$1> manpage}gx;
307
308         # LREF: an =item on this manpage
309         s{
310            ((?:
311             L<
312                 /
313                 (
314                     [:\w]+
315                     (\(\))?
316                 )
317             >
318             (,?\s+(and\s+)?)?
319           )+)
320         } { internal_lrefs($1) }gex;
321
322         # LREF: a =head2 (head1?), maybe on a manpage, maybe right here
323         # the "func" can disambiguate
324         s{
325             L<
326                 (?:
327                     ([a-zA-Z]\S+?) / 
328                 )?
329                 "?(.*?)"?
330             >
331         }{
332             do {
333                 $1      # if no $1, assume it means on this page.
334                     ?  "the section on I<$2> in the I<$1> manpage"
335                     :  "the section on I<$2>"
336             } 
337         }gex;
338
339         s/Z<>/\\&/g;
340
341         # comes last because not subject to reprocessing
342         s/C<([^<>]*)>/noremap("${CFont_embed}${1}\\fR")/eg;
343     }
344
345     if (s/^=//) {
346         $needspace = 0;         # Assume this.
347
348         s/\n/ /g;
349
350         ($Cmd, $_) = split(' ', $_, 2);
351
352         if (defined $_) {
353             &escapes;
354             s/"/""/g;
355         }
356
357         clear_noremap(1);
358
359         if ($Cmd eq 'cut') {
360             $cutting = 1;
361         }
362         elsif ($Cmd eq 'head1') {
363             print qq{.SH "$_"\n}
364         }
365         elsif ($Cmd eq 'head2') {
366             print qq{.Sh "$_"\n}
367         }
368         elsif ($Cmd eq 'over') {
369             push(@indent,$indent);
370             $indent = $_ + 0;
371         }
372         elsif ($Cmd eq 'back') {
373             $indent = pop(@indent);
374             warn "Unmatched =back\n" unless defined $indent;
375             $needspace = 1;
376         }
377         elsif ($Cmd eq 'item') {
378             s/^\*( |$)/\\(bu$1/g;
379             print STDOUT qq{.Ip "$_" $indent\n};
380         }
381         else {
382             warn "Unrecognized directive: $Cmd\n";
383         }
384     }
385     else {
386         if ($needspace) {
387             &makespace;
388         }
389         &escapes;
390         clear_noremap(1);
391         print $_, "\n";
392         $needspace = 1;
393     }
394 }
395
396 print <<"END";
397
398 .rn }` ''
399 END
400
401 #########################################################################
402
403 sub nobreak {
404     my $string = shift;
405     $string =~ s/ /\\ /g;
406     $string;
407 }
408
409 sub escapes {
410
411     # translate the minus in foo-bar into foo\-bar for roff
412     s/([^0-9a-z-])-([^-])/$1\\-$2/g;
413
414     # make -- into the string version \*(-- (defined above)
415     s/\b--\b/\\*(--/g;
416     s/"--([^"])/"\\*(--$1/g;  # should be a better way
417     s/([^"])--"/$1\\*(--"/g;
418
419     # fix up quotes; this is somewhat tricky
420     if (!/""/) {
421         s/(^|\s)(['"])/noremap("$1\\*(L$2")/ge;
422         s/(['"])($|[\-\s,;\\!?.])/noremap("\\*(R$1$2")/ge;
423     }
424
425     #s/(?!")(?:.)--(?!")(?:.)/\\*(--/g;
426     #s/(?:(?!")(?:.)--(?:"))|(?:(?:")--(?!")(?:.))/\\*(--/g;
427     
428
429     # make sure that func() keeps a bit a space tween the parens
430     ### s/\b\(\)/\\|()/g;
431     ### s/\b\(\)/(\\|)/g;
432
433     # make C++ into \*C+, which is a squinched version (defined above)
434     s/\bC\+\+/\\*(C+/g;
435
436     # make double underbars have a little tiny space between them
437     s/__/_\\|_/g;
438
439     # PI goes to \*(-- (defined above)
440     s/\bPI\b/noremap('\\*(PI')/ge;
441
442     # make all caps a teeny bit smaller, but don't muck with embedded code literals
443     my $hidCFont = font('C');
444     if ($Cmd !~ /^head1/) { # SH already makes smaller
445         # /g isn't enough; 1 while or we'll be off
446
447 #       1 while s{
448 #           (?!$hidCFont)(..|^.|^)
449 #           \b
450 #           (
451 #               [A-Z][\/A-Z+:\-\d_$.]+
452 #           )
453 #           (s?)                
454 #           \b
455 #       } {$1\\s-1$2\\s0}gmox;
456
457         1 while s{
458             (?!$hidCFont)(..|^.|^)
459             (
460                 \b[A-Z]{2,}[\/A-Z+:\-\d_\$]*\b
461             )
462         } { 
463             $1 . noremap( '\\s-1' .  $2 . '\\s0' )
464         }egmox;
465
466     }
467 }
468
469 # make troff just be normal, but make small nroff get quoted
470 # decided to just put the quotes in the text; sigh;
471 sub ccvt {
472      local($_,$prev) = @_;
473      if ( /^\W+$/ && !/^\$./ ) {
474         ($prev && "\n") . noremap(qq{.CQ $_ \n\\&});
475         # what about $" ?
476      } else {
477         noremap(qq{${CFont_embed}$_\\fR});
478      } 
479     noremap(qq{.CQ "$_" \n\\&});
480
481
482 sub makespace {
483     if ($indent) {
484         print ".Sp\n";
485     }
486     else {
487         print ".PP\n";
488     }
489 }
490
491 sub font {
492     local($font) = shift;
493     return '\\f' . noremap($font);
494
495
496 sub noremap {
497     local($thing_to_hide) = shift;
498     $thing_to_hide =~ tr/\000-\177/\200-\377/;
499     return $thing_to_hide;
500
501
502 sub init_noremap {
503     if ( /[\200-\377]/ ) {
504         warn "hit bit char in input stream";
505     } 
506
507
508 sub clear_noremap {
509     my $ready_to_print = $_[0];
510
511     tr/\200-\377/\000-\177/;
512
513     # trofficate backslashes
514     # s/(?!\\e)(?:..|^.|^)\\/\\e/g;
515
516     # now for the E<>s, which have been hidden until now
517     # otherwise the interative \w<> processing would have
518     # been hosed by the E<gt>
519     s {
520             E<  
521             ( [A-Za-z]+ )       
522             >   
523     } { 
524          do {   
525              exists $HTML_Escapes{$1}
526                 ? do { $HTML_Escapes{$1} }
527                 : do {
528                     warn "Unknown escape: $& in $_";
529                     "E<$1>";
530                 } 
531          } 
532     }egx if $ready_to_print;
533
534
535 sub internal_lrefs {
536     local($_) = shift;
537
538     s{L</([^>]+)>}{$1}g;
539     my(@items) = split( /(?:,?\s+(?:and\s+)?)/ );
540     my $retstr = "the ";
541     my $i;
542     for ($i = 0; $i <= $#items; $i++) {
543         $retstr .= "C<$items[$i]>";
544         $retstr .= ", " if @items > 2 && $i != $#items;
545         $retstr .= " and " if $i+2 == @items;
546     } 
547
548     $retstr .= " entr" . ( @items > 1  ? "ies" : "y" )
549             .  " elsewhere in this document";
550
551     return $retstr;
552
553
554
555 BEGIN {
556 %HTML_Escapes = (
557     'amp'       =>      '&',    #   ampersand
558     'lt'        =>      '<',    #   left chevron, less-than
559     'gt'        =>      '>',    #   right chevron, greater-than
560     'quot'      =>      '"',    #   double quote
561
562     "Aacute"    =>      "A\\*'",        #   capital A, acute accent
563     "aacute"    =>      "a\\*'",        #   small a, acute accent
564     "Acirc"     =>      "A\\*^",        #   capital A, circumflex accent
565     "acirc"     =>      "a\\*^",        #   small a, circumflex accent
566     "AElig"     =>      '\*(AE',        #   capital AE diphthong (ligature)
567     "aelig"     =>      '\*(ae',        #   small ae diphthong (ligature)
568     "Agrave"    =>      "A\\*`",        #   capital A, grave accent
569     "agrave"    =>      "A\\*`",        #   small a, grave accent
570     "Aring"     =>      'A\\*o',        #   capital A, ring
571     "aring"     =>      'a\\*o',        #   small a, ring
572     "Atilde"    =>      'A\\*~',        #   capital A, tilde
573     "atilde"    =>      'a\\*~',        #   small a, tilde
574     "Auml"      =>      'A\\*:',        #   capital A, dieresis or umlaut mark
575     "auml"      =>      'a\\*:',        #   small a, dieresis or umlaut mark
576     "Ccedil"    =>      'C\\*,',        #   capital C, cedilla
577     "ccedil"    =>      'c\\*,',        #   small c, cedilla
578     "Eacute"    =>      "E\\*'",        #   capital E, acute accent
579     "eacute"    =>      "e\\*'",        #   small e, acute accent
580     "Ecirc"     =>      "E\\*^",        #   capital E, circumflex accent
581     "ecirc"     =>      "e\\*^",        #   small e, circumflex accent
582     "Egrave"    =>      "E\\*`",        #   capital E, grave accent
583     "egrave"    =>      "e\\*`",        #   small e, grave accent
584     "ETH"       =>      '\\*(D-',       #   capital Eth, Icelandic
585     "eth"       =>      '\\*(d-',       #   small eth, Icelandic
586     "Euml"      =>      "E\\*:",        #   capital E, dieresis or umlaut mark
587     "euml"      =>      "e\\*:",        #   small e, dieresis or umlaut mark
588     "Iacute"    =>      "I\\*'",        #   capital I, acute accent
589     "iacute"    =>      "i\\*'",        #   small i, acute accent
590     "Icirc"     =>      "I\\*^",        #   capital I, circumflex accent
591     "icirc"     =>      "i\\*^",        #   small i, circumflex accent
592     "Igrave"    =>      "I\\*`",        #   capital I, grave accent
593     "igrave"    =>      "i\\*`",        #   small i, grave accent
594     "Iuml"      =>      "I\\*:",        #   capital I, dieresis or umlaut mark
595     "iuml"      =>      "i\\*:",        #   small i, dieresis or umlaut mark
596     "Ntilde"    =>      'N\*~',         #   capital N, tilde
597     "ntilde"    =>      'n\*~',         #   small n, tilde
598     "Oacute"    =>      "O\\*'",        #   capital O, acute accent
599     "oacute"    =>      "o\\*'",        #   small o, acute accent
600     "Ocirc"     =>      "O\\*^",        #   capital O, circumflex accent
601     "ocirc"     =>      "o\\*^",        #   small o, circumflex accent
602     "Ograve"    =>      "O\\*`",        #   capital O, grave accent
603     "ograve"    =>      "o\\*`",        #   small o, grave accent
604     "Oslash"    =>      "O\\*/",        #   capital O, slash
605     "oslash"    =>      "o\\*/",        #   small o, slash
606     "Otilde"    =>      "O\\*~",        #   capital O, tilde
607     "otilde"    =>      "o\\*~",        #   small o, tilde
608     "Ouml"      =>      "O\\*:",        #   capital O, dieresis or umlaut mark
609     "ouml"      =>      "o\\*:",        #   small o, dieresis or umlaut mark
610     "szlig"     =>      '\*8',          #   small sharp s, German (sz ligature)
611     "THORN"     =>      '\\*(Th',       #   capital THORN, Icelandic
612     "thorn"     =>      '\\*(th',,      #   small thorn, Icelandic
613     "Uacute"    =>      "U\\*'",        #   capital U, acute accent
614     "uacute"    =>      "u\\*'",        #   small u, acute accent
615     "Ucirc"     =>      "U\\*^",        #   capital U, circumflex accent
616     "ucirc"     =>      "u\\*^",        #   small u, circumflex accent
617     "Ugrave"    =>      "U\\*`",        #   capital U, grave accent
618     "ugrave"    =>      "u\\*`",        #   small u, grave accent
619     "Uuml"      =>      "U\\*:",        #   capital U, dieresis or umlaut mark
620     "uuml"      =>      "u\\*:",        #   small u, dieresis or umlaut mark
621     "Yacute"    =>      "Y\\*'",        #   capital Y, acute accent
622     "yacute"    =>      "y\\*'",        #   small y, acute accent
623     "yuml"      =>      "y\\*:",        #   small y, dieresis or umlaut mark
624 );
625 }