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