bd6df71c749d55c2a0e7ec1b203fecb186df73dc
[p5sagit/p5-mst-13.2.git] / pod / pod2latex.PL
1 #!/usr/local/bin/perl
2
3 use Config;
4 use File::Basename qw(&basename &dirname);
5
6 # List explicitly here the variables you want Configure to
7 # generate.  Metaconfig only looks for shell variables, so you
8 # have to mention them as if they were shell variables, not
9 # %Config entries.  Thus you write
10 #  $startperl
11 # to ensure Configure will look for $Config{startperl}.
12
13 # This forces PL files to create target in same directory as PL file.
14 # This is so that make depend always knows where to find PL derivatives.
15 chdir(dirname($0));
16 ($file = basename($0)) =~ s/\.PL$//;
17 $file =~ s/\.pl$//
18         if ($Config{'osname'} eq 'VMS' or
19             $Config{'osname'} eq 'OS2');  # "case-forgiving"
20
21 open OUT,">$file" or die "Can't create $file: $!";
22
23 print "Extracting $file (with variable substitutions)\n";
24
25 # In this section, perl variables will be expanded during extraction.
26 # You can use $Config{...} to use Configure variables.
27
28 print OUT <<"!GROK!THIS!";
29 $Config{'startperl'}
30     eval 'exec perl -S \$0 "\$@"'
31         if 0;
32 !GROK!THIS!
33
34 # In the following, perl variables are not expanded during extraction.
35
36 print OUT <<'!NO!SUBS!';
37 #
38 # pod2latex, version 1.1
39 # by Taro Kawagish (kawagish@imslab.co.jp),  Jan 11, 1995.
40 #
41 # pod2latex filters Perl pod documents to LaTeX documents.
42 #
43 # What pod2latex does:
44 # 1. Pod file 'perl_doc_entry.pod' is filtered to 'perl_doc_entry.tex'.
45 # 2. Indented paragraphs are translated into
46 #    '\begin{verbatim} ... \end{verbatim}'.
47 # 3. '=head1 heading' command is translated into '\section{heading}'
48 # 4. '=head2 heading' command is translated into '\subsection*{heading}'
49 # 5. '=over N' command is translated into
50 #        '\begin{itemize}'      if following =item starts with *,
51 #        '\begin{enumerate}'    if following =item starts with 1.,
52 #        '\begin{description}'  if else.
53 #      (indentation level N is ignored.)
54 # 6. '=item * heading' command is translated into '\item heading',
55 #    '=item 1. heading' command is translated into '\item heading',
56 #    '=item heading' command(other) is translated into '\item[heading]'.
57 # 7. '=back' command is translated into
58 #        '\end{itemize}'        if started with '\begin{itemize}',
59 #        '\end{enumerate}'      if started with '\begin{enumerate}',
60 #        '\end{description}'    if started with '\begin{description}'.
61 # 8. other paragraphs are translated into strings with TeX special characters
62 #    escaped.
63 # 9. In heading text, and other paragraphs, the following translation of pod
64 #    quotes are done, and then TeX special characters are escaped after that.
65 #      I<text> to {\em text\/},
66 #      B<text> to {\bf text},
67 #      S<text> to text1,
68 #        where text1 is a string with blank characters replaced with ~,
69 #      C<text> to {\tt text2},
70 #        where text2 is a string with TeX special characters escaped to
71 #        obtain a literal printout,
72 #      E<text> (HTML escape) to TeX escaped string,
73 #      L<text> to referencing string as is done by pod2man,
74 #      F<file> to {\em file\/},
75 #      Z<> to a null string,
76 # 10. those headings are indexed:
77 #       '=head1 heading'   =>  \section{heading}\index{heading}
78 #       '=head2 heading'   =>  \subsection*{heading}\index{heading}
79 #                 only when heading does not match frequent patterns such as
80 #                 DESCRIPTION, DIAGNOSTICS,...
81 #       '=item heading'   =>  \item{heading}\index{heading}
82 #
83 # Usage:
84 #     pod2latex perl_doc_entry.pod
85 # this will write to a file 'perl_doc_entry.tex'.
86 #
87 # To LaTeX:
88 # The following commands need to be defined in the preamble of the LaTeX
89 # document:
90 # \def\C++{{\rm C\kern-.05em\raise.3ex\hbox{\footnotesize ++}}}
91 # \def\underscore{\leavevmode\kern.04em\vbox{\hrule width 0.4em height 0.3pt}}
92 # and \parindent should be set zero:
93 # \setlength{\parindent}{0pt}
94 #
95 # Note:
96 # This script was written modifing pod2man.
97 #
98 # Bug:
99 # If HTML escapes E<text> other than E<amp>,E<lt>,E<gt>,E<quot> are used
100 # in C<>, translation will produce wrong character strings.
101 # Translation of HTML escapes of various European accents might be wrong.
102
103
104 $/ = "";                        # record separator is blank lines
105 # TeX special characters.
106 ##$tt_ables = "!@*()-=+|;:'\"`,./?<>";
107 $backslash_escapables = "#\$%&{}_";
108 $backslash_escapables2 = "#\$%&{}";     # except _
109 ##$nonverbables = "^\\~";
110 ##$bracketesc = "[]";
111 ##@tex_verb_fences = unpack("aaaaaaaaa","|#@!*+?:;");
112
113 @head1_freq_patterns            # =head1 patterns which need not be index'ed
114     = ("AUTHOR","Author","BUGS","DATE","DESCRIPTION","DIAGNOSTICS",
115        "ENVIRONMENT","EXAMPLES","FILES","INTRODUCTION","NAME","NOTE",
116        "SEE ALSO","SYNOPSIS","WARNING");
117
118 $indent = 0;
119
120 # parse the pods, produce LaTeX.
121
122 open(POD,"<$ARGV[0]") || die "cant open $ARGV[0]";
123 ($pod=$ARGV[0]) =~ s/\.pod$//;
124 open(LATEX,">$pod.tex");
125 &do_hdr();
126
127 $cutting = 1;
128 while (<POD>) {
129     if ($cutting) {
130         next unless /^=/;
131         $cutting = 0;
132     }
133     chop;
134     length || (print LATEX  "\n") && next;
135
136     # translate indented lines as a verabatim paragraph
137     if (/^\s/) {
138         @lines = split(/\n/);
139         print LATEX  "\\begin{verbatim}\n";
140         for (@lines) {
141             1 while s
142                 {^( [^\t]* ) \t ( \t* ) }
143                 { $1 . ' ' x (8 - (length($1)%8) + 8*(length($2))) }ex;
144             print LATEX  $_,"\n";
145         }
146         print LATEX  "\\end{verbatim}\n";
147         next;
148     }
149
150     # preserve '=item' line with pod quotes as they are.
151     if (/^=item/) {
152         ($bareitem = $_) =~ s/^=item\s*//;
153     }
154
155     # check for things that'll hosed our noremap scheme; affects $_
156     &init_noremap();
157
158     # expand strings "func()" as pod quotes.
159     if (!/^=item/) {
160         # first hide pod escapes.
161         # escaped strings are mapped into the ones with the MSB's on.
162         s/([A-Z]<[^<>]*>)/noremap($1)/ge;
163
164         # func() is a reference to a perl function
165         s{\b([:\w]+\(\))}{I<$1>}g;
166         # func(n) is a reference to a man page
167         s{(\w+)(\([^\s,\051]+\))}{I<$1>$2}g;
168         # convert simple variable references
169 #       s/([\$\@%][\w:]+)/C<$1>/g;
170 #       s/\$[\w:]+\[[0-9]+\]/C<$&>/g;
171
172         if (m{ ([\-\w]+\([^\051]*?[\@\$,][^\051]*?\))
173                }x && $` !~ /([LCI]<[^<>]*|-)$/ && !/^=\w/)
174         {
175             warn "``$1'' should be a [LCI]<$1> ref";
176         }
177         while (/(-[a-zA-Z])\b/g && $` !~ /[\w\-]$/) {
178             warn "``$1'' should be [CB]<$1> ref";
179         }
180
181         # put back pod quotes so we get the inside of <> processed;
182         $_ = &clear_noremap($_);
183     }
184
185
186     # process TeX special characters
187
188     # First hide HTML quotes E<> since they can be included in C<>.
189     s/(E<[^<>]+>)/noremap($1)/ge;
190
191     # Then hide C<> type literal quotes.
192     # String inside of C<> will later be expanded into {\tt ..} strings
193     # with TeX special characters escaped as needed.
194     s/(C<[^<>]*>)/&noremap($1)/ge;
195
196     # Next escape TeX special characters including other pod quotes B< >,...
197     #
198     # NOTE: s/re/&func($str)/e evaluates $str just once in perl5.
199     # (in perl4 evaluation takes place twice before getting passed to func().)
200
201     # - hyphen => ---
202     s/(\S+)(\s+)-+(\s+)(\S+)/"$1".&noremap(" --- ")."$4"/ge;
203     # '-', '--', "-"  =>  '{\tt -}', '{\tt --}', "{\tt -}"
204 ##    s/("|')(\s*)(-+)(\s*)\1/&noremap("$1$2\{\\tt $3\}$4$1")/ge;
205 ## changed Wed Jan 25 15:26:39 JST 1995
206     # '-', '--', "-"  =>  '$-$', '$--$', "$-$"
207     s/(\s+)(['"])(-+)([^'"\-]*)\2(\s+|[,.])/"$1$2".&noremap("\$$3\$")."$4$2$5"/ge;
208     s/(\s+)(['"])([^'"\-]*)(-+)(\s*)\2(\s+|[,.])/"$1$2$3".&noremap("\$$4\$")."$5$2$6"/ge;
209     # (--|-)  =>  ($--$|$-$)
210     s/(\s+)\((-+)([=@%\$\+\\\|\w]*)(-*)([=@%\$\+\\\|\w]*)\)(\s+|[,.])/"$1\(".&noremap("\$$2\$")."$3".&noremap("\$$4\$")."$5\)$6"/ge;
211     # numeral -  =>  $-$
212     s/(\(|[0-9]+|\s+)-(\s*\(?\s*[0-9]+)/&noremap("$1\$-\$$2")/ge;
213     # -- in quotes  =>  two separate -
214     s/B<([^<>]*)--([^<>]*)>/&noremap("B<$1\{\\tt --\}$2>")/ge;
215
216     # backslash escapable characters except _.
217     s/([$backslash_escapables2])/&noremap("\\$1")/ge;
218     s/_/&noremap("\\underscore{}")/ge;          # a litle thicker than \_.
219     # quote TeX special characters |, ^, ~, \.
220     s/\|/&noremap("\$|\$")/ge;
221     s/\^/&noremap("\$\\hat{\\hspace{0.4em}}\$")/ge;
222     s/\~/&noremap("\$\\tilde{\\hspace{0.4em}}\$")/ge;
223     s/\\/&noremap("\$\\backslash{}\$")/ge;
224     # quote [ and ] to be used in \item[]
225     s/([\[\]])/&noremap("{\\tt $1}")/ge;
226     # characters need to be treated differently in TeX
227     # keep * if an item heading
228     s/^(=item[ \t]+)[*]((.|\n)*)/"$1" . &noremap("*") . "$2"/ge;
229     s/[*]/&noremap("\$\\ast\$")/ge;     # other *
230
231     # hide other pod quotes.
232     s/([ABD-Z]<[^<>]*>)/&noremap($1)/ge;
233
234     # escape < and > as math strings,
235     # now that we are done with hiding pod <> quotes.
236     s/</&noremap("\$<\$")/ge;
237     s/>/&noremap("\$>\$")/ge;
238
239     # put it back so we get the <> processed again;
240     $_ = &clear_noremap($_);
241
242
243     # Expand pod quotes recursively:
244     # (1) type face directives [BIFS]<[^<>]*> to appropriate TeX commands,
245     # (2) L<[^<>]*> to reference strings,
246     # (3) C<[^<>]*> to TeX literal quotes,
247     # (4) HTML quotes E<> inside of C<> quotes.
248
249     # Hide E<> again since they can be included in C<>.
250     s/(E<[^<>]+>)/noremap($1)/ge;
251
252     $maxnest = 10;
253     while ($maxnest-- && /[A-Z]</) {
254
255         # bold and italic quotes
256         s/B<([^<>]*)>/"{\\bf $1}"/eg;
257         s#I<([^<>]*)>#"{\\em $1\\/}"#eg;
258
259         # files and filelike refs in italics
260         s#F<([^<>]*)>#"{\\em $1\\/}"#eg;
261
262         # no break quote -- usually we want C<> for this
263         s/S<([^<>]*)>/&nobreak($1)/eg;
264
265         # LREF: a manpage(3f)
266         s:L<([a-zA-Z][^\s\/]+)(\([^\)]+\))?>:the {\\em $1\\/}$2 manpage:g;
267
268         # LREF: an =item on another manpage
269         s{
270             L<([^/]+)/([:\w]+(\(\))?)>
271         } {the C<$2> entry in the I<$1> manpage}gx;
272
273         # LREF: an =item on this manpage
274         s{
275            ((?:L</([:\w]+(\(\))?)>
276             (,?\s+(and\s+)?)?)+)
277         } { &internal_lrefs($1) }gex;
278
279         # LREF: a =head2 (head1?), maybe on a manpage, maybe right here
280         # the "func" can disambiguate
281         s{
282             L<(?:([a-zA-Z]\S+?) /)?"?(.*?)"?>
283         }{
284             do {
285                 $1      # if no $1, assume it means on this page.
286                     ?  "the section on I<$2> in the I<$1> manpage"
287                     :  "the section on I<$2>"
288             } 
289         }gex;
290
291         s/Z<>/\\&/g;            # the "don't format me" thing
292
293         # comes last because not subject to reprocessing
294         s{
295             C<([^<>]*)>
296         }{
297             do {
298                 ($str = $1) =~ tr/\200-\377/\000-\177/; #normalize hidden stuff
299                 # expand HTML escapes if any;
300                 # WARNING: if HTML escapes other than E<amp>,E<lt>,E<gt>,
301                 # E<quot> are in C<>, they will not be printed correctly.
302                 $str = &expand_HTML_escapes($str);
303                 $strverb = &alltt($str);    # Tex verbatim escape of a string.
304                 &noremap("$strverb");
305             }
306         }gex;
307
308 #       if ( /C<([^<>]*)/ ) {
309 #           $str = $1;
310 #           if ($str !~ /\|/) {         # if includes |
311 #               s/C<([^<>]*)>/&noremap("\\verb|$str|")/eg;
312 #           } else {
313 #               print STDERR "found \| in C<.*> at paragraph $.\n";
314 #               # find a character not contained in $str to use it as a
315 #               # separator of the \verb
316 #               ($chars = $str) =~ s/(\W)/\\$1/g;
317 #               ## ($chars = $str) =~ s/([\$<>,\|"'\-^{}()*+?\\])/\\$1/g;
318 #               @fence = grep(!/[ $chars]/,@tex_verb_fences);
319 #               s/C<([^<>]*)>/&noremap("\\verb$fence[0]$str$fence[0]")/eg;
320 #           }
321 #       }
322     }
323
324
325     # process each pod command
326     if (s/^=//) {                               # if a command
327         s/\n/ /g;
328         ($cmd, $rest) = split(' ', $_, 2);
329         $rest =~ s/^\s*//;
330         $rest =~ s/\s*$//;
331
332         if (defined $rest) {
333             &escapes;
334         }
335
336         $rest = &clear_noremap($rest);
337         $rest = &expand_HTML_escapes($rest);
338
339         if ($cmd eq 'cut') {
340             $cutting = 1;
341             $lastcmd = 'cut';
342         }
343         elsif ($cmd eq 'head1') {       # heading type 1
344             $rest =~ s/^\s*//; $rest =~ s/\s*$//;
345             print LATEX  "\n\\subsection*{$rest}";
346             # put index entry
347             ($index = $rest) =~ s/^(An?\s+|The\s+)//i;  # remove 'A' and 'The'
348             # index only those heads not matching the frequent patterns.
349             foreach $pat (@head1_freq_patterns) {
350                 if ($index =~ /^$pat/) {
351                     goto freqpatt;
352                 }
353             }
354             print LATEX  "%\n\\index{$index}\n" if ($index);
355           freqpatt:
356             $lastcmd = 'head1';
357         }
358         elsif ($cmd eq 'head2') {       # heading type 2
359             $rest =~ s/^\s*//; $rest =~ s/\s*$//;
360             print LATEX  "\n\\subsubsection*{$rest}";
361             # put index entry
362             ($index = $rest) =~ s/^(An?\s+|The\s+)//i;  # remove 'A' and 'The'
363             $index =~ s/^Example\s*[1-9][0-9]*\s*:\s*//; # remove 'Example :'
364             print LATEX  "%\n\\index{$index}\n"  if ($index);
365             $lastcmd = 'head2';
366         }
367         elsif ($cmd eq 'over') {        # 1 level within a listing environment
368             push(@indent,$indent);
369             $indent = $rest + 0;
370             $lastcmd = 'over';
371         }
372         elsif ($cmd eq 'back') {        # 1 level out of a listing environment
373             $indent = pop(@indent);
374             warn "Unmatched =back\n" unless defined $indent;
375             $listingcmd = pop(@listingcmd);
376             print LATEX  "\n\\end{$listingcmd}\n"  if ($listingcmd);
377             $lastcmd = 'back';
378         }
379         elsif ($cmd eq 'item') {        # an item paragraph starts
380             if ($lastcmd eq 'over') {   # if we have just entered listing env
381                 # see what type of list environment we are in.
382                 if ($rest =~ /^[0-9]\.?/) {     # if numeral heading
383                     $listingcmd = 'enumerate';
384                 } elsif ($rest =~ /^\*\s*/) {   # if * heading
385                     $listingcmd = 'itemize';
386                 } elsif ($rest =~ /^[^*]/) {    # if other headings
387                     $listingcmd = 'description';
388                 } else {
389                     warn "unknown list type for item $rest";
390                 }
391                 print LATEX  "\n\\begin{$listingcmd}\n";
392                 push(@listingcmd,$listingcmd);
393             } elsif ($lastcmd ne 'item') {
394                 warn "Illegal '=item' command without preceding 'over':";
395                 warn "=item $bareitem";
396             }
397
398             if ($listingcmd eq 'enumerate') {
399                 $rest =~ s/^[0-9]+\.?\s*//;     # remove numeral heading
400                 print LATEX  "\n\\item";
401                 print LATEX  "{\\bf $rest}" if $rest;
402             } elsif ($listingcmd eq 'itemize') {
403                 $rest =~ s/^\*\s*//;            # remove * heading
404                 print LATEX  "\n\\item";
405                 print LATEX  "{\\bf $rest}" if $rest;
406             } else {                            # description item
407                 print LATEX  "\n\\item[$rest]";
408             }
409             $lastcmd = 'item';
410             $rightafter_item = 'yes';
411
412             # check if the item heading is short or long.
413             ($itemhead = $rest) =~ s/{\\bf (\S*)}/$1/g;
414             if (length($itemhead) < 4) {
415                 $itemshort = "yes";
416             } else {
417                 $itemshort = "no";
418             }
419             # write index entry
420             if ($pod =~ "perldiag") {                   # skip 'perldiag.pod'
421                 goto noindex;
422             }
423             # strip out the item of pod quotes and get a plain text entry
424             $bareitem =~ s/\n/ /g;                      # remove newlines
425             $bareitem =~ s/\s*$//;                      # remove trailing space
426             $bareitem =~ s/[A-Z]<([^<>]*)>/$1/g;        # remove <> quotes
427             ($index = $bareitem) =~ s/^\*\s+//;         # remove leading '*'
428             $index =~ s/^(An?\s+|The\s+)//i;            # remove 'A' and 'The'
429             $index =~ s/^\s*[1-9][0-9]*\s*[.]\s*$//; # remove numeral only
430             $index =~ s/^\s*\w\s*$//;                   # remove 1 char only's
431                 # quote ", @ and ! with " to be used in makeindex.
432             $index =~ s/"/""/g;                         # quote "
433             $index =~ s/@/"@/g;                         # quote @
434             $index =~ s/!/"!/g;                         # quote !
435             ($rest2=$rest) =~ s/^\*\s+//;       # remove *
436             $rest2 =~ s/"/""/g;                         # quote "
437             $rest2 =~ s/@/"@/g;                         # quote @
438             $rest2 =~ s/!/"!/g;                         # quote !
439             if ($pod =~ "(perlfunc|perlvar)") { # when doc is perlfunc,perlvar
440                 # take only the 1st word of item heading
441                 $index =~ s/^([^{}\s]*)({.*})?([^{}\s]*)\s+.*/\1\2\3/;
442                 $rest2 =~ s/^([^{}\s]*)({.*})?([^{}\s]*)\s+.*/\1\2\3/;
443             }
444             if ($index =~ /[A-Za-z\$@%]/) {
445                     #  write  \index{plain_text_entry@TeX_string_entry}
446                 print LATEX  "%\n\\index{$index\@$rest2}%\n";
447             }
448           noindex:
449             ;
450         }
451         else {
452             warn "Unrecognized directive: $cmd\n";
453         }
454     }
455     else {                                      # if not command
456         &escapes;
457         $_ = &clear_noremap($_);
458         $_ = &expand_HTML_escapes($_);
459
460         # if the present paragraphs follows an =item declaration,
461         # put a line break.
462         if ($lastcmd eq 'item' &&
463             $rightafter_item eq 'yes' && $itemshort eq "no") {
464             print LATEX  "\\hfil\\\\";
465             $rightafter_item = 'no';
466         }
467         print LATEX  "\n",$_;
468     }
469 }
470
471 print LATEX  "\n";
472 close(POD);
473 close(LATEX);
474
475
476 #########################################################################
477
478 sub do_hdr {
479     print LATEX "% LaTeX document produced by pod2latex from \"$pod.pod\".\n";
480     print LATEX "% The followings need be defined in the preamble of this document:\n";
481     print LATEX "%\\def\\C++{{\\rm C\\kern-.05em\\raise.3ex\\hbox{\\footnotesize ++}}}\n";
482     print LATEX "%\\def\\underscore{\\leavevmode\\kern.04em\\vbox{\\hrule width 0.4em height 0.3pt}}\n";
483     print LATEX "%\\setlength{\\parindent}{0pt}\n";
484     print LATEX "\n";
485     $podq = &escape_tex_specials("\U$pod\E");
486     print LATEX "\\section{$podq}%\n";
487     print LATEX "\\index{$podq}";
488     print LATEX "\n";
489 }
490
491 sub nobreak {
492     my $string = shift;
493     $string =~ s/ +/~/g;                # TeX no line break
494     $string;
495 }
496
497 sub noremap {
498     local($thing_to_hide) = shift;
499     $thing_to_hide =~ tr/\000-\177/\200-\377/;
500     return $thing_to_hide;
501 }
502
503 sub init_noremap {
504     if ( /[\200-\377]/ ) {
505         warn "hit bit char in input stream";
506     }
507 }
508
509 sub clear_noremap {
510     local($tmp) = shift;
511     $tmp =~ tr/\200-\377/\000-\177/;
512     return $tmp;
513 }
514
515 sub expand_HTML_escapes {
516     local($s) = $_[0];
517     $s =~ s { E<([A-Za-z]+)> }
518     {
519         do {
520             exists $HTML_Escapes{$1}
521             ? do { $HTML_Escapes{$1} }
522             : do {
523                 warn "Unknown escape: $& in $_";
524                 "E<$1>";
525             }
526         }
527     }egx;
528     return $s;
529 }
530
531 sub escapes {
532     # make C++ into \C++, which is to be defined as
533     # \def\C++{{\rm C\kern-.05em\raise.3ex\hbox{\footnotesize ++}}}
534     s/\bC\+\+/\\C++{}/g;
535 }
536
537 # Translate a string into a TeX \tt string to obtain a verbatim print out.
538 # TeX special characters are escaped by \.
539 # This can be used inside of LaTeX command arguments.
540 # We don't use LaTeX \verb since it doesn't work inside of command arguments.
541 sub alltt {
542     local($str) = shift;
543         # other chars than #,\,$,%,&,{,},_,\,^,~ ([ and ] included).
544     $str =~ s/([^${backslash_escapables}\\\^\~]+)/&noremap("$&")/eg;
545         # chars #,\,$,%,&,{,}  =>  \# , ...
546     $str =~ s/([$backslash_escapables2])/&noremap("\\$&")/eg;
547         # chars _,\,^,~  =>  \char`\_ , ...
548     $str =~ s/_/&noremap("\\char`\\_")/eg;
549     $str =~ s/\\/&noremap("\\char`\\\\")/ge;
550     $str =~ s/\^/\\char`\\^/g;
551     $str =~ s/\~/\\char`\\~/g;
552
553     $str =~ tr/\200-\377/\000-\177/;            # put back
554     $str = "{\\tt ".$str."}";                   # make it a \tt string
555     return $str;
556 }
557
558 sub escape_tex_specials {
559     local($str) = shift;
560         # other chars than #,\,$,%,&,{,},  _,\,^,~ ([ and ] included).
561     # backslash escapable characters #,\,$,%,&,{,} except _.
562     $str =~ s/([$backslash_escapables2])/&noremap("\\$1")/ge;
563     $str =~ s/_/&noremap("\\underscore{}")/ge;  # \_ is too thin.
564     # quote TeX special characters |, ^, ~, \.
565     $str =~ s/\|/&noremap("\$|\$")/ge;
566     $str =~ s/\^/&noremap("\$\\hat{\\hspace{0.4em}}\$")/ge;
567     $str =~ s/\~/&noremap("\$\\tilde{\\hspace{0.4em}}\$")/ge;
568     $str =~ s/\\/&noremap("\$\\backslash{}\$")/ge;
569     # characters need to be treated differently in TeX
570     # *
571     $str =~ s/[*]/&noremap("\$\\ast\$")/ge;
572     # escape < and > as math string,
573     $str =~ s/</&noremap("\$<\$")/ge;
574     $str =~ s/>/&noremap("\$>\$")/ge;
575     $str =~ tr/\200-\377/\000-\177/;            # put back
576     return $str;
577 }
578
579 sub internal_lrefs {
580     local($_) = shift;
581
582     s{L</([^>]+)>}{$1}g;
583     my(@items) = split( /(?:,?\s+(?:and\s+)?)/ );
584     my $retstr = "the ";
585     my $i;
586     for ($i = 0; $i <= $#items; $i++) {
587         $retstr .= "C<$items[$i]>";
588         $retstr .= ", " if @items > 2 && $i != $#items;
589         $retstr .= " and " if $i+2 == @items;
590     }
591     $retstr .= " entr" . ( @items > 1  ? "ies" : "y" )
592             .  " elsewhere in this document";
593
594     return $retstr;
595 }
596
597 # map of HTML escapes to TeX escapes.
598 BEGIN {
599 %HTML_Escapes = (
600     'amp'       =>      '&',    #   ampersand
601     'lt'        =>      '<',    #   left chevron, less-than
602     'gt'        =>      '>',    #   right chevron, greater-than
603     'quot'      =>      '"',    #   double quote
604
605     "Aacute"    =>      "\\'{A}",       #   capital A, acute accent
606     "aacute"    =>      "\\'{a}",       #   small a, acute accent
607     "Acirc"     =>      "\\^{A}",       #   capital A, circumflex accent
608     "acirc"     =>      "\\^{a}",       #   small a, circumflex accent
609     "AElig"     =>      '\\AE',         #   capital AE diphthong (ligature)
610     "aelig"     =>      '\\ae',         #   small ae diphthong (ligature)
611     "Agrave"    =>      "\\`{A}",       #   capital A, grave accent
612     "agrave"    =>      "\\`{a}",       #   small a, grave accent
613     "Aring"     =>      '\\u{A}',       #   capital A, ring
614     "aring"     =>      '\\u{a}',       #   small a, ring
615     "Atilde"    =>      '\\~{A}',       #   capital A, tilde
616     "atilde"    =>      '\\~{a}',       #   small a, tilde
617     "Auml"      =>      '\\"{A}',       #   capital A, dieresis or umlaut mark
618     "auml"      =>      '\\"{a}',       #   small a, dieresis or umlaut mark
619     "Ccedil"    =>      '\\c{C}',       #   capital C, cedilla
620     "ccedil"    =>      '\\c{c}',       #   small c, cedilla
621     "Eacute"    =>      "\\'{E}",       #   capital E, acute accent
622     "eacute"    =>      "\\'{e}",       #   small e, acute accent
623     "Ecirc"     =>      "\\^{E}",       #   capital E, circumflex accent
624     "ecirc"     =>      "\\^{e}",       #   small e, circumflex accent
625     "Egrave"    =>      "\\`{E}",       #   capital E, grave accent
626     "egrave"    =>      "\\`{e}",       #   small e, grave accent
627     "ETH"       =>      '\\OE',         #   capital Eth, Icelandic
628     "eth"       =>      '\\oe',         #   small eth, Icelandic
629     "Euml"      =>      '\\"{E}',       #   capital E, dieresis or umlaut mark
630     "euml"      =>      '\\"{e}',       #   small e, dieresis or umlaut mark
631     "Iacute"    =>      "\\'{I}",       #   capital I, acute accent
632     "iacute"    =>      "\\'{i}",       #   small i, acute accent
633     "Icirc"     =>      "\\^{I}",       #   capital I, circumflex accent
634     "icirc"     =>      "\\^{i}",       #   small i, circumflex accent
635     "Igrave"    =>      "\\`{I}",       #   capital I, grave accent
636     "igrave"    =>      "\\`{i}",       #   small i, grave accent
637     "Iuml"      =>      '\\"{I}',       #   capital I, dieresis or umlaut mark
638     "iuml"      =>      '\\"{i}',       #   small i, dieresis or umlaut mark
639     "Ntilde"    =>      '\\~{N}',       #   capital N, tilde
640     "ntilde"    =>      '\\~{n}',       #   small n, tilde
641     "Oacute"    =>      "\\'{O}",       #   capital O, acute accent
642     "oacute"    =>      "\\'{o}",       #   small o, acute accent
643     "Ocirc"     =>      "\\^{O}",       #   capital O, circumflex accent
644     "ocirc"     =>      "\\^{o}",       #   small o, circumflex accent
645     "Ograve"    =>      "\\`{O}",       #   capital O, grave accent
646     "ograve"    =>      "\\`{o}",       #   small o, grave accent
647     "Oslash"    =>      "\\O",          #   capital O, slash
648     "oslash"    =>      "\\o",          #   small o, slash
649     "Otilde"    =>      "\\~{O}",       #   capital O, tilde
650     "otilde"    =>      "\\~{o}",       #   small o, tilde
651     "Ouml"      =>      '\\"{O}',       #   capital O, dieresis or umlaut mark
652     "ouml"      =>      '\\"{o}',       #   small o, dieresis or umlaut mark
653     "szlig"     =>      '\\ss',         #   small sharp s, German (sz ligature)
654     "THORN"     =>      '\\L',          #   capital THORN, Icelandic
655     "thorn"     =>      '\\l',,         #   small thorn, Icelandic
656     "Uacute"    =>      "\\'{U}",       #   capital U, acute accent
657     "uacute"    =>      "\\'{u}",       #   small u, acute accent
658     "Ucirc"     =>      "\\^{U}",       #   capital U, circumflex accent
659     "ucirc"     =>      "\\^{u}",       #   small u, circumflex accent
660     "Ugrave"    =>      "\\`{U}",       #   capital U, grave accent
661     "ugrave"    =>      "\\`{u}",       #   small u, grave accent
662     "Uuml"      =>      '\\"{U}',       #   capital U, dieresis or umlaut mark
663     "uuml"      =>      '\\"{u}',       #   small u, dieresis or umlaut mark
664     "Yacute"    =>      "\\'{Y}",       #   capital Y, acute accent
665     "yacute"    =>      "\\'{y}",       #   small y, acute accent
666     "yuml"      =>      '\\"{y}',       #   small y, dieresis or umlaut mark
667 );
668 }
669 !NO!SUBS!
670
671 close OUT or die "Can't close $file: $!";
672 chmod 0755, $file or die "Can't reset permissions for $file: $!\n";
673 exec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';