Code

Created trunk inside of 2.6-lhm
[gosa.git] / trunk / gosa-core / contrib / latex2html
1 #! /usr/bin/perl
2 #
3 # $Id: latex2html.pin,v 1.71 2004/01/06 23:49:54 RRM Exp $
4 #
5 # Comprises patches and revisions by various authors:
6 #   See Changes, the log file of LaTeX2HTML.
7 #
8 # Original Copyright notice:
9 #
10 # LaTeX2HTML by Nikos Drakos <nikos@cbl.leeds.ac.uk>
12 # ****************************************************************
13 # LaTeX To HTML Translation **************************************
14 # ****************************************************************
15 # LaTeX2HTML is a Perl program that translates LaTeX source
16 # files into HTML (HyperText Markup Language). For each source
17 # file given as an argument the translator will create a
18 # directory containing the corresponding HTML files.
19 #
20 # The man page for this program is included at the end of this file
21 # and can be viewed using "perldoc latex2html"
22 #
23 # For more information on this program and some examples of its
24 # capabilities visit 
25 #
26 #          http://www.latex2html.org/
27 #
28 # or see the accompanying documentation in the docs/  directory
29 #
30 # or
31 #
32 #    http://www-texdev.ics.mq.edu.au/l2h/docs/manual/
33 #
34 # or
35 #
36 #    http://www.cbl.leeds.ac.uk/nikos/tex2html/doc/latex2html/
37 #
38 # Original code written by Nikos Drakos, July 1993.
39 #
40 # Address: Computer Based Learning Unit
41 #          University of Leeds
42 #          Leeds,  LS2 9JT
43 #
44 # Copyright (c) 1993-95. All rights reserved.
45 #
46 #
47 # Extensively modified by Ross Moore, Herb Swan and others
48 #
49 # Address: Mathematics Department
50 #          Macquarie University
51 #          Sydney, Australia, 2109 
52 #
53 # Copyright (c) 1996-2001. All rights reserved.
54 #
55 # See general license in the LICENSE file.
56 #
57 ##########################################################################
59 use 5.003; # refuse to work with old and buggy perl version
60 #use strict;
61 #use diagnostics;
63 # include some perl packages; these come with the standard distribution
64 use Getopt::Long;
65 use Fcntl;
66 use AnyDBM_File;
68 # The following are global variables that also appear in some modules
69 use vars qw($LATEX2HTMLDIR $LATEX2HTMLPLATDIR $SCRIPT
70             %Month %used_icons $inside_tabbing $TABLE_attribs
71             %mathentities $date_name $outer_math $TABLE__CELLPADDING_rx);
73 BEGIN {
74   # print "scanning for l2hdir\n";
75   if($ENV{'LATEX2HTMLDIR'}) {
76     $LATEX2HTMLDIR = $ENV{'LATEX2HTMLDIR'};
77   } else {
78     $ENV{'LATEX2HTMLDIR'} = $LATEX2HTMLDIR = '/usr/share/latex2html';
79   }
81   if($ENV{'LATEX2HTMLPLATDIR'}) {
82     $LATEX2HTMLPLATDIR = $ENV{'LATEX2HTMLPLATDIR'};
83   } else {
84     $LATEX2HTMLPLATDIR = '/usr/share/latex2html'||$LATEX2HTMLDIR;
85     $ENV{'LATEX2HTMLPLATDIR'} = $LATEX2HTMLPLATDIR;
86   }
87   if(-d $LATEX2HTMLPLATDIR) {
88     push(@INC,$LATEX2HTMLPLATDIR);
89   }
91   if(-d $LATEX2HTMLDIR) {
92     push(@INC,$LATEX2HTMLDIR);
93   } else {
94     die qq{Fatal: Directory "$LATEX2HTMLDIR" does not exist.\n};
95   }
96 }
98 use L2hos; # Operating system dependent routines
100 # $^W = 1; # turn on warnings
102 my $RELEASE = '2002-2-1';
103 my ($REVISION) = q$Revision: 1.71 $ =~ /:\s*(\S+)/;
105 # The key, which delimts expressions defined in the environment
106 # depends on the operating system. 
107 $envkey = L2hos->pathd();
109 # $dd is the directory delimiter character
110 $dd = L2hos->dd();
112 # make sure the $LATEX2HTMLDIR is on the search-path for forked processes
113 if($ENV{'PERL5LIB'}) {
114   $ENV{'PERL5LIB'} .= "$envkey$LATEX2HTMLDIR"
115     unless($ENV{'PERL5LIB'} =~ m|\Q$LATEX2HTMLDIR\E|o);
116 } else {
117   $ENV{'PERL5LIB'} = $LATEX2HTMLDIR;
120 # Local configuration, read at runtime
121 # Read the $CONFIG_FILE  (usually l2hconf.pm )
122 if($ENV{'L2HCONFIG'}) {
123   require $ENV{'L2HCONFIG'} ||
124     die "Fatal (require $ENV{'L2HCONFIG'}): $!";
125 } else {
126   eval 'use l2hconf';
127   if($@) {
128     die "Fatal (use l2hconf): $@\n";
129   }
132 # MRO: Changed this to global value in config/config.pl
133 # change these whenever you do a patch to this program and then
134 # name the resulting patch file accordingly
135 # $TVERSION = "2002-2-1";
136 #$TPATCHLEVEL = " beta";
137 #$TPATCHLEVEL = " release";
138 #$RELDATE = "(March 30, 1999)";
139 #$TEX2HTMLV_SHORT = $TVERSION . $TPATCHLEVEL;
141 $TEX2HTMLV_SHORT = $RELEASE;
142 $TEX2HTMLVERSION = "$TEX2HTMLV_SHORT ($REVISION)";
143 $TEX2HTMLADDRESS = "http://www.latex2html.org/";
144 $AUTHORADDRESS = "http://cbl.leeds.ac.uk/nikos/personal.html";
145 #$AUTHORADDRESS2 = "http://www-math.mpce.mq.edu.au/%7Eross/";
146 $AUTHORADDRESS2 = "http://www.maths.mq.edu.au/&#126;ross/";
148 # Set $HOME to what the system considers the home directory
149 $HOME = L2hos->home();
150 push(@INC,$HOME);
152 # flush stdout with every print -- gives better feedback during
153 # long computations
154 $| = 1;
156 # set Perl's subscript separator to LaTeX's illegal character.
157 # (quite defensive but why not)
158 $; = "\000";
160 # No arguments!!
161 unless(@ARGV) {
162   die "Error: No files to process!\n";
165 # Image prefix
166 $IMAGE_PREFIX = '_image';
168 # Partition prefix 
169 $PARTITION_PREFIX = 'part_' unless $PARTITION_PREFIX;
171 # Author address
172 @address_data = &address_data('ISO');
173 $ADDRESS = "$address_data[0]\n$address_data[1]";
175 # ensure non-zero defaults
176 $MAX_SPLIT_DEPTH = 4 unless ($MAX_SPLIT_DEPTH);
177 $MAX_LINK_DEPTH = 4 unless ($MAX_LINK_DEPTH);
178 $TOC_DEPTH = 4 unless ($TOC_DEPTH);
180 # A global value may already be set in the $CONFIG_FILE
181 $INIT_FILE_NAME = $ENV{'L2HINIT_NAME'} || '.latex2html-init'
182    unless $INIT_FILE_NAME;
184 # Read the $HOME/$INIT_FILE_NAME if one is found
185 if (-f "$HOME$dd$INIT_FILE_NAME" && -r _) {
186     print "Note: Loading $HOME$dd$INIT_FILE_NAME\n";
187     require("$HOME$dd$INIT_FILE_NAME");
188     $INIT_FILE = "$HOME$dd$INIT_FILE_NAME";
189     # _MRO_TODO_: Introduce a version to be checked?
190     die "Error: You have an out-of-date " . $HOME .
191         "$dd$INIT_FILE_NAME file.\nPlease update or delete it.\n"
192         if ($DESTDIR eq '.');
195 # Read the $INIT_FILE_NAME file if one is found in current directory
196 if ( L2hos->Cwd() ne $HOME && -f ".$dd$INIT_FILE_NAME" && -r _) {
197     print "Note: Loading .$dd$INIT_FILE_NAME\n";
198     require(".$dd$INIT_FILE_NAME");
199     $INIT_FILE = "$INIT_FILE_NAME";
201 die "Error: '.' is an incorrect setting for DESTDIR.\n" .
202     "Please check your $INIT_FILE_NAME file.\n"
203     if ($DESTDIR eq '.');
205 # User home substitutions
206 $LATEX2HTMLSTYLES =~ s/~([$dd$dd$envkey]|$)/$HOME$1/go;
207 # the next line fails utterly on non-UNIX systems
208 $LATEX2HTMLSTYLES =~ s/~([^$dd$dd$envkey]+)/L2hos->home($1)/geo;
210 #absolutise the paths
211 $LATEX2HTMLSTYLES = join($envkey,
212                         map(L2hos->Make_directory_absolute($_),
213                                 split(/$envkey/o, $LATEX2HTMLSTYLES)));
215 #HWS:  That was the last reference to HOME.  Now set HOME to $LATEX2HTMLDIR,
216 #       to enable dvips to see that version of .dvipsrc!  But only if we
217 #       have DVIPS_MODE not set - yes - this is a horrible nasty kludge
218 # MRO: The file has to be updated by configure _MRO_TODO_
220 if ($PK_GENERATION && ! $DVIPS_MODE) {
221     $ENV{HOME} =  $LATEX2HTMLDIR;
222     delete $ENV{PRINTER}; # Overrides .dvipsrc
225 # language of the DTD specified in the <DOCTYPE...> tag
226 $ISO_LANGUAGE = 'EN' unless $ISO_LANGUAGE;
228 # Save the command line arguments, quote where necessary
229 $argv = join(' ', map {/[\s#*!\$%]/ ? "'$_'" : $_ } @ARGV);
231 # Pre-process the command line for backward compatibility
232 foreach(@ARGV) {
233   s/^--?no_/-no/; # replace e.g. no_fork by nofork
234   # s/^[+](\d+)$/$1/; # remove + in front of integers
237 # Process command line options
238 my %opt;
239 unless(GetOptions(\%opt, # all non-linked options go into %opt
240         # option                linkage (optional)
241         'help|h',
242         'version|V',
243         'split=s',
244         'link=s',
245         'toc_depth=i',          \$TOC_DEPTH,
246         'toc_stars!',           \$TOC_STARS,
247         'short_extn!',          \$SHORTEXTN,
248         'iso_language=s',       \$ISO_LANGUAGE,
249         'validate!',            \$HTML_VALIDATE,
250         'latex!',
251         'djgpp!',               \$DJGPP,
252         'fork!',                \$CAN_FORK,
253         'external_images!',     \$EXTERNAL_IMAGES,
254         'ascii_mode!',          \$ASCII_MODE,
255         'lcase_tags!',          \$LOWER_CASE_TAGS,
256         'ps_images!',           \$PS_IMAGES,
257         'font_size=s',          \$FONT_SIZE,
258         'tex_defs!',            \$TEXDEFS,
259         'navigation!',
260         'top_navigation!',      \$TOP_NAVIGATION,
261         'bottom_navigation!',   \$BOTTOM_NAVIGATION,
262         'auto_navigation!',     \$AUTO_NAVIGATION,
263         'index_in_navigation!', \$INDEX_IN_NAVIGATION,
264         'contents_in_navigation!', \$CONTENTS_IN_NAVIGATION,
265         'next_page_in_navigation!', \$NEXT_PAGE_IN_NAVIGATION,
266         'previous_page_in_navigation!', \$PREVIOUS_PAGE_IN_NAVIGATION,
267         'footnode!',
268         'numbered_footnotes!',  \$NUMBERED_FOOTNOTES,
269         'prefix=s',             \$PREFIX,
270         'auto_prefix!',         \$AUTO_PREFIX,
271         'long_titles=i',        \$LONG_TITLES,
272         'custom_titles!',       \$CUSTOM_TITLES,
273         'title|t=s',            \$TITLE,
274         'rooted!',              \$ROOTED,
275         'rootdir=s',
276         'dir=s',                \$FIXEDDIR,
277         'mkdir',                \$MKDIR,
278         'address=s',            \$ADDRESS,
279         'noaddress',
280         'subdir!',
281         'info=s',               \$INFO,
282         'noinfo',
283         'auto_link!',
284         'reuse=i',              \$REUSE,
285         'noreuse',
286         'antialias_text!',      \$ANTI_ALIAS_TEXT,
287         'antialias!',           \$ANTI_ALIAS,
288         'transparent!',         \$TRANSPARENT_FIGURES,
289         'white!',               \$WHITE_BACKGROUND,
290         'discard!',             \$DISCARD_PS,
291         'image_type=s',         \$IMAGE_TYPE,
292         'images!',
293         'accent_images=s',      \$ACCENT_IMAGES,
294         'noaccent_images',
295         'style=s',              \$STYLESHEET,
296         'parbox_images!',
297         'math!',
298         'math_parsing!',
299         'latin!',
300         'entities!',            \$USE_ENTITY_NAMES,
301         'local_icons!',         \$LOCAL_ICONS,
302         'scalable_fonts!',      \$SCALABLE_FONTS,
303         'images_only!',         \$IMAGES_ONLY,
304         'show_section_numbers!',\$SHOW_SECTION_NUMBERS,
305         'show_init!',           \$SHOW_INIT_FILE,
306         'init_file=s',          \$INIT_FILE,
307         'up_url=s',             \$EXTERNAL_UP_LINK,
308         'up_title=s',           \$EXTERNAL_UP_TITLE,
309         'down_url=s',           \$EXTERNAL_DOWN_LINK,
310         'down_title=s',         \$EXTERNAL_DOWN_TITLE,
311         'prev_url=s',           \$EXTERNAL_PREV_LINK,
312         'prev_title=s',         \$EXTERNAL_PREV_TITLE,
313         'index=s',              \$EXTERNAL_INDEX,
314         'biblio=s',             \$EXTERNAL_BIBLIO,
315         'contents=s',           \$EXTERNAL_CONTENTS,
316         'external_file=s',      \$EXTERNAL_FILE,
317         'short_index!',         \$SHORT_INDEX,
318         'unsegment!',           \$UNSEGMENT,
319         'debug!',               \$DEBUG,
320         'tmp=s',                \$TMP,
321         'ldump!',               \$LATEX_DUMP,
322         'timing!',              \$TIMING,
323         'verbosity=i',          \$VERBOSITY,
324         'html_version=s',       \$HTML_VERSION,
325         'strict!',              \$STRICT_HTML,
326         'xbit!',                \$XBIT_HACK,
327         'ssi!',                 \$ALLOW_SSI,
328         'php!',                 \$ALLOW_PHP,
329         'test_mode!' # undocumented switch
330        )) {
331     &usage();
332     exit 1;
335 # interpret options, check option consistency
336 if(defined $opt{'split'}) {
337     if ($opt{'split'} =~ /^(\+?)(\d+)$/) {
338         $MAX_SPLIT_DEPTH = $2;
339         if ($1) { $MAX_SPLIT_DEPTH *= -1; $REL_DEPTH = 1; }
340     } else { 
341         &usage;
342         die "Error: Unrecognised value for -split: $opt{'split'}\n";
343     }
345 if(defined $opt{'link'}) {
346     if ($opt{'link'} =~ /^(\+?)(\d+)$/) {
347         $MAX_LINK_DEPTH = $2;
348         if ($1) { $MAX_LINK_DEPTH *= -1 }
349     } else { 
350         &usage;
351         die "Error: Unrecognised value for -link: $opt{'link'}\n";
352     }
354 unless ($ISO_LANGUAGE =~ /^[A-Z.]+$/) {
355     die "Error: Language (-iso_language) must be uppercase and dots only: $ISO_LANGUAGE\n";
357 if ($HTML_VALIDATE && !$HTML_VALIDATOR) {
358     die "Error: Need a HTML_VALIDATOR when -validate is specified.\n";
360 &set_if_false($NOLATEX,$opt{latex}); # negate the option...
361 if ($ASCII_MODE || $PS_IMAGES) {
362     $EXTERNAL_IMAGES = 1;
364 if ($FONT_SIZE && $FONT_SIZE !~ /^\d+pt$/) {
365     die "Error: Font size (-font_size) must end with 'pt': $FONT_SIZE\n"
367 &set_if_false($NO_NAVIGATION,$opt{navigation});
368 &set_if_false($NO_FOOTNODE,$opt{footnode});
369 if (defined $TITLE && !length($TITLE)) {
370     die "Error: Empty title (-title).\n";
372 if ($opt{rootdir}) {
373     $ROOTED = 1;
374     $FIXEDDIR = $opt{rootdir};
376 if ($FIXEDDIR && !-d $FIXEDDIR) {
377     if ($MKDIR) {
378         print "\n *** creating directory: $FIXEDDIR ";
379         die "Failed: $!\n" unless (mkdir($FIXEDDIR, 0755));
380         # _TODO_ use File::Path to create a series of directories
381     } else {
382         &usage;
383         die "Error: Specified directory (-rootdir, -dir) does not exist.\n";
384     }
386 &set_if_false($NO_SUBDIR, $opt{subdir});
387 &set_if_false($NO_AUTO_LINK, $opt{auto_link});
388 if ($opt{noreuse}) {
389     $REUSE = 0;
391 unless(grep(/^\Q$IMAGE_TYPE\E$/o, @IMAGE_TYPES)) {
392     die <<"EOF";
393 Error: No such image type '$IMAGE_TYPE'.
394        This installation supports (first is default): @IMAGE_TYPES
395 EOF
397 &set_if_false($NO_IMAGES, $opt{images});
398 if ($opt{noaccent_images}) {
399     $ACCENT_IMAGES = '';
401 if($opt{noaddress}) {
402     $ADDRESS = '';
404 if($opt{noinfo}) {
405     $INFO = 0;
407 if($ACCENT_IMAGES && $ACCENT_IMAGES !~ /^[a-zA-Z,]+$/) {
408     die "Error: Single word or comma-list of style words needed for -accent_images, not: $_\n";
410 &set_if_false($NO_PARBOX_IMAGES, $opt{parbox_images});
411 &set_if_false($NO_SIMPLE_MATH, $opt{math});
412 if (defined $opt{math_parsing}) {
413     $NO_MATH_PARSING = !$opt{math_parsing};
414     $NO_SIMPLE_MATH = !$opt{math_parsing} unless(defined $opt{math});
416 &set_if_false($NO_ISOLATIN, $opt{latin});
417 if ($INIT_FILE) {
418     if (-f $INIT_FILE && -r _) {
419         print "Note: Initialising with file: $INIT_FILE\n"
420             if ($DEBUG || $VERBOSITY);
421         require($INIT_FILE);
422     } else {
423         die "Error: Could not find file (-init_file): $INIT_FILE\n";
424     }
426 foreach($EXTERNAL_UP_LINK, $EXTERNAL_DOWN_LINK, $EXTERNAL_PREV_LINK,
427         $EXTERNAL_INDEX, $EXTERNAL_BIBLIO, $EXTERNAL_CONTENTS) {
428     $_ ||= ''; # initialize
429     s/~/&#126;/g; # protect `~'
431 if($TMP && !(-d $TMP && -w _)) {
432     die "Error: '$TMP' not usable as temporary directory.\n";
434 if ($opt{help}) {
435     L2hos->perldoc($SCRIPT);
436     exit 0;
438 if ($opt{version}) {
439     &banner();
440     exit 0;
442 if ($opt{test_mode}) {
443     return; # make /usr/bin/latex2html non-exploitable
444     $TITLE = 'LaTeX2HTML Test Document';
445     $TEXEXPAND = "$PERL /build/buildd/latex2html-2002-2-1-20050114${dd}texexpand";
446     $PSTOIMG   = "$PERL /build/buildd/latex2html-2002-2-1-20050114${dd}pstoimg";
447     $ICONSERVER = L2hos->path2URL("/build/buildd/latex2html-2002-2-1-20050114${dd}icons");
448     $TEST_MODE  = 1;
449     $RGBCOLORFILE = "/build/buildd/latex2html-2002-2-1-20050114${dd}styles${dd}rgb.txt";
450     $CRAYOLAFILE = "/build/buildd/latex2html-2002-2-1-20050114${dd}styles${dd}crayola.txt";
452 if($DEBUG) {
453     # make the OS-dependent functions more chatty, too
454     $L2hos::Verbose = 1;
457 undef %opt; # not needed any more
460 $FIXEDDIR = $FIXEDDIR || $DESTDIR || '';  # for backward compatibility
462 if ($EXTERNAL_UP_TITLE xor $EXTERNAL_UP_LINK) {
463     warn "Warning (-up_url, -up_title): Need to specify both a parent URL and a parent title!\n";
464     $EXTERNAL_UP_TITLE = $EXTERNAL_UP_LINK = "";
467 if ($EXTERNAL_DOWN_TITLE xor $EXTERNAL_DOWN_LINK) {
468     warn "Warning (-down_url, -down_title): Need to specify both a parent URL and a parent title!\n";
469     $EXTERNAL_DOWN_TITLE = $EXTERNAL_DOWN_LINK = "";
472 # $NO_NAVIGATION = 1 unless $MAX_SPLIT_DEPTH;   #  Martin Wilck
474 if ($MAX_SPLIT_DEPTH && $MAX_SPLIT_DEPTH < 0) {
475     $MAX_SPLIT_DEPTH *= -1; $REL_DEPTH = 1;
477 if ($MAX_LINK_DEPTH && $MAX_LINK_DEPTH < 0) {
478     $MAX_LINK_DEPTH *= -1; $LEAF_LINKS = 1;
481 $FOOT_FILENAME = 'footnode' unless ($FOOT_FILENAME);
482 $NO_FOOTNODE = 1 unless ($MAX_SPLIT_DEPTH || $NO_FOOTNODE);
483 $NO_SPLIT = 1 unless $MAX_SPLIT_DEPTH; # _MRO_TODO_: is this needed at all?
484 $SEGMENT = $SEGMENTED = 0;
485 $NO_MATH_MARKUP = 1;
487 # specify the filename extension to use with the generated HTML files
488 if ($SHORTEXTN) { $EXTN = ".htm"; }     # for HTML files on CDROM
489 elsif ($ALLOW_PHP) { $EXTN = ".php"; }  # has PHP dynamic includes
490         # with server-side includes (SSI) :
491 elsif ($ALLOW_SSI && !$XBIT_HACK) { $EXTN = ".shtml"; }
492         # ordinary names, valid also for SSI with XBit hack :
493 else { $EXTN = ".html"; }
495 $NODE_NAME = 'node' unless (defined $NODE_NAME);
497 # space for temporary files
498 # different to the $TMPDIR for image-generation
499 # MRO: No directory should end with $dd!
500 $TMP_ = "TMP";
502 $TMP_PREFIX = "l2h" unless ($TMP_PREFIX);
504 # This can be set to 1 when using a version of dvips that is safe
505 # from the "dot-in-name" bug.
506 # _TODO_ this should be determined by configure
507 $DVIPS_SAFE = 1;
509 $CHARSET = $charset || 'iso-8859-1';
511 ####################################################################
513 # If possible, use icons of the same type as generated images
515 if ($IMAGE_TYPE && defined %{"icons_$IMAGE_TYPE"}) {
516     %icons = %{"icons_$IMAGE_TYPE"};
519 ####################################################################
521 # Figure out what options we need to pass to DVIPS and store that in
522 # the $DVIPSOPT variable.  Also, scaling is taken care of at the
523 # dvips level if PK_GENERATION is set to 1, so adjust SCALE_FACTORs
524 # accordingly.
526 if ($SCALABLE_FONTS) {
527     $PK_GENERATION = 0;
528     $DVIPS_MODE = '';
531 if ($PK_GENERATION) {
532     if ($MATH_SCALE_FACTOR <= 0) { $MATH_SCALE_FACTOR = 2; }
533     if ($FIGURE_SCALE_FACTOR <= 0) { $FIGURE_SCALE_FACTOR = 2; }
534     my $saveMSF = $MATH_SCALE_FACTOR;
535     my $saveFSF = $FIGURE_SCALE_FACTOR;
536     my $desired_dpi = int($MATH_SCALE_FACTOR*75);
537     $FIGURE_SCALE_FACTOR = ($METAFONT_DPI / 72) *
538         ($FIGURE_SCALE_FACTOR / $MATH_SCALE_FACTOR) ;
539     $MATH_SCALE_FACTOR = $METAFONT_DPI / 72;
540     $dvi_mag = int(1000 * $desired_dpi / $METAFONT_DPI);
541     if ($dvi_mag > 1000) {
542         &write_warnings(
543             "WARNING: Your SCALE FACTOR is too large for PK_GENERATION.\n" .
544             "         See $CONFIG_FILE for more information.\n");
545     }
547     # RRM: over-sized scaling, using dvi-magnification
548     if ($EXTRA_IMAGE_SCALE) {
549         print "\n *** Images at $EXTRA_IMAGE_SCALE times resolution of displayed size ***\n";
550         $desired_dpi = int($EXTRA_IMAGE_SCALE * $desired_dpi+.5);
551         print "    desired_dpi = $desired_dpi  METAFONT_DPI = $METAFONT_DPI\n"
552             if $DEBUG;
553         $dvi_mag = int(1000 * $desired_dpi / $METAFONT_DPI);
554         $MATH_SCALE_FACTOR = $saveMSF;
555         $FIGURE_SCALE_FACTOR = $saveFSF;
556     }
557     # no space after "-y", "-D", "-e" --- required by DVIPS under DOS !
558     my $mode_switch = "-mode $DVIPS_MODE" if $DVIPS_MODE;
559     $DVIPSOPT .= " -y$dvi_mag -D$METAFONT_DPI $mode_switch -e5 ";
560 } else { # no PK_GENERATION
561 #    if ($EXTRA_IMAGE_SCALE) {
562 #       &write_warnings(
563 #          "the \$EXTRA_IMAGE_SCALE feature requires either \$PK_GENERATION=1"
564 #                       . " or the '-scalable_fonts' option");
565 #       $EXTRA_IMAGE_SCALE = '';
566 #    }
567     # MRO: shifted to l2hconf
568     #$DVIPSOPT .= ' -M';
569 } # end PK_GENERATION
571 # The mapping from numbers to accents.
572 # These are required to process the \accent command, which is found in
573 # tables of contents whenever there is an accented character in a
574 # caption or section title.  Processing the \accent command makes
575 # $encoded_*_number work properly (see &extract_captions) with
576 # captions that contain accented characters.
577 # I got the numbers from the plain.tex file, version 3.141.
579 # Missing entries should be looked up by a native speaker.
580 # Have a look at generate_accent_commands and $iso_8859_1_character_map.
582 # MEH: added more accent types
583 # MRO: only uppercase needed!
584 %accent_type = (
585    '18' => 'grave',             # \`
586    '19' => 'acute',             # `'
587    '20' => 'caron',             # \v
588    '21' => 'breve',             # \u
589    '22' => 'macr',              # \=
590    '23' => 'ring',              #
591    '24' => 'cedil',             # \c
592    '94' => 'circ',              # \^
593    '95' => 'dot',               # \.
594    '7D' => 'dblac',             # \H
595    '7E' => 'tilde',             # \~
596    '7F' => 'uml',               # \"
597 );
599 &driver;
601 exit 0; # clean exit, no errors
603 ############################ Subroutines ##################################
605 #check that $TMP is writable, if so create a subdirectory
606 sub make_tmp_dir {
607     &close_dbm_database if $DJGPP; # to save file-handles
609     # determine a suitable temporary path
610     #
611     $TMPDIR = '';
612     my @tmp_try = ();
613     push(@tmp_try, $TMP) if($TMP);
614     push(@tmp_try, "$DESTDIR$dd$TMP_") if($TMP_);
615     push(@tmp_try, $DESTDIR) if($DESTDIR);
616     push(@tmp_try, L2hos->Cwd());
618     my $try;
619     TempTry: foreach $try (@tmp_try) {
620       next unless(-d $try && -w _);
621       my $tmp = "$try$dd$TMP_PREFIX$$";
622       if(mkdir($tmp,0755)) {
623         $TMPDIR=$tmp;
624         last TempTry;
625       } else {
626         warn "Warning: Cannot create temporary directory '$tmp': $!\n";
627       }
628     }
630     $dvips_warning = <<"EOF";
632 Warning: There is a '.' in \$TMPDIR, $DVIPS will probably fail.
633 Set \$TMP to use a /tmp directory, or rename the working directory.
634 EOF
635     die ($dvips_warning . "\n\$TMPDIR=$TMPDIR  ***\n\n")
636         if ($TMPDIR =~ /\./ && $DVIPS =~ /dvips/ && !$DVIPS_SAFE);
638     &open_dbm_database if $DJGPP;
641 # MRO: set first parameter to the opposite of the second if second parameter is defined
642 sub set_if_false {
643     $_[0] = !$_[1] if(defined $_[1]);
646 sub check_for_dots {
647     local($file) = @_;
648     if ($file =~ /\.[^.]*\./ && !$DVIPS_SAFE) {
649         die "\n\n\n *** Fatal Error --- but easy to fix ***\n"
650             . "\nCannot have '.' in file-name prefix, else dvips fails on images"
651             . "\nChange the name from  $file  and try again.\n\n";
652     }
655 # Process each file ...
656 sub driver {
657     local($FILE, $orig_cwd, %unknown_commands, %dependent, %depends_on
658           , %styleID, %env_style, $bbl_cnt, $dbg, %numbered_section);
659     # MRO: $texfilepath has to be global!
660     local(%styles_loaded);
661     $orig_cwd = L2hos->Cwd();
663     print "\n *** initialise *** " if ($VERBOSITY > 1);
664     &initialise;                # Initialise some global variables
666     print "\n *** check modes *** " if ($VERBOSITY > 1);
667     &ascii_mode if $ASCII_MODE; # Must come after initialization
668     &titles_language($TITLES_LANGUAGE);
669     &make_numbered_footnotes if ($NUMBERED_FOOTNOTES);
670     $dbg = $DEBUG ? "-debug" : "";
671     $dbg .= (($VERBOSITY>2) ? " -verbose" : "");
673     #use the same hashes for all files in a batch
674     local(%cached_env_img, %id_map, %symbolic_labels, %latex_labels)
675         if ($FIXEDDIR && $NO_SUBDIR);
677     local($MULTIPLE_FILES,$THIS_FILE);
678     $MULTIPLE_FILES = 1+$#ARGV if $ROOTED;
679     print "\n *** $MULTIPLE_FILES file".($MULTIPLE_FILES ? 's: ' : ': ')
680         . join(',',@ARGV) . " *** " if ($VERBOSITY > 1);
682     local(%section_info, %toc_section_info, %cite_info, %ref_files);
683     
684     foreach $FILE (@ARGV) {
685         &check_for_dots($FILE) unless $DVIPS_SAFE;
686         ++$THIS_FILE if $MULTIPLE_FILES;
687         do {
688             %section_info = ();
689             %toc_section_info = ();
690             %cite_info = ();
691             %ref_files = ();
692         } unless $MULTIPLE_FILES;
693         local($bbl_nr) = 1;
695         # The number of reused images and those in images.tex
696         local($global_page_num) = (0) unless($FIXEDDIR && $NO_SUBDIR);
697         # The number of images in images.tex
698         local($new_page_num) = (0); # unless($FIXEDDIR && $NO_SUBDIR);
699         local($pid, $sections_rx,
700             , $outermost_level, %latex_body, $latex_body
701             , %encoded_section_number
702             , %verbatim, %new_command, %new_environment
703             , %provide_command, %renew_command, %new_theorem
704             , $preamble, $aux_preamble, $prelatex, @preamble);
706         # must retain these when all files are in the same directory
707         # else the images.pl and labels.pl files get clobbered
708         unless ($FIXEDDIR && $NO_SUBDIR) {
709             print "\nResetting image-cache" if ($#ARGV);
710             local(%cached_env_img, %id_map, %symbolic_labels, %latex_labels)
711         }
713 ## AYS: Allow extension other than .tex and make it optional
714         ($EXT = $FILE) =~ s/.*\.([^\.]*)$/$1/;
715         if ( $EXT eq $FILE ) {
716             $EXT = "tex";
717             $FILE =~ s/$/.tex/;
718         }
720         #RRM: allow user-customisation, dependent on file-name
721         # e.g. add directories to $TEXINPUTS named for the file
722         # --- idea due to Fred Drake <fdrake@acm.org>
723         &custom_driver_hook($FILE) if (defined &custom_driver_hook);
725 # JCL(jcl-dir)
726 # We need absolute paths for TEXINPUTS here, because
727 # we change the directory
728         if ($orig_cwd eq $texfilepath) {
729             &deal_with_texinputs($orig_cwd);
730         } else {
731             &deal_with_texinputs($orig_cwd, $texfilepath);
732         }
734         ($texfilepath, $FILE) = &get_full_path($FILE);
735         $texfilepath = '.' unless($texfilepath);
737         die "Cannot read $texfilepath$dd$FILE \n"
738             unless (-f "$texfilepath$dd$FILE");
741 # Tell texexpand which files we *don't* want to look at.
742         $ENV{'TEXE_DONT_INCLUDE'} = $DONT_INCLUDE if $DONT_INCLUDE;
743 # Tell texexpand which files we *do* want to look at, e.g.
744 # home-brew style files
745         $ENV{'TEXE_DO_INCLUDE'} = $DO_INCLUDE if $DO_INCLUDE;
747         $FILE =~ s/\.[^\.]*$//; ## AYS
748         $DESTDIR = ''; # start at empty
749         if ($FIXEDDIR) {
750             $DESTDIR = $FIXEDDIR unless ($FIXEDDIR eq '.');
751             if (($ROOTED)&&!($texfilepath eq $orig_cwd)) {
752                 $DESTDIR .= $dd . $FILE unless $NO_SUBDIR;
753             };
754         } elsif ($texfilepath eq $orig_cwd) {
755             $DESTDIR = ($NO_SUBDIR ? '.' : $FILE);
756         } else {
757             $DESTDIR = $ROOTED ? '.' : $texfilepath;
758             $DESTDIR .= $dd . $FILE unless $NO_SUBDIR;
759         }
760         $PREFIX  = "$FILE-" if $AUTO_PREFIX;
762         print "\nOPENING $texfilepath$dd$FILE.$EXT \n"; ## AYS
764         next unless (&new_dir($DESTDIR,''));
765         # establish absolute path to $DESTDIR
766         $DESTDIR = L2hos->Make_directory_absolute($DESTDIR);
767         &make_tmp_dir;
768         print "\nNote: Working directory is $DESTDIR\n";
769         print "Note: Images will be generated in $TMPDIR\n\n";
771 # Need to clean up a bit in case there's garbage left
772 # from former runs.
773         if ($DESTDIR) { chdir($DESTDIR) || die "$!\n"; }
774         if (opendir (TMP,$TMP_)) {
775             foreach (readdir TMP) {
776                 L2hos->Unlink("TMP_$dd$_") unless (/^\.\.?$/);
777             }
778             closedir TMP; 
779         }
780         &cleanup(1);
781         unless(-d $TMP_) {
782             mkdir($TMP_, 0755) ||
783               die "Cannot create directory '$TMP_': $!\n";
784         }
785         chdir($orig_cwd);
787 # RRM 14/5/98  moved this to occur earlier
788 ## JCL(jcl-dir)
789 ## We need absolute paths for TEXINPUTS here, because
790 ## we change the directory
791 #       if ($orig_cwd eq $texfilepath) {
792 #           &deal_with_texinputs($orig_cwd);
793 #       } else {
794 #           &deal_with_texinputs($orig_cwd, $texfilepath);
795 #       }
798 # This needs $DESTDIR to have been created ...
799         print " *** calling  `texexpand' ***" if ($VERBOSITY > 1);
800         local($unseg) = ($UNSEGMENT ? "-unsegment " : "");
802 # does DOS need to check these here ?
803 #       die "File $TEXEXPAND does not exist or is not executable\n"
804 #           unless (-x $TEXEXPAND);
805         L2hos->syswait("$TEXEXPAND $dbg -auto_exclude $unseg"
806                  . "-save_styles $DESTDIR$dd$TMP_${dd}styles "
807                  . ($TEXINPUTS ? "-texinputs $TEXINPUTS " : '' )
808                  . (($VERBOSITY >2) ? "-verbose " : '' )
809                  . "-out $DESTDIR$dd$TMP_$dd$FILE "
810                  . "$texfilepath$dd$FILE.$EXT")
811             && die " texexpand  failed: $!\n";
812         print STDOUT "\n ***  `texexpand' done ***\n" if ($VERBOSITY > 1);
814         chdir($DESTDIR) if $DESTDIR;
815         $SIG{'INT'} = 'handler';
817         &open_dbm_database;
818         &initialise_sections;
819         print STDOUT "\n ***  database open ***\n" if ($VERBOSITY > 1);
821         if ($IMAGES_ONLY) {
822             &make_off_line_images;
823         } else {
824             &rename_image_files;
825             &load_style_file_translations;
826             &make_language_rx;
827             &make_raw_arg_cmd_rx;
828 #           &make_isolatin1_rx unless ($NO_ISOLATIN);
829             &translate_titles;
830             &make_sections_rx;
831             print "\nReading ...";
832             if ($SHORT_FILENAME) {
833                 L2hos->Rename ("$TMP_$dd$FILE" ,"$TMP_$dd$SHORT_FILENAME" );
834                 &slurp_input_and_partition_and_pre_process(
835                       "$TMP_$dd$SHORT_FILENAME");
836             } else {
837                 &slurp_input_and_partition_and_pre_process("$TMP_$dd$FILE");
838             }
839             &add_preamble_head;
840             # Create a regular expressions
841             &set_depth_levels;
842             &make_sections_rx;
843             &make_order_sensitive_rx;
844             &add_document_info_page if ($INFO && !(/\\htmlinfo/));
845             &add_bbl_and_idx_dummy_commands;
846             &translate; # Destructive!
847         }
848         &style_sheet;
849         &close_dbm_database;
850         &cleanup();
852 #JCL: read warnings from file to $warnings
853         local($warnings) = &get_warnings;
854         print "\n\n*********** WARNINGS ***********  \n$warnings"
855             if ($warnings || $NO_IMAGES || $IMAGES_ONLY);
856         &image_cache_message if ($NO_IMAGES || $IMAGES_ONLY);
857         &image_message if ($warnings =~ /Failed to convert/io);
858         undef $warnings;
860 # JCL - generate directory index entry.
861 # Yet, a hard link, cause Perl lacks symlink() on some systems.
862         do {
863             local($EXTN) = $EXTN;
864             $EXTN =~ s/_\w+(\.html?)/$1/ if ($frame_main_name);
865             local($from,$to) = (eval($LINKPOINT),eval($LINKNAME));
866             if (length($from) && length($to) && ($from ne $to)) {
867                 #frames may have altered $EXTN
868                 $from =~ s/$frame_main_name(\.html?)/$1/ if ($frame_main_name);
869                 $to =~ s/$frame_main_name(\.html?)/$1/ if ($frame_main_name);
870                 L2hos->Unlink($to);
871                 L2hos->Link($from,$to);
872             }
873         } unless ($NO_AUTO_LINK || !($LINKPOINT) || !($LINKNAME));
875         &html_validate if ($HTML_VALIDATE && $HTML_VALIDATOR);
877 # Go back to the source directory
878         chdir($orig_cwd);
879         $TEST_MODE = $DESTDIR if($TEST_MODE); # save path
880         $DESTDIR = '';
881         $OUT_NODE = 0 unless $FIXEDDIR;
882         $STYLESHEET = '' if ($STYLESHEET =~ /^\Q$FILE./);
883     }
884     print "\nUnknown commands: ". join(" ",keys %unknown_commands)
885         if %unknown_commands;
886 ###MEH -- math support
887     print "\nMath commands outside math: " .
888         join(" ",keys %commands_outside_math) .
889             "\n  Output may look weird or may be faulty!\n"
890                 if %commands_outside_math;
891     print "\nDone.\n";
892     if($TEST_MODE) {
893       $TEST_MODE =~ s:[$dd$dd]+$::;
894       print "\nTo view the results, point your browser at:\n",
895         L2hos->path2URL(L2hos->Make_directory_absolute($TEST_MODE).$dd.
896         "index$EXTN"),"\n";
897     }
898     $end_time = time; 
899     $total_time = $end_time - $start_time;
900     print STDOUT join(' ',"Timing:",$total_time,"seconds\n")
901         if ($TIMING||$DEBUG||($VERBOSITY > 2));
902     $_;
905 sub open_dbm_database {
906     # These are DBM (unix DataBase Management) arrays which are actually
907     # stored in external files. They are used for communication between
908     # the main process and forked child processes;
909     print STDOUT "\n"; # this mysteriously prevents a core dump !
911     dbmopen(%verb, "$TMP_${dd}verb",0755);
912 #    dbmopen(%verbatim, "$TMP_${dd}verbatim",0755);
913     dbmopen(%verb_delim, "$TMP_${dd}verb_delim",0755);
914     dbmopen(%expanded,"$TMP_${dd}expanded",0755);
915 # Holds max_id, verb_counter, verbatim_counter, eqn_number
916     dbmopen(%global, "$TMP_${dd}global",0755);
917 # Hold style sheet information
918     dbmopen(%env_style, "$TMP_${dd}envstyles",0755);
919     dbmopen(%txt_style, "$TMP_${dd}txtstyles",0755);
920     dbmopen(%styleID, "$TMP_${dd}styleIDs",0755);
922 # These next two are used during off-line image conversion
923 # %new_id_map maps image id's to page_numbers of the images in images.tex
924 # %image_params maps image_ids to conversion parameters for that image
925     dbmopen(%new_id_map, "$TMP_${dd}ID_MAP",0755);
926     dbmopen(%img_params, "$TMP_${dd}IMG_PARAMS",0755);
927     dbmopen(%orig_name_map, "$TMP_${dd}ORIG_MAP",0755);
929     $global{'max_id'} = ($global{'max_id'} | 0);
930     &read_mydb(\%verbatim, "verbatim");
931     $global{'verb_counter'} = ($global{'verb_counter'} | 0);
932     $global{'verbatim_counter'} = ($global{'verbatim_counter'} | 0);
934     &read_mydb(\%new_command, "new_command");
935     &read_mydb(\%renew_command, "renew_command");
936     &read_mydb(\%provide_command, "provide_command");
937     &read_mydb(\%new_theorem, "new_theorem");
938     &read_mydb(\%new_environment, "new_environment");
939     &read_mydb(\%dependent, "dependent");
940 #    &read_mydb(\%env_style, "env_style");
941 #    &read_mydb(\%styleID, "styleID");
942     # MRO: Why should we use read_mydb instead of catfile?
943     $preamble = &catfile(&_dbname("preamble"),1) || '';
944     $prelatex = &catfile(&_dbname("prelatex"),1) || '';
945     $aux_preamble = &catfile(&_dbname("aux_preamble"),1) || '';
946     &restore_critical_variables;
949 sub close_dbm_database {
950     &save_critical_variables;
951     dbmclose(%verb); undef %verb;
952 #    dbmclose(%verbatim); undef %verbatim;
953     dbmclose(%verb_delim); undef %verb_delim;
954     dbmclose(%expanded); undef %expanded;
955     dbmclose(%global); undef %global;
956     dbmclose(%env_style); undef %env_style;
957     dbmclose(%style_id); undef %style_id;
958     dbmclose(%new_id_map); undef %new_id_map;
959     dbmclose(%img_params); undef %img_params;
960     dbmclose(%orig_name_map); undef %orig_name_map;
961     dbmclose(%txt_style); undef %txt_style;
962     dbmclose(%styleID); undef %styleID;
965 sub clear_images_dbm_database {
966     # <Added calls to dbmclose dprhws>
967     # %new_id_map will be used by the off-line image conversion process
968     #
969     dbmclose(%new_id_map);
970     dbmclose(%img_params);
971     dbmclose(%orig_name_map);
972     undef %new_id_map;
973     undef %img_params;
974     undef %orig_name_map;
975     dbmopen(%new_id_map, "$TMP_${dd}ID_MAP",0755);
976     dbmopen(%img_params, "$TMP_${dd}IMG_PARAMS",0755);
977     dbmopen(%orig_name_map, "$TMP_${dd}ORIG_MAP",0755);
980 sub initialise_sections {
981     local($key);
982     foreach $key (keys %numbered_section) {
983         $global{$key} = $numbered_section{$key}}
986 sub save_critical_variables {
987     $global{'math_markup'} = $NO_MATH_MARKUP;
988     $global{'charset'} = $CHARSET;
989     $global{'charenc'} = $charset;
990     $global{'language'} = $default_language;
991     $global{'isolatin'} = $ISOLATIN_CHARS;
992     $global{'unicode'} = $UNICODE_CHARS;
993     if ($UNFINISHED_ENV) {
994         $global{'unfinished_env'} = $UNFINISHED_ENV;
995         $global{'replace_end_env'} = $REPLACE_END_ENV;
996     }
997     $global{'unfinished_comment'} = $UNFINISHED_COMMENT;
998     if (@UNMATCHED_OPENING) {
999         $global{'unmatched'} = join(',',@UNMATCHED_OPENING);
1000     }
1003 sub restore_critical_variables {
1004     $NO_MATH_MARKUP = ($global{'math_markup'}|
1005         (defined $NO_MATH_MARKUP ? $NO_MATH_MARKUP:1));
1006     $CHARSET = ($global{'charset'}| $CHARSET);
1007     $charset = ($global{'charenc'}| $charset);
1008     $default_language = ($global{'language'}|
1009         (defined $default_language ? $default_language:'english'));
1010     $ISOLATIN_CHARS = ($global{'isolatin'}|
1011         (defined $ISOLATIN_CHARS ? $ISOLATIN_CHARS:0));
1012     $UNICODE_CHARS = ($global{'unicode'}|
1013         (defined $UNICODE_CHARS ? $UNICODE_CHARS:0));
1014     if ($global{'unfinished_env'}) {
1015         $UNFINISHED_ENV = $global{'unfinished_env'};
1016         $REPLACE_END_ENV = $global{'replace_end_env'};
1017     }
1018     $UNFINISHED_COMMENT = $global{'unfinished_comment'};
1019     if ($global{'unmatched'}) {
1020         @UNMATCHED_OPENING = split(',',$global{'unmatched'});
1021     }
1023     # undef any renewed-commands...
1024     # so the new defs are read from %new_command
1025     local($cmd,$key,$code);
1026     foreach $key (keys %renew_command) {
1027         $cmd = "do_cmd_$key";
1028         $code = "undef \&$cmd"; eval($code) if (defined &$cmd);
1029         if ($@) { print "\nundef \&do_cmd_$cmd failed"}
1030     }
1033 #JCL: The warnings should have been handled within the DBM database.
1034 # Unfortunately if the contents of an array are more than ~900 (system
1035 # dependent) chars long then dbm cannot handle it and gives error messages.
1036 sub write_warnings { #clean
1037     my ($str) = @_;
1038     $str .= "\n" unless($str =~ /\n$/);
1039     print STDOUT "\n *** Warning: $str" if ($VERBOSITY > 1);
1040     my $warnings = '';
1041     if(-f 'WARNINGS') {
1042         $warnings = &catfile('WARNINGS') || '';
1043     }
1044     return () if ($warnings =~ /\Q$str\E/);
1045     if(open(OUT,">>WARNINGS")) {
1046         print OUT $str;
1047         close OUT;
1048     } else {
1049         print "\nError: Cannot append to 'WARNINGS': $!\n";
1050     }
1053 sub get_warnings {
1054     return &catfile('WARNINGS',1) || '';
1057 # MRO: Standardizing
1058 sub catfile {
1059     my ($file,$ignore) = @_;
1060     unless(open(CATFILE,"<$file")) {
1061         print "\nError: Cannot read '$file': $!\n"
1062             unless($ignore);
1063         return undef;
1064     }
1065     local($/) = undef; # slurp in whole file
1066     my $contents = <CATFILE>;
1067     close(CATFILE);
1068     $contents;
1072 sub html_validate {
1073     my ($extn) = $EXTN;
1074     if ($EXTN !~ /^\.html?$/i) {
1075         $extn =~ s/^[^\.]*(\.html?)$/$1/;
1076     }
1077     print "\n *** Validating ***\n";
1078     my @htmls = glob("*$extn");
1079     my $file;
1080     foreach $file (@htmls) {
1081       system("$HTML_VALIDATOR $file");
1082     }
1085 sub lost_argument {
1086     local($cmd) = @_;
1087     &write_warnings("\nincomplete argument to command: \\$cmd");
1091 # These subroutines should have been handled within the DBM database.
1092 # Unfortunately if the contents of an array are more than ~900 (system
1093 # dependent) chars long then dbm cannot handle it and gives error messages.
1094 # So here we save and then read the contents explicitly.
1095 sub write_mydb {
1096     my ($db, $key, $str) = @_;
1097     &write_mydb_simple($db, "\n$mydb_mark#$key#$str");
1100 # generate the DB file name from the DB name
1101 sub _dbname {
1102     "$TMP_$dd$_[0]";
1105 sub write_mydb_simple {
1106     my ($db, $str) = @_;
1107     my $file = &_dbname($db);
1108     if(open(DB,">>$file")) {
1109         print DB $str;
1110         close DB;
1111     } else {
1112         print "\nError: Cannot append to '$file': $!\n";
1113     }
1116 sub clear_mydb {
1117     my ($db) = @_;
1118     my $file = &_dbname($db);
1119     if(open(DB,">$file")) {
1120         close DB;
1121     } else {
1122         print "\nError: Cannot clear '$file': $!\n";
1123     }
1126 # Assumes the existence of a DB file which contains
1127 # sequences of e.g. verbatim counters and verbatim contents.
1128 sub read_mydb {
1129     my ($dbref,$name) = @_;
1130     my $contents = &catfile(&_dbname($name),1);
1131     return '' unless(defined $contents);
1132     my @tmp = split(/\n$mydb_mark#([^#]*)#/, $contents);
1133     my $i = 1;  # Ignore the first element at 0
1134     print "\nDBM: $name open..." if ($VERBOSITY > 2);
1135     while ($i < scalar(@tmp)) {
1136         my $tmp1 = $tmp[$i];
1137         my $tmp2 = $tmp[++$i];
1138         $$dbref{$tmp1} = defined $tmp2 ? $tmp2 : '';
1139         ++$i;
1140     };
1141     $contents;
1145 # Reads in a latex generated file (e.g. .bbl or .aux)
1146 # It returns success or failure
1147 # ****** and binds $_ in the caller as a side-effect ******
1148 sub process_ext_file {
1149     local($ext) = @_;
1150     local($found, $extfile,$dum,$texpath);
1151     $extfile =  $EXTERNAL_FILE||$FILE;
1152     local($file) = &fulltexpath("$extfile.$ext");
1153     $found = 0;
1154     &write_warnings(
1155             "\n$extfile.$EXT is newer than $extfile.$ext: Please rerun latex" . ## AYS
1156             (($ext =~ /bbl/) ? " and bibtex.\n" : ".\n"))
1157         if ( ($found = (-f $file)) &&
1158             &newer(&fulltexpath("$extfile.$EXT"), $file)); ## AYS
1159     if ((!$found)&&($extfile =~ /\.$EXT$/)) {
1160         $file = &fulltexpath("$extfile");
1161         &write_warnings(
1162             "\n$extfile is newer than $extfile: Please rerun latex" . ## AYS
1163             (($ext =~ /bbl/) ? " and bibtex.\n" : ".\n"))
1164             if ( ($found = (-f $file)) &&
1165                 &newer(&fulltexpath("$extfile"), $file)); ## AYS
1166     }
1168     # check in other directories on the $TEXINPUTS paths
1169     if (!$found) {
1170         foreach $texpath (split /$envkey/, $TEXINPUTS ) {
1171             $file = "$texpath$dd$extfile.$ext";
1172             last if ($found = (-f $file));
1173         }
1174     }
1175     if ( $found ) {
1176         print "\nReading $ext file: $file ...";
1177         # must allow @ within control-sequence names
1178         $dum = &do_cmd_makeatletter();
1179         &slurp_input($file);
1180         if ($ext =~ /bbl/) {
1181             # remove the \newcommand{\etalchar}{...} since not needed
1182             s/^\\newcommand{\\etalchar}[^\n\r]*[\n\r]+//s;
1183         }
1184         &pre_process;
1185         &substitute_meta_cmds if (%new_command || %new_environment);
1186         if ($ext eq "aux") {
1187             my $latex_pathname = L2hos->path2latex($file);
1188             $aux_preamble .=
1189                 "\\AtBeginDocument{\\makeatletter\n\\input $latex_pathname\n\\makeatother\n}\n";
1190             local(@extlines) = split ("\n", $_);
1191             print " translating ".(0+@extlines). " lines " if ($VERBOSITY >1);
1192             local($eline,$skip_to); #$_ = '';
1193             foreach $eline (@extlines) {
1194                 if ($skip_to) { next unless ($eline =~ s/$O$skip_to$C//) }
1195                 $skip_to = '';
1196                 # skip lines added for pdfTeX/hyperref compatibility
1197                 next if ($eline =~ /^\\(ifx|else|fi|global \\let|gdef|AtEndDocument|let )/);
1198                 # remove \index and \label commands, else invalid links may result
1199                 $eline =~ s/\\(index|label)\s*($O\d+$C).*\2//g;
1200                 if ($eline =~ /\\(old)?contentsline/) {
1201                     do { local($_,$save_AUX) = ($eline,$AUX_FILE);
1202                     $AUX_FILE = 0;
1203                     &wrap_shorthand_environments;
1204                     #footnote markers upset the numbering
1205                     s/\\footnote(mark|text)?//g;
1206                     $eline = &translate_environments($_);
1207                     $AUX_FILE = $save_AUX;
1208                     undef $_ };
1209                 } elsif ($eline =~ s/^\\\@input//) {
1210                     &do_cmd__at_input($eline);
1211                     $eline = '';
1212                 } elsif ($eline =~ s/^\\\@setckpt$O(\d+)$C//) {
1213                     $skip_to = $1; next;
1214                 }
1215 #           $eline =~ s/$image_mark#([^#]+)#/print "\nIMAGE:",$img_params{$1},"\n";''/e;
1216 #               $_ .= &translate_commands(&translate_environments($eline));
1217                 $_ .= &translate_commands($eline) if $eline;
1218             }
1219             undef @extlines;
1220         } elsif ($ext =~ /$caption_suffixes/) {
1221             local(@extlines) = split ("\n", $_);
1222             print " translating ".(0+@extlines). " lines "if ($VERBOSITY >1);
1223             local($eline); $_ = '';
1224             foreach $eline (@extlines) {
1225                 # remove \index and \label commands, else invalid links may result
1226                 $eline =~ s/\\(index|label)\s*($O\d+$C).*\2//gso;
1227                 if ($eline =~ /\\(old)?contentsline/) {
1228                     do { local($_,$save_PREAMBLE) = ($eline,$PREAMBLE);
1229                     $PREAMBLE = 0;
1230                     &wrap_shorthand_environments;
1231                     $eline = &translate_environments($_);
1232                     $PREAMBLE = $save_PREAMBLE;
1233                     undef $_ };
1234                 }
1235                 $_ .= &translate_commands($eline);
1236             }
1237             undef @extlines;
1238         } else {
1239             print " wrapping " if ($VERBOSITY >1);
1240             &wrap_shorthand_environments;
1241             $_ = &translate_commands(&translate_environments($_));
1242             print " translating " if ($VERBOSITY >1);
1243         }
1244         print "\n processed size: ".length($_)."\n" if($VERBOSITY>1);
1245         $dum = &do_cmd_makeatother();
1246     } else { 
1247         print "\n*** Could not find file: $file ***\n" if ($DEBUG)
1248     };
1249     $found;
1252 sub deal_with_texinputs {
1253 # The dot precedes all, this let's local files override always.
1254 # The dirs we want are given as parameter list.
1255     if(!$TEXINPUTS) { $TEXINPUTS = '.' }
1256     elsif ($TEXINPUTS =~ /^$envkey/) {
1257         $TEXINPUTS = '.'.$TEXINPUTS
1258     };
1259     if ($ROOTED) {$TEXINPUTS .= "$envkey$FIXEDDIR"}
1260     $TEXINPUTS = &absolutize_path($TEXINPUTS);
1261     $ENV{'TEXINPUTS'} = join($envkey,".",@_,$TEXINPUTS,$ENV{'TEXINPUTS'});
1264 # provided by Fred Drake
1265 sub absolutize_path {
1266     my ($path) = @_;
1267     my $npath = '';
1268     foreach $dir (split /$envkey/o, $path) {
1269         $npath .= L2hos->Make_directory_absolute($dir) . $envkey;
1270     }
1271     $npath =~ s/$envkey$//;
1272     $npath;
1275 sub add_document_info_page {
1276     # Uses $outermost_level
1277     # Nasty race conditions if the next two are done in parallel
1278     local($X) = ++$global{'max_id'};
1279     local($Y) = ++$global{'max_id'};
1280     ###MEH -- changed for math support: no underscores in commandnames
1281     $_ = join('', $_
1282               , (($MAX_SPLIT_DEPTH <= $section_commands{$outermost_level})?
1283                  "\n<HR>\n" : '')
1284               , "\\$outermost_level", "*"
1285               , "$O$X$C$O$Y$C\\infopagename$O$Y$C$O$X$C\n",
1286               , " \\textohtmlinfopage");
1290 # For each style file name in TMP_styles (generated by texexpand) look for a
1291 # perl file in $LATEX2HTMLDIR/styles and load it.
1292 sub load_style_file_translations {
1293     local($_, $style, $options, $dir);
1294     print "\n";
1295     if ($TEXDEFS) {
1296         foreach $dir (split(/$envkey/,$LATEX2HTMLSTYLES)) {
1297             if (-f ($_ = "$dir${dd}texdefs.perl")) {
1298                 print "\nLoading $_...";
1299                 require ($_);
1300                 $styles_loaded{'texdefs'} = 1;
1301                 last;
1302             }
1303         }
1304     }
1306     # packages automatically implemented
1307     local($auto_styles) = $AUTO_STYLES;
1308     $auto_styles .= 'array|' if ($HTML_VERSION > 3.1);
1309     $auto_styles .= 'tabularx|' if ($HTML_VERSION > 3.1);
1310     $auto_styles .= 'theorem|';
1312     # these are not packages, but can appear as if class-options
1313     $auto_styles .= 'psamsfonts|';
1314     $auto_styles .= 'noamsfonts|';
1316     $auto_styles =~ s/\|$//;
1318     if(open(STYLES, "<$TMP_${dd}styles")) {
1319         while(<STYLES>) {
1320             if(s/^\s*(\S+)\s*(.*)$/$style = $1; $options = $2;/eo) {
1321                 &do_require_package($style);
1322                 $_ = $DONT_INCLUDE;
1323                 s/:/|/g;
1324                 &write_warnings("No implementation found for style \`$style\'\n")
1325                     unless ($styles_loaded{$style} || $style =~ /^($_)$/
1326                         || $style =~ /$auto_styles/);
1328                 # MRO: Process options for packages
1329                 &do_package_options($style,$options) if($options);
1330             }
1331         }
1332         close(STYLES);
1333     } else {
1334         print "\nError: Cannot read '$TMP_${dd}styles': $!\n";
1335     }
1338 ################## Weird Special case ##################
1340 # The new texexpand can be told to leave in \input and \include
1341 # commands which contain code that the translator should simply pass
1342 # to latex, such as the psfig stuff.  These should still be seen by
1343 # TeX, so we add them to the preamble ...
1345 sub do_include_lines {
1346     while (s/$include_line_rx//o) {
1347         local($include_line) = &revert_to_raw_tex($&);
1348         &add_to_preamble ('include', $include_line);
1349     }
1352 ########################## Preprocessing ############################
1354 # JCL(jcl-verb)
1355 # The \verb declaration and the verbatim environment contain simulated
1356 # typed text and should not be processed. Characters such as $,\,{,and }
1357 # loose their special meanings and should not be considered when marking
1358 # brackets etc. To achieve this \verb declarations and the contents of
1359 # verbatim environments are replaced by markers. At the end the original
1360 # text is put back into the document.
1361 # The markers for verb and verbatim are different so that these commands
1362 # can be restored to what the raw input was just in case they need to
1363 # be passed to latex.
1365 sub pre_process {
1366     # Modifies $_;
1367     #JKR: We need support for some special environments.
1368     # This has to be here, because  they might contain
1369     # structuring commands like \section etc.
1370     local(%comments);
1371     &pre_pre_process if (defined &pre_pre_process);
1372     s/\\\\/\\\\ /go;            # Makes it unnecessary to look for escaped cmds
1373     &replace_html_special_chars;
1374     # Remove fake environment which should be invisible to LaTeX2HTML.
1375     s/\001//m;
1376     s/[%]end\s*{latexonly}/\001/gom;
1377     s/[%]begin\s*{latexonly}([^\001]*)\001/%/gos;
1378     s/\001//m;
1380     &preprocess_alltt if defined(&preprocess_alltt);
1382     $KEEP_FILE_MARKERS = 1;
1383     if ($KEEP_FILE_MARKERS) {
1384 #       if (s/%%% TEXEXPAND: \w+ FILE( MARKER)? (\S*).*/
1385 #           '<tex2html_'.($1?'':'end').'file>'.qq|#$2#|."\n"/em) {
1386 #           $_ = "<tex2html_file>#$2#\n". $_ };
1387         #RRM: ignore \n at end of included file, else \par may result
1388         if (s/(\n{1,2})?%%% TEXEXPAND: \w+ FILE( MARKER)? (\S*).*\n?/
1389             ($2?$1:"\n").'<tex2html_'.($2?'':'end').'file>'.qq|#$3#|."\n"/em) {
1390             $_ = "<tex2html_file>#$3#\n". $_ };
1391     } else {
1392         s/%%% TEXEXPAND[^\n]*\n//gm;
1393     }
1395     # Move all LaTeX comments into a local list
1396     s/([ \t]*(^|\G|[^\\]))(%.*(\n[ \t]*|$))/print "%";
1397         $comments{++$global{'verbatim_counter'}} = "$3";
1398         &write_mydb("verbatim", $global{'verbatim_counter'}, $3);
1399         "$1$comment_mark".$global{'verbatim_counter'}."\n"/mge;
1400     # Remove the htmlonly-environment
1401     s/\\begin\s*{htmlonly}\s*\n?//gom;
1402     s/\\end\s*{htmlonly}\s*\n?//gom;
1403     # Remove enviroments which should be invisible to LaTeX2HTML.
1404     s/\n[^%\n]*\\end\s*{latexonly}\s*\n?/\001/gom;
1405     s/((^|\n)[^%\n]*)\\begin\s*{latexonly}([^\001]*)\001/$1/gom;
1406     s/\\end\s*{comment}\s*\n?/\001/gom;
1407     s/\\begin\s*{comment}([^\001]*)\001//gom;
1409     # this used to be earlier, but that can create problems with comments
1410     &wrap_other_environments if (%other_environments);
1412 #    s/\\\\/\\\\ /go;           # Makes it unnecessary to look for escaped cmds
1413     local($next, $esc_del);
1414     &normalize_language_changes;
1415     # Patches by #JKR, #EI#, #JCL(jcl-verb)
1417     #protect \verb|\begin/end....|  parts, for LaTeX documentation
1418     s/(\\verb\*?(.))\\(begin|end)/$1\003$3/g;
1420     local(@processedV);
1421     local($opt, $style_info,$before, $contents, $after, $env);
1422     while (($UNFINISHED_COMMENT)||
1423   (/\\begin\s*($opt_arg_rx)?\s*\{($verbatim_env_rx|$keepcomments_rx)\}/o)) {
1424         ($opt, $style_info) = ($1,$2);
1425         $before=$contents=$after=$env='';
1426         if ($UNFINISHED_COMMENT) {
1427             $UNFINISHED_COMMENT =~ s/([^:]*)::(\d+)/$env=$1;$after=$_;
1428                 $before = join("",$unfinished_mark,$env,$2,"#");''/e;
1429             print "\nfound the lost \\end{$env}\n";
1430         }
1431         #RRM: can we avoid copying long strings here ?
1432         #     maybe this loop can be an  s/.../../s  with (.*?)
1433         #
1434         ($before, $after, $env) = ($`, $', $3) unless ($env);
1435         if (!($before =~ 
1436      /\\begin(\s*\[[^\]]*\]\s*)?\{($verbatim_env_rx|$keepcomments_rx)\}/)) {
1437             push(@processedV,$before);
1438             print "'";$before = '';
1439         }
1440         if ($after =~ /\s*\\end{$env[*]?}/) { # Must NOT use the s///o option!!!
1441             ($contents, $after) = ($`, $');
1442             $contents =~ s/^\n+/\n/s;
1443 #           $contents =~ s/\n+$//s;
1445             # re-insert comments
1446             $contents =~ s/$comment_mark(\d+)\n?/$comments{$1}/g;
1447 #           $contents =~ s/$comment_mark(\d+)/$verbatim{$1}/g;
1449             # revert '\\ ' -> '\\' only once 
1450             if ($env =~ /rawhtml|$keepcomments_rx/i) {
1451                 $contents = &revert_to_raw_tex($contents);
1452             } else {
1453                 $contents =~ s/([^\\](?:\\\\)*\\)([$html_escape_chars])/$1.&special($2)/geos;
1454                 $contents =~ s/\\\\ /\\\\/go;
1455             }
1457             if ($env =~/$keepcomments_rx/) {
1458                 $verbatim{++$global{'verbatim_counter'}} = "$contents";
1459             } else {
1460                 &write_mydb("verbatim", ++$global{'verbatim_counter'}, $contents);
1461             }
1462 #           $verbatim{$global{'verbatim_counter'}} = "$contents" if ($env =~/$keepcomments_rx/);
1463 #           $verbatim{$global{'verbatim_counter'}} = "$contents";
1465             if ($env =~ /rawhtml|$keepcomments_rx/i) {
1466                 if ($before) {
1467                     $after = join("",$verbatim_mark,$env
1468                               ,$global{'verbatim_counter'},"#",$after);
1469                 } else {
1470                     push (@processedV, join("",$verbatim_mark,$env
1471                            ,$global{'verbatim_counter'},"#"));
1472                 }
1473             } elsif ($env =~ /tex2html_code/) {
1474                 if ($before) {
1475                     $after = join("","\\begin", $opt, "\{verbatim_code\}"
1476                           , $verbatim_mark,$env
1477                           , $global{'verbatim_counter'},"#"
1478                           , "\\end\{verbatim_code\}",$after);
1479                 } else {
1480                     push (@processedV
1481                           , join("","\\begin", $opt, "\{verbatim_code\}"
1482                                  , $verbatim_mark,$env
1483                                  , $global{'verbatim_counter'},"#"
1484                                  , "\\end\{verbatim_code\}"));
1485                 }
1486             } else {
1487                 if ($before) {
1488                     $after = join("","\\begin", $opt, "\{tex2html_preform\}"
1489                           , $verbatim_mark,$env
1490                           , $global{'verbatim_counter'},"#"
1491                           , "\\end\{tex2html_preform\}",$after);
1492                 } else {
1493                     push (@processedV
1494                           , join("","\\begin", $opt, "\{tex2html_preform\}"
1495                                  , $verbatim_mark,$env
1496                                  , $global{'verbatim_counter'},"#"
1497                                  , "\\end\{tex2html_preform\}" ));
1498                 }
1499             }
1500         } else {
1501             print "Cannot find \\end{$env}\n";
1502             $after =~ s/$comment_mark(\d+)\n?/$comments{$1}/g;
1503 #           $after =~ s/$comment_mark(\d+)/$verbatim{$1}/g;
1504             if ($env =~ /rawhtml|$keepcomments_rx/i) {
1505                 $after = &revert_to_raw_tex($contents);
1506             } else {
1507                 $after =~ s/([^\\](?:\\\\)*\\)([$html_escape_chars])/$1.&special($2)/geos;
1508                 $after =~ s/\\\\ /\\\\/go;
1509             }
1510             if ($env =~/$keepcomments_rx/) {
1511                 $verbatim{++$global{'verbatim_counter'}} = "$after";
1512             } else {
1513                 &write_mydb("verbatim", ++$global{'verbatim_counter'}, $after );
1514             }
1515             $after = join("",$unfinished_mark,$env
1516                           ,$global{'verbatim_counter'},"#");
1517         }
1518         $_ = join("",$before,$after);
1519     }
1520     print STDOUT "\nsensitive environments found: ".(int(0+@processedV/2))." "
1521         if((@processedV)&&($VERBOSITY > 1));
1522     $_ = join('',@processedV, $_); undef @processedV;
1524     #restore \verb|\begin/end....|  parts, for LaTeX documentation
1525 #    $_ =~ s/(\\verb\W*?)\003(begin|end)/$1\\$2/g;
1526     $_ =~ s/(\\verb(;SPM\w+;|\W*?))\003(begin|end)/$1\\$3/g;
1528     # Now do the \verb declarations
1529     # Patches by: #JKR, #EI#, #JCL(jcl-verb)
1530     # Tag \verb command and legal opening delimiter with unique number.
1531     # Replace tagged ones and its contents with $verb_mark & id number if the
1532     # closing delimiter can be found. After no more \verb's are to tag, revert
1533     # tagged one's to the original pattern.
1534     local($del,$contents,$verb_rerun);
1535     local($id) = $global{'verb_counter'};
1536     # must tag only one alternation per loop
1537     ##RRM: can this be speeded up using a list ??
1538     my $vbmark = $verb_mark;
1539     while (s/\\verb(\t*\*\t*)(\S)/"<verb$1".++$id.">$2"/e ||
1540             s/\\verb()(\;SPM\w+\;|[^a-zA-Z*\s])/"<verb$1".++$id.">$2"/e ||
1541             s/\\verb(\t\t*)([^*\s])/"<verb$1".++$id.">$2"/e) {
1543         $del = $2;
1544         #RRM: retain knowledge of whether \verb* or \verb
1545         $vb_mark = ($1 =~/^\s*\*/? $verbstar_mark : $verb_mark);
1546         $esc_del = &escape_rx_chars($del);
1547         $esc_del = '' if (length($del) > 2);
1549         # try to find closing delimiter and substitute the complete
1550         # statement with $verb_mark or $verbstar_mark
1551 #       s/(<verb[^\d>]*$id>[\Q$del\E])([^$esc_del\n]*)([\Q$del\E]|$comment_mark(\d+)\n?)/
1552         s/(<verb[^\d>]*$id>\Q$del\E)([^$esc_del\n]*?)(\Q$del\E|$comment_mark(\d+)\n?)/
1553             $contents=$2;
1554             if ($4) { $verb_rerun = 1;
1555                 join('', "\\verb$del", $contents, $comments{$4})
1556             } else {
1557                 $contents =~ s|\\\\ |\\\\|g;
1558                 $contents =~ s|\n| |g;
1559                 $verb{$id}=$contents;
1560                 $verb_delim{$id}=$del;
1561                 join('',$vb_mark,$id,$verb_mark)
1562             }
1563         /e;
1564     }
1565     $global{'verb_counter'} = $id;
1566     # revert changes to fake verb statements
1567     s/<verb([^\d>]*)\d+>/\\verb$1/g;
1569     #JKR: the comments include the linebreak and the following whitespace
1570 #   s/([^\\]|^)(%.*\n[ \t]*)+/$1/gom; # Remove Comments but not % which may be meaningful
1571     s/((^|\n)$comment_mark(\d+))+//gom; # Remove comment markers on new lines, but *not* the trailing \n
1572     s/(\\\w+|(\W?))($comment_mark\d*\n?)/($2)? $2.$3:($1? $1.' ':'')/egm; # Remove comment markers, not after braces
1573 #    s/(\W?)($comment_mark\d*\n?)/($1)? $1.$2:''/egm; # Remove comment markers, not after braces
1574     # Remove comment markers, but *not* the trailing \n
1575 #  HWS:  Correctly remove multiple %%'s.
1577     s/\\%/\002/gm;
1578 #    s/(%.*\n[ \t]*)//gm;
1579     s/(%[^\n]*\n)[ \t]*/$comment_mark\n/gm;
1581     s/\002/\\%/gm;
1583     local($tmp1,$tmp2);
1584     s/^$unfinished_mark$keepcomments_rx(\d+)#\n?$verbatim_mark$keepcomments_rx(\d+)#/
1585         $verbatim{$4}."\n\\end{$1}"/egm; # Raw TeX
1586     s/$verbatim_mark$keepcomments_rx(\d+)#/
1587         $tmp1 = $1;
1588         $tmp2 = &protect_after_comments($verbatim{$2});
1589         $tmp2 =~ s!\n$!!s;
1590         join ('', "\\begin{$tmp1}"
1591                 , $tmp2
1592                 , "\n\\end{$tmp1}"
1593                 )/egm; # Raw TeX
1594     s/$unfinished_mark$keepcomments_rx(\d+)#/$UNFINISHED_COMMENT="$1::$2";
1595         "\\begin{$1}\n".$verbatim{$2}/egm; # Raw TeX
1597     $KEEP_FILE_MARKERS = 1;
1598     if ($KEEP_FILE_MARKERS) {
1599         s/%%% TEXEXPAND: \w+ FILE( MARKER) (\S*).*\n/
1600             '<tex2html_'.($1?'':'end').'file>'.qq|#.$2#\n|/gem;
1601     } else {
1602         s/%%% TEXEXPAND[^\n]*\n//gm;
1603     }
1605     &mark_string($_);
1608     # attempt to remove the \html \latex and \latexhtml commands
1609     s/\\latex\s*($O\d+$C)(.*)\1//gm;
1610     s/\\latexhtml\s*($O\d+$C)(.*)\1\s*($O\d+$C)(.*)\3/$4/sg;
1611     s/\\html\s*($O\d+$C)(.*)\1/$2/sg;
1612     s/\\html\s*($O\d+$C)//gm;
1614 #    &make_unique($_);
1617 # RRM:  When comments are retained, then ensure that they are benign
1618 # by removing \s and escaping braces, 
1619 # so that environments/bracing cannot become unbalanced.
1620 sub protect_after_comments {
1621     my ($verb_text) = @_;
1622 #    $verb_text =~ s/\%(.*)/'%'.&protect_helper($1)/eg;
1623     $verb_text =~ s/(^|[^\\])(\\\\)*\%(.*)/$1.$2.'%'.&protect_helper($3)/emg;
1624     $verb_text;
1627 sub protect_helper {
1628     my ($text) = @_;
1629     $text =~ s/\\/ /g;
1630     $text =~ s/(\{|\})/\\$1/g;
1631     $text;
1634 sub make_comment {
1635     local($type,$_) = @_;
1636     $_ =~ s/\\(index|label)\s*(($O|$OP)\d+($C|$CP)).*\2//sg;
1637     $_ = &revert_to_raw_tex($_);  s/^\n+//m;
1638     $_ =~ s/\\(index|label)\s*\{.*\}//sg;
1639     s/\-\-/- -/g; s/\-\-/- -/g; # cannot have -- inside a comment
1640     $_ = join('', '<!-- ', $type , "\n ", $_ , "\n -->" );
1641     $verbatim{++$global{'verbatim_counter'}} = $_;
1642     &write_mydb('verbatim', $global{'verbatim_counter'}, $_ );
1643     join('', $verbatim_mark, 'verbatim' , $global{'verbatim_counter'},'#')
1646 sub wrap_other_environments {
1647     local($key, $env, $start, $end, $opt_env, $opt_start);
1648     foreach $key (keys %other_environments) {
1649         # skip bogus entries
1650         next unless ($env = $other_environments{$key});
1651         $key =~ s/:/($start,$end)=($`,$');':'/e;
1653         if (($end =~ /^\#$/m) && ($start =~ /^\#/m)) {
1654             # catch Indica pre-processor language switches
1655             $opt_start = $';
1656             if ($env =~ s/\[(\w*)\]//o) {
1657                 $opt_env = join('','[', ($1 ? $1 : $opt_start ), ']');
1658             }
1659             local($next);
1660             while ($_ =~ /$start\b/) {
1661                 push(@pre_wrapped, $`, "\\begin\{pre_$env\}", $opt_env );
1662                 $_=$';
1663                 if (/(\n*)$end/) {
1664                     push(@pre_wrapped, $`.$1,"\\end\{pre_$env\}$1");
1665                     $_ = $';
1666                     if (!(s/^N(IL)?//o)) {$_ = '#'.$_ }
1667                 } else {
1668                     print "\n *** unclosed $start...$end chunk ***\n";
1669                     last;
1670                 }
1671             }
1672             $_ = join('', @pre_wrapped, $_);
1673             undef @pre_wrapped;
1675         } elsif (($end=~/^\n$/) && ($start =~ /^\#/)) {
1676             # catch ITRANS pre-processor language info;  $env = 'nowrap';
1677             local($ilang) = $start; $ilang =~ s/^\#//m;
1678             s/$start\s*\=([^<\n%]*)\s*($comment_mark\d*|\n|%)/\\begin\{tex2html_$env\}\\ITRANSinfo\{$ilang\}\{$1\}\n\\end\{tex2html_$env\}$2/g;
1680         } elsif (!$end &&($start =~ /^\#/m)) {
1681             # catch Indica pre-processor input-mode switches
1682             s/$start(.*)\n/\\begin\{tex2html_$env\}$&\\end\{tex2html_$env\}\n/g;
1684         } elsif (($start eq $end)&&(length($start) == 1)) {
1685             $start =~ s/(\W)/\\$1/; $end = $start;
1686             s/([^$end])$start([^$end]+)$end/$1\\begin\{pre_$env\}$2\\end\{pre_$env\}/mg;
1687         } elsif ($start eq $end) {
1688             if (!($start =~ /\#\#/)) {
1689                 $start =~ s/(\W)/\\$1/g; $end = $start; }
1690             local (@pre_wrapped);
1691             local($opt); $opt = '[indian]' if ($start =~ /^\#\#$/m);
1692             while ($_ =~ /$start/s) {
1693                 push(@pre_wrapped, $` , "\\begin\{pre_$env\}$opt");
1694                 $_=$';
1695                 if (/$end/s) {
1696                     push(@pre_wrapped, $`, "\\end\{pre_$env\}");
1697                     $_ = $';
1698                 } else {
1699                     print "\n *** unclosed $start...$end chunk ***\n";
1700                     last;
1701                 }
1702             }
1703             $_ = join('', @pre_wrapped, $_);
1704             undef @pre_wrapped;
1705         } elsif ($start && ($env =~ /itrans/)) {
1706             # ITRANS is of this form
1707             local($indic); if($start =~ /\#(\w+)$/m) {$indic = $1}
1708             #include the language-name as an optional parameter
1709             s/$start\b/\\begin\{pre_$env\}\[$indic\]/sg;
1710             s/$end\b/\\end\{pre_$env\}/sg;
1711         } elsif (($start)&&($end)) {
1712             s/$start\b/\\begin\{pre_$env\}/sg;
1713             s/$end\b/\\end\{pre_$env\}/sg;
1714         }
1715     }
1716     $_;
1719 #################### Marking Matching Brackets ######################
1721 # Reads the entire input file and performs pre_processing operations
1722 # on it before returning it as a single string. The pre_processing is
1723 # done on separate chunks of the input file by separate Unix processes
1724 # as determined by LaTeX \input commands, in order to reduce the memory
1725 # requirements of LaTeX2HTML.
1726 sub slurp_input_and_partition_and_pre_process {
1727     local($file) = @_;
1728     local(%string, @files, $pos);
1729     local ($count) =  1;
1731     unless(open(SINPUT,"<$file")) {
1732         die "\nError: Cannot read '$file': $!\n";
1733     }
1734     local(@file_string);
1735     print STDOUT "$file" if ($VERBOSITY >1);
1736     while (<SINPUT>) {
1737         if (/TEXEXPAND: INCLUDED FILE MARKER (\S*)/) {
1738             # Forking seems to screw up the rest of the input stream
1739             # We save the current position ...
1740             $pos = tell SINPUT;
1741             print STDOUT " fork at offset $pos " if ($VERBOSITY >1);
1742             $string{'STRING'} = join('',@file_string); @file_string = ();
1743             &write_string_out($count);
1744             delete $string{'STRING'};
1745             # ... so that we can return to it
1746             seek(SINPUT, $pos, 0);
1747             print STDOUT "\nDoing $1 ";
1748             ++$count}
1749         else {
1750 #           $string{'STRING'} .= $_
1751             push(@file_string,$_);
1752         }
1753     }
1754     $string{'STRING'} = join('',@file_string); @file_string = ();
1755     &write_string_out($count);
1756     delete $string{'STRING'};
1757     close SINPUT;
1758     @files = ();
1759     if(opendir(DIR, $TMP_)) {
1760         @files = sort grep(/^\Q$PARTITION_PREFIX\E\d+/, readdir(DIR));
1761         closedir(DIR);
1762     }
1764     unless(@files) {
1765         die "\nFailed to read in document parts.\n".
1766              "Look up section Globbing in the troubleshooting manual.\n";
1767     }
1769     $count = 0;
1770     foreach $file (@files) {
1771         print STDOUT "\nappending file: $TMP_$dd$file " if ($VERBOSITY > 1);
1772         $_ .= (&catfile("$TMP_$dd$file") || '');
1773         print STDOUT "\ntotal length: ".length($_)." characters\n" if ($VERBOSITY > 1);
1774     }
1775     die "\nFailed to read in document parts (out of memory?).\n"
1776         unless length($_);
1777     print STDOUT "\ntotal length: ".length($_)." characters\n" if ($VERBOSITY > 1);
1780 sub write_string_out {
1781     local($count) = @_;
1782     if ($count < 10) {$count = '00'.$count}
1783     elsif ($count < 100) {$count = '0'.$count}
1784     local($pid);
1785     # All open unflushed streams are inherited by the child. If this is
1786     # not set then the parent will *not* wait
1787     $| = 1;
1788     # fork returns 0 to the child and PID to the parent
1789     &write_mydb_simple("prelatex", $prelatex);
1790     &close_dbm_database;
1791     unless ($CAN_FORK) {
1792         &do_write_string_out;
1793     } else {
1794         unless ($pid = fork) {
1795             &do_write_string_out;
1796             exit 0;
1797         };
1798         waitpid($pid,0);
1799     }
1800     &open_dbm_database;
1803 sub do_write_string_out {
1804     local($_);
1805     close (SINPUT) if($CAN_FORK);
1806     &open_dbm_database;
1807     $_ = delete $string{'STRING'};
1808     # locate blank-lines, for paragraphs.
1809     # Replace verbatim environments etc.
1810     &pre_process;
1811     # locate the blank lines for \par s
1812     &substitute_pars;
1813     # Handle newcommand, newenvironment, newcounter ...
1814     &substitute_meta_cmds;
1815     &wrap_shorthand_environments;
1816     print STDOUT "\n *** End-of-partition ***" if ($VERBOSITY > 1);
1817     if(open(OUT, ">$TMP_$dd$PARTITION_PREFIX$count")) {
1818         print OUT $_;
1819         close(OUT);
1820     } else {
1821         print "\nError: Cannot write '$TMP_$dd$PARTITION_PREFIX$count': $!\n";
1822     }
1823     print STDOUT $_ if ($VERBOSITY > 9);
1824     $preamble = join("\n",$preamble,@preamble); # undef @preamble;
1825     &write_mydb_simple("preamble", $preamble);
1826     # this was done earlier; it should not be repeated
1827     #&write_mydb_simple("prelatex", $prelatex);
1828     &write_mydb_simple("aux_preamble", $aux_preamble);
1829     &close_dbm_database;
1832 # Reads the entire input file into a
1833 # single string.
1834 sub slurp_input  {
1835     local($file) = @_;
1836     local(%string);
1837     if(open(INPUT,"<$file")) {
1838         local(@file_string);
1839         while (<INPUT>) {
1840             push(@file_string, $_ );
1841         }
1842         $string{'STRING'} = join('',@file_string);
1843         close INPUT;
1844         undef @file_string;
1845     } else {
1846         print "\nError: Cannot read '$file': $!\n";
1847     }
1848     $_ = delete $string{'STRING'}; # Blow it away and return the result
1851 # MRO: make them more efficient
1852 sub special {
1853     $html_specials{$_[0]} || $_[0];
1856 sub special_inv {
1857     $html_specials_inv{$_[0]} || $_[0];
1860 sub special_html {
1861     $html_special_entities{$_[0]} || $_[0];
1864 sub special_html_inv {
1865     $html_spec_entities_inv{$_[0]} || $_[0];
1868 # Mark each matching opening and closing bracket with a unique id.
1869 sub mark_string {
1870     # local (*_) = @_; # Modifies $_ in the caller;
1871     # -> MRO: changed to $_[0] (same effect)
1872     # MRO: removed deprecated $*, replaced by option /m
1873     $_[0] =~ s/(^|[^\\])\\{/$1tex2html_escaped_opening_bracket/gom;
1874     $_[0] =~ s/(^|[^\\])\\{/$1tex2html_escaped_opening_bracket/gom; # repeat this
1875     $_[0] =~ s/(^|[^\\])\\}/$1tex2html_escaped_closing_bracket/gom;
1876     $_[0] =~ s/(^|[^\\])\\}/$1tex2html_escaped_closing_bracket/gom; # repeat this
1877     my $id = $global{'max_id'};
1878     my $prev_id = $id;
1879     # mark all balanced braces
1880     # MRO: This should in fact mark all of them as the hierarchy is
1881     # processed inside-out.
1882     1 while($_[0] =~ s/{([^{}]*)}/join("",$O,++$id,$C,$1,$O,$id,$C)/geo);
1883     # What follows seems esoteric...
1884     my @processedB = ();
1885     # Take one opening brace at a time
1886     while ($_[0] =~ /\{/) { 
1887         my ($before,$after) = ($`,$');
1888         my $change = 0;
1889         while (@UNMATCHED_OPENING && $before =~ /\}/) {
1890             my $this = pop(@UNMATCHED_OPENING);
1891             print "\n *** matching brace \#$this found ***\n";
1892             $before =~ s/\}/join("",$O,$this,$C)/eo;
1893             $change = 1;
1894         }
1895         $_[0] = join('',$before,"\{",$after) if($change);
1896         # MRO: mark one opening brace
1897         if($_[0] =~ s/^([^{]*){/push(@processedB,$1);join('',$O,++$id,$C)/eos) {
1898             $before=''; $after=$';
1899         }
1900         if ($after =~ /\}/) { 
1901             $after =~ s/\}/join("",$O,$id,$C)/eo;
1902             $_[0] = join('',$before,$O,$id,$C,$after);
1903         } else {
1904             print "\n *** opening brace \#$id  is unmatched ***\n";
1905             $after =~ /^(.+\n)(.+\n)?/;
1906             print " preceding: $after \n";
1907             push (@UNMATCHED_OPENING,$id);
1908         }
1909     }
1910     $_[0] = join('',@processedB,$_[0]); undef(@processedB);
1911     print STDOUT "\nInfo: bracketings found: ", $id - $prev_id,"\n"
1912         if ($VERBOSITY > 1);
1913     # process remaining closing braces
1914     while (@UNMATCHED_OPENING && $_[0] =~ /\}/) {
1915         my $this = pop(@UNMATCHED_OPENING);
1916         print "\n *** matching brace \#$this found ***\n";
1917         $_[0] =~ s/\}/join("",$O,$this,$C)/eo;
1918     }
1920     while ($_[0] =~ /\}/) {
1921         print "\n *** there was an unmatched closing \} ";
1922         my ($beforeline,$prevline,$afterline) = ($`, $`.$& , $');
1923         $prevline =~ /\n([^\n]+)\}$/m;
1924         if ($1) {
1925             print "at the end of:\n" . $1 . "\}\n\n";
1926         } else {
1927             $afterline =~ /^([^\n]+)\n/m;
1928             if ($1) {
1929                 print "at the start of:\n\}" . $1 ."\n\n";
1930             } else {
1931                 $prevline =~ /\n([^\n]+)\n\}$/m;
1932                 print "on a line by itself after:\n" . $1 . "\n\}\n\n";
1933             }
1934         }
1935         $_[0] =  $beforeline . $afterline;
1936     }
1937     $global{'max_id'} = $id;
1939     # restore escaped braces
1940     $_[0] =~ s/tex2html_escaped_opening_bracket/\\{/go;
1941     $_[0] =~ s/tex2html_escaped_closing_bracket/\\}/go;
1944 sub replace_html_special_chars {
1945     # Replaces html special characters with markers unless preceded by "\"
1946     s/([^\\])(<|>|&|\"|``|'')/&special($1).&special($2)/geom;
1947     # MUST DO IT AGAIN JUST IN CASE THERE ARE CONSECUTIVE HTML SPECIALS
1948     s/([^\\])(<|>|&|\"|``|'')/&special($1).&special($2)/geom;
1949     s/^(<|>|&|\"|``|'')/&special($1)/geom;
1952 #  used in \verbatiminput only:   $html_escape_chars = '<>&';
1953 sub replace_all_html_special_chars { s/([$html_escape_chars])/&special($1)/geom; }
1955 # The bibliography and the index should be treated as separate sections
1956 # in their own HTML files. The \bibliography{} command acts as a sectioning command
1957 # that has the desired effect. But when the bibliography is constructed
1958 # manually using the thebibliography environment, or when using the
1959 # theindex environment it is not possible to use the normal sectioning
1960 # mechanism. This subroutine inserts a \bibliography{} or a dummy
1961 # \textohtmlindex command just before the appropriate environments
1962 # to force sectioning.
1963 sub add_bbl_and_idx_dummy_commands {
1964     local($id) = $global{'max_id'};
1966     s/([\\]begin\s*$O\d+$C\s*thebibliography)/$bbl_cnt++; $1/eg;
1967     ## if ($bbl_cnt == 1) {
1968         s/([\\]begin\s*$O\d+$C\s*thebibliography)/$id++; "\\bibliography$O$id$C$O$id$C $1"/geo;
1969     #}
1970     $global{'max_id'} = $id;
1971     s/([\\]begin\s*$O\d+$C\s*theindex)/\\textohtmlindex $1/o;
1972     s/[\\]printindex/\\textohtmlindex /o;
1973     &lib_add_bbl_and_idx_dummy_commands() if defined(&lib_add_bbl_and_idx_dummy_commands);
1977 # Uses and modifies $default_language
1978 # This would be straight-forward except when there are
1979 #  \MakeUppercase, \MakeLowercase  or \uppercase , \lowercase commands
1980 # present in the source. The cases have to be adjusted before the
1981 # ISO-character code is set; e.g. with "z --> "Z  in  german.perl
1983 sub convert_iso_latin_chars {
1984     local($_) = @_;
1985     local($next_language, $pattern);
1986     local($xafter, $before, $after, $funct, $level, $delim);
1987     local(@case_processed);
1988     while (/$case_change_rx/) {
1989         $xafter = $2;
1990 #       $before .= $`;
1991         push(@case_processed, $`);
1992         $funct = $3;
1993         $after = '';
1994         $_ = $';
1995         if ($xafter =~ /noexpand/) { $before .= "\\$funct"; next; }
1997         s/^[\s%]*(.)/$delim=$1;''/eo;
1998         if ($delim =~ /{/ ) {
1999             # brackets not yet numbered...
2000 #           $before .= $funct . $delim;
2001             push(@case_processed, $funct . $delim);
2002             $level = 1;
2003             $after = $delim;
2004             while (($level)&&($_)&&(/[\{\}]/)) {
2005                 $after .= $` . $&;
2006                 $_ = $';
2007                 if ( "$&" eq "\{" ) {$level++}
2008                 elsif ( "$&" eq "\}" ) { $level-- }
2009                 else { print $_ }
2010                 print "$level";
2011             } 
2012 #           $before .= $after;
2013             push(@case_processed, $after);
2014         } elsif ($delim eq "<") {
2015             # brackets numbered, but maybe not processed...
2016             s/((<|#)(\d+)(>|#)>).*\1//;
2017             $after .= $delim . $&;
2018             $_ = $';
2019             print STDOUT "\n<$2$funct$4>" if ($VERBOSITY > 2);
2020             $funct =~ s/^\\//o;
2021             local($cmd) = "do_cmd_$funct";
2022             $after = &$cmd($after);
2023 #           $before .= $after;
2024             push(@case_processed, $after);
2025         } elsif (($xafter)&&($delim eq "\\")) {
2026             # preceded by \expandafter ...
2027             # ...so expand the following macro first
2028             $funct =~ s/^\\//o;
2029             local($case_change) = $funct;
2030             s/^(\w+|\W)/$funct=$1;''/eo;
2031             local($cmd) = $funct;
2032             local($thiscmd) = "do_cmd_$funct";
2033             if (defined &$thiscmd) { $_ = &$thiscmd($_) }
2034             elsif ($new_command{$funct}) { 
2035                 local($argn, $body, $opt) = split(/:!:/, $new_command{$funct});
2036                 do { ### local($_) = $body;
2037                      &make_unique($body);
2038                 } if ($body =~ /$O/);
2039                 if ($argn) {
2040                     do { 
2041                         local($before) = '';
2042                         local($after) = "\\$funct ".$_;
2043                         $after = &substitute_newcmd;   # may change $after
2044                         $after =~ s/\\\@#\@\@/\\/o ;
2045                     }
2046                 } else { $_ = $body . $_; }
2047             } else { print "\nUNKNOWN COMMAND: $cmd "; }
2049             $cmd = $case_change;
2050             $case_change = "do_cmd_$cmd";
2051             if (defined &$case_change) { $_ = &$case_change($_) }
2052         } else {
2053             # this should not happen, but just in case...
2054             $funct =~ s/^\\//o;
2055             local($cmd) = "do_cmd_$funct";
2056             print STDOUT "\n\n<$delim$funct>" if ($VERBOSITY > 2);
2057             $_ = join('', $delim , $_ );
2058             if (defined &$cmd) { $_ = &$cmd($_) }
2059         }
2060     }
2061 #   $_ = join('', $before, $_) if ($before);
2062     $_ = join('', @case_processed, $_) if (@case_processed);
2064     # ...now do the conversions
2065     ($before, $after, $funct) = ('','','');
2066     @case_processed = ();
2067     if (/$language_rx/o) {
2068         ($next_language, $pattern, $before, $after) = (($2||$1), $&, $`, $');
2069         $before = &convert_iso_latin_chars($before) if ($before);
2070 #       push(@case_processed, $pattern, $before);
2071         local($br_id) = ++$global{'max_id'};
2072         $pattern = join('' , '\selectlanguage', $O.$br_id.$C
2073             , (($pattern =~ /original/) ? $TITLES_LANGUAGE : $next_language )
2074             , $O.$br_id.$C );
2075         push(@case_processed, $before, $pattern);
2076         push(@language_stack, $default_language);
2077         $default_language = $next_language;
2078         $_ = &convert_iso_latin_chars($after);
2079         $default_language = pop @language_stack;
2080     } else {
2081         $funct = $language_translations{$default_language};
2082         (defined(&$funct) ? $_ = &$funct($_) :
2083          do {   &write_warnings(
2084                 "\nCould not find translation function for $default_language.\n\n")
2085             }
2086         );
2087         if ($USE_UTF ||(!$NO_UTF &&(defined %unicode_table)&&length(%unicode_table)>2)) {
2088             &convert_to_unicode($_)};
2089     }
2090     $_ = join('', @case_processed, $_); undef(@case_processed);
2091     $_;
2094 # May need to add something here later
2095 sub english_translation { $_[0] }
2097 # This replaces \setlanguage{\language} with \languageTeX
2098 # This makes the identification of language chunks easier.
2099 sub normalize_language_changes {
2100     s/$setlanguage_rx/\\$2TeX/gs;
2103 sub get_current_language {
2104     return () if ($default_language eq $TITLES_LANGUAGE);
2105     local($lang,$lstyle) = ' LANG="';
2106     $lang_code = $iso_languages{$default_language};
2107     if (%styled_languages) {
2108         $lstyle = $styled_languages{$default_language};
2109         $lstyle = '" CLASS="'.$lstyle  if $lstyle;
2110     }
2111     ($lang_code ? $lang.$lang_code.$lstyle.'"' : '');
2114 %styled_languages = ();
2116 sub do_cmd_htmllanguagestyle {
2117     local($_) = @_;
2118     local($class) = &get_next_optional_argument;
2119     local($lang) = &missing_braces unless (
2120         (s/$next_pair_pr_rx/$lang=$2;''/e)
2121         ||(s/$next_pair_rx/$lang=$2;''/e));
2122     return ($_) unless $lang;
2123     local($class) = $iso_languages{$lang} unless $class;
2124     if ($USING_STYLES && $class) {
2125         print "\nStyling language: $lang = \"$class\" ";
2126         $styled_languages{"$lang"} = $class;
2127     }
2128     $_;
2131 # General translation mechanism:
2134 # The main program latex2html calls texexpand with the document name
2135 # in order to expand some of its \input and \include statements, here
2136 # also called 'merging', and to write a list of sensitized style, class,
2137 # input, or include file names.
2138 # When texexpand has finished, all is contained in one file, TMP_foo.
2139 # (assumed foo.tex is the name of the document to translate).
2141 # In this version, texexpand cares for following environments
2142 # that may span include files / section boundaries:
2143 # (For a more technical description, see texexpand.)
2144 #  a) \begin{comment}
2145 #  b) %begin{comment}
2146 #  c) \begin{any}  introduced with \excludecomment
2147 #  d) %begin{any}
2148 #  e) \begin{verbatim}
2149 #  f) \begin{latexonly}
2150 #  g) %begin{latexonly}
2151
2152 # a)-d) cause texexpand to drop its contents, it will not show up in the
2153 # output file. You can use this to 'comment out' a bunch of files, say.
2154
2155 # e)-g) prevent texexpand from expanding input files, but the environment
2156 # content goes fully into the output file.
2157
2158 # Together with each merging of \input etc. there are so-called %%%texexpand
2159 # markers accompanying the boundary.
2161 # When latex2html reads in the output file, it uses these markers to write
2162 # each part to a separate file, and process them further.
2165 # If you have, for example:
2167 # a) preample
2168 # b) \begin{document}
2169 # c) text
2170 # d) \input{chapter}
2171 # e) more text
2172 # f) \end{document}
2174 # you end up in two parts, part 1 is a)-c), part 2 is the rest.
2175 # Regardless of environments spanning input files or sections.
2178 # What now starts is meta command substitution:
2179 # Therefore, latex2html forks a child process on the first part and waits
2180 # until it finished, then forks another on the next part and so forth
2181 # (see also &slurp_input_and_partition_and_preprocess).
2183 # Here's what each child is doing:
2184 # Each child process reads the new commands translated so far by the previous
2185 # child from the TMP_global DBM database.
2186 # After &pre_processing, it substitutes the meta commands (\newcommand, \def,
2187 # and the like) it finds, and adds the freshly retrieved new commands to the
2188 # list so far.
2189 # This is done *only on its part* of the document; this saves upwards of memory.
2190 # Finally, it writes its list of new commands (synopsis and bodies) to the
2191 # DBM database, and exits.
2192 # After the last child finished, latex2html reads in all parts and
2193 # concatenates them.
2196 # So, at this point in time (start of &translate), it again has the complete
2197 # document, but now preprocessed and with new commands substituted.
2198 # This has several disadvantages: an amount of commands is substituted (in
2199 # TeX lingo, expanded) earlier than the rest.
2200 # This causes trouble if commands really must get expanded at the point
2201 # in time they show up.
2204 # Then, still in &translate, latex2html uses the list of section commands to
2205 # split the complete document into chunks.
2206 # The chunks are not written to files yet. They are retained in the @sections
2207 # list, but each chunk is handled separately.
2208 # latex2html puts the current chunk to $_ and processes it with
2209 # &translate_environments etc., then fetches the next chunk, and so on.
2210 # This prevents environments that span section boundaries from getting
2211 # translated, because \begin and \end cannot find one another, to say it this
2212 # way.
2215 # After the chunk is translated to HTML, it is written to a file.
2216 # When all chunks are done, latex2html rereads each file to get cross
2217 # references right, replace image markers with the image file names, and
2218 # writes index and bibliography.
2221 sub translate {
2222     &normalize_sections;        # Deal with the *-form of sectioning commands
2224     # Split the input into sections, keeping the preamble together
2225     # Due to the regular expression, each split will create 5 more entries.
2226     # Entry 1 and 2: non-letter/letter sectioning command,
2227     # entry 4: the delimiter (may be empty)
2228     # entry 5: the text.
2229     local($pre_section, @sections);
2230     if (/\\(startdocument|begin\s*($O\d+$C)\s*document\s*\2)/) {
2231         $pre_section = $`.$&; $_ = $';
2232     }
2233     @sections = split(/$sections_rx/, $_);
2234     $sections[0] = $pre_section.$sections[0] if ($pre_section);
2235     undef $pre_section;
2236     local($sections) = int(scalar(@sections) / 5);
2238     # Initialises $curr_sec_id to a list of 0's equal to
2239     # the number of sectioning commands.
2240     local(@curr_sec_id) = split(' ', &make_first_key);
2241     local(@segment_sec_id) = @curr_sec_id;
2242     local($i, $j, $current_depth) = (0,0,0);
2243     local($curr_sec) = $SHORT_FILENAME||$FILE;
2244     local($top_sec) = ($SEGMENT ? '' : 'top of ');
2245 #    local(%section_info, %toc_section_info, $CURRENT_FILE, %cite_info, %ref_files);
2246     local($CURRENT_FILE);
2247     # These filenames may be set when translating the corresponding commands.
2248     local($tocfile, $loffile, $lotfile, $footfile, $citefile, $idxfile,
2249           $figure_captions, $table_captions, $footnotes, $citations, %font_size, %index,
2250           %done, $t_title, $t_author, $t_date, $t_address, $t_affil, $changed);
2251     local(@authors,@affils,@addresses,@emails,@authorURLs);
2252     local(%index_labels, %index_segment, $preindex, %footnotes, %citefiles);
2253     local($segment_table_captions, $segment_figure_captions);
2254     local($dir,$nosave) = ('','');
2255     local($del,$close_all,$open_all,$toc_sec_title,$multiple_toc);
2256     local($open_tags_R) = [];
2257     local(@save_open_tags)= ();
2258     local(@language_stack) = ();
2259     push (@language_stack, $default_language);
2261 #    $LATEX_FONT_SIZE = '10pt' unless ($LATEX_FONT_SIZE);
2262     &process_aux_file 
2263         if $SHOW_SECTION_NUMBERS || /\\(caption|(html|hyper)?((eq)?ref|cite))/;
2265     require ("${PREFIX}internals.pl") if (-f "${PREFIX}internals.pl");
2266 #JCL(jcl-del)
2267     &make_single_cmd_rx;
2269     $tocfile = $EXTERNAL_CONTENTS;
2270     $idxfile = $EXTERNAL_INDEX;
2271     $citefile = $EXTERNAL_BIBLIO; $citefile =~ s/#.*$//;
2272     $citefiles{1} = $citefile if ($citefile);
2273     print "\nTranslating ...";
2275     while ($i <= @sections) {
2276         undef $_;
2277         $_ = $sections[$i];
2278         s/^[\s]*//;             # Remove initial blank lines
2280         # The section command was removed when splitting ...
2281         s/^/\\$curr_sec$del/  if ($i > 0); # ... so put it back
2282         if ($current_depth < $MAX_SPLIT_DEPTH)  {
2283             if (($footnotes)&&($NO_FOOTNODE)&&( $current_depth < $MAX_SPLIT_DEPTH)) {
2284                 local($thesenotes) = &make_footnotes ;
2285                 print OUTPUT $thesenotes;
2286             }
2287             $CURRENT_FILE = &make_name($curr_sec, join('_',@curr_sec_id));
2288             
2289             open(OUTPUT, ">$CURRENT_FILE")
2290                 || die "Cannot write '$CURRENT_FILE': $!\n";
2291             if ($XBIT_HACK) { # use Apache's XBit hack
2292                 chmod 0744, $CURRENT_FILE;
2293                 &check_htaccess;
2294             } else {
2295                 chmod 0644, $CURRENT_FILE;
2296             }
2298             if ($MULTIPLE_FILES && $ROOTED) {
2299                 if ($DESTDIR =~ /^\Q$FIXEDDIR\E[$dd$dd]?([^$dd$dd]+)/)
2300                     { $CURRENT_FILE = "$1$dd$CURRENT_FILE" };
2301             }
2302         }
2303         &remove_document_env;
2304 #        &wrap_shorthand_environments;    #RRM  Is this needed ?
2305         print STDOUT "\n" if ($VERBOSITY);
2306         print STDOUT "\n" if ($VERBOSITY > 2);
2307         print $i/5,"/$sections";
2308         print ":$top_sec$curr_sec:" if ($VERBOSITY);
2310         # Must do this early ... It also sets $TITLE
2311         &process_command($sections_rx, $_) if (/^$sections_rx/);
2312         # reset tags saved from the previous section
2313         $open_tags_R = [ @save_open_tags ];
2314         @save_open_tags = ();
2316         local($curr_sec_tex);
2317         if ((! $TITLE) || ($TITLE eq $default_title)) {
2318             eval '$TITLE = '.$default_title;
2319             $TITLE = $default_title if $@;
2320             $curr_sec_tex = ($top_sec ? '' :
2321                   join('', '"', &revert_to_raw_tex($curr_sec), '"'));
2322             print STDOUT "$curr_sec_tex for $CURRENT_FILE\n" if ($VERBOSITY);
2323         } else { 
2324             local($tmp) = &purify($TITLE,1);
2325             $tmp = &revert_to_raw_tex($tmp);
2326             print STDOUT "\"$tmp\" for $CURRENT_FILE\n" if ($VERBOSITY); 
2327         }
2329         if (/\\(latextohtmlditchpreceding|startdocument)/m) {
2330             local($after) = $';
2331             local($before) = $`.$&;
2332             $SEGMENT = 1 if ($1 =~ /startdocument/);
2333             print STDOUT "\n *** translating preamble ***\n" if ($VERBOSITY);
2334             $_ = &translate_preamble($before);
2335             s/\n\n//g; s/<BR>//g;       # remove redundant blank lines and breaks
2337 #           &process_aux_file  if $AUX_FILE_NEEDED;
2339             print STDOUT "\n *** preamble done ***\n" if ($VERBOSITY);
2340             $PREAMBLE = 0;
2341             $NESTING_LEVEL=0;
2342             &do_AtBeginDocument;
2343             $after =~ s/^\s*//m;
2344             print STDOUT (($VERBOSITY >2)? "\n*** Translating environments ***" : ";");
2345             $after = &translate_environments($after);
2346             print STDOUT (($VERBOSITY >2)? "\n*** Translating commands ***" : ";");
2347             $_ .= &translate_commands($after);
2348 #            $_ = &translate_commands($after);
2349         } else {
2350             &do_AtBeginDocument;
2351             $PREAMBLE = 0;
2352             $NESTING_LEVEL=0;
2353             print STDOUT (($VERBOSITY >2)? "\n*** Translating environments ***" : ";");
2354             $_ = &translate_environments($_);
2355             print STDOUT (($VERBOSITY >2)? "\n*** Translating commands ***" : ";");
2356             $_ = &translate_commands($_);
2357         }
2359         # close any tags that remain open
2360         if (@$open_tags_R) {
2361             ($close_all,$open_all) = &preserve_open_tags();
2362             $_ .= $close_all; 
2363             @save_open_tags = @$open_tags_R; $open_tags_R = [];
2364         } else { ($close_all,$open_all) = ('','') }
2366         print STDOUT (($VERBOSITY >2)? "\n*** Translations done ***" : "\n");
2367 #       if (($footnotes)&&($NO_FOOTNODE)&&( $current_depth < $MAX_SPLIT_DEPTH)) {
2368 #           $_ .= &make_footnotes
2369 #       }
2370         print OUTPUT $_;
2372         # Associate each id with the depth, the filename and the title
2373         ###MEH -- starred sections don't show up in TOC ...
2374         # RRM:  ...unless $TOC_STARS is set
2375 #       $toc_sec_title = &simplify($toc_sec_title);
2376         $toc_sec_title = &purify($toc_sec_title);# if $SEGMENT;
2377         $toc_sec_title = &purify($TITLE) unless ($toc_sec_title);       
2379         if ($TOC_STARS) {
2380             $toc_section_info{join(' ',@curr_sec_id)} =
2381                 "$current_depth$delim$CURRENT_FILE$delim$toc_sec_title"
2382 #                   if ($current_depth <= $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH);
2383                     if ($current_depth <= $TOC_DEPTH);
2384         } else {
2385             $toc_section_info{join(' ',@curr_sec_id)} =
2386                 "$current_depth$delim$CURRENT_FILE$delim$toc_sec_title"
2387                 . ($curr_sec =~ /star$/ ? "$delim<tex2html_star_mark>" : "")
2388 #                   if ($current_depth <= $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH);
2389                     if ($current_depth <= $TOC_DEPTH);
2390         }
2392         # include $BODYTEXT in the section_info, when starting a new page
2393         $section_info{join(' ',@curr_sec_id)} =
2394             "$current_depth$delim$CURRENT_FILE$delim$TITLE$delim"
2395                 . (($current_depth < $MAX_SPLIT_DEPTH)? $BODYTEXT: "");
2397         # Get type of section (see also the split above)
2398         $curr_sec = $sections[$i+1].$sections[$i+2];
2399         $del = $sections[$i+4];
2401         # Get the depth of the current section;
2402 #       $curr_sec = $outermost_level unless $curr_sec;
2403         $current_depth = $section_commands{$curr_sec};
2404         if ($after_segment) {
2405             $current_depth = $after_segment;
2406             $curr_sec_id[$after_segment] += $after_seg_num;
2407             ($after_segment,$after_seg_num) = ('','');
2408             for($j=1+$current_depth; $j <= $#curr_sec_id; $j++) {
2409                 $curr_sec_id[$j] = 0;
2410             }
2411         }
2412         if ($SEGMENT||$SEGMENTED) {
2413             for($j=1; $j <= $#curr_sec_id; $j++) {
2414                 $curr_sec_id[$j] += $segment_sec_id[$j];
2415                 $segment_sec_id[$j] = 0;
2416             }
2417         }; 
2420         # this may alter the section-keys
2421         $multiple_toc = 1 if ($MULTIPLE_FILES && $ROOTED && (/$toc_mark/));
2424         #RRM : Should this be done here, or in \stepcounter ?
2425         @curr_sec_id = &new_level($current_depth, @curr_sec_id);
2427         $toc_sec_title = $TITLE = $top_sec = '';
2428         $i+=5; #skip to next text section
2429     }
2430     $open_tags_R = [];
2431     $open_all = '';
2433     $_ = undef;
2434     $_ = &make_footnotes if ($footnotes);
2435     $CURRENT_FILE = '';
2436     print OUTPUT;
2437     close OUTPUT;
2438     
2440 #    # this may alter the section-keys
2441 #    &adjust_root_keys if $multiple_toc;
2443     if ($PREPROCESS_IMAGES) { &preprocess_images }
2444     else { &make_image_file }
2445     print STDOUT "\n *** making images ***" if ($VERBOSITY > 1);
2446     &make_images;
2448     # Link sections, add head/body/address do cross-refs etc
2449     print STDOUT "\n *** post-process ***" if ($VERBOSITY > 1);
2450     &post_process;
2452     if (defined &document_post_post_process) {
2453         #BRM: extra document-wide post-processing
2454         print STDOUT "\n *** post-processing Document ***" if ($VERBOSITY > 1);
2455         &document_post_post_process();
2456     }
2458     print STDOUT "\n *** post-processed ***" if ($VERBOSITY > 1);
2459     &copy_icons if $LOCAL_ICONS;
2460     if ($SEGMENT || $DEBUG || $SEGMENTED) {
2461         &save_captions_in_file("figure",  $figure_captions) if $figure_captions;
2462         &save_captions_in_file("table",  $table_captions) if $table_captions;
2463 #       &save_array_in_file ("captions", "figure_captions", 0, %figure_captions) if %figure_captions;
2464 #       &save_array_in_file ("captions", "table_captions", 0, %table_captions) if %table_captions;
2465         &save_array_in_file ("index", "index", 0, %index);
2466         &save_array_in_file ("sections", "section_info", 0, %section_info);
2467         &save_array_in_file ("contents", "toc_section_info", 0,%toc_section_info);
2468         &save_array_in_file ("index", "sub_index", 1, %sub_index) if %sub_index;
2469         &save_array_in_file ("index", "index_labels", 1, %index_labels) if %index_labels;
2470         &save_array_in_file ("index", "index_segment", 1, %index_segment) if %index_segment;
2471         &save_array_in_file ("index", "printable_key", 1, %printable_key) 
2472             if (%printable_key || %index_segment);
2473     }
2474     elsif ($MULTIPLE_FILES && $ROOTED) {
2475         &save_array_in_file ("sections", "section_info", 0, %section_info);
2476         &save_array_in_file ("contents", "toc_section_info", 0, %toc_section_info);
2477     }
2478     &save_array_in_file ("internals", "ref_files", 0, %ref_files) if $changed;
2479     &save_array_in_file ("labels", "external_labels", 0, %ref_files);
2480     &save_array_in_file ("labels", "external_latex_labels", 1, %latex_labels);
2481     &save_array_in_file ("images", "cached_env_img", 0, %cached_env_img);
2484 # RRM:
2485 sub translate_preamble {
2486     local($_) = @_;
2487     $PREAMBLE = 1;
2488     $NESTING_LEVEL=0;   #counter for TeX group nesting level
2489     # remove some artificially inserted constructions
2490     s/\n${tex2html_deferred_rx}\\par\s*${tex2html_deferred_rx2}\n/\n/gm;
2491     s/\\newedcommand(<<\d+>>)([A-Za-z]+|[^A-Za-z])\1(\[\d+\])?(\[[^]]*\])?(<<\d+>>)[\w\W\n]*\5($comment_mark\d*)?//gm;
2492     s/\n{2,}/\n/ogm;
2494     if (/\\htmlhead/) {
2495         print STDOUT "\nPREAMBLE: discarding...\n$`" if ($VERBOSITY > 4);
2496         local($after) = $&.$';
2497         # translate segment preamble preceding  \htmlhead
2498         &translate_commands(&translate_environments($`));
2499         # translate \htmlhead  and rest of preamble
2500         $_=&translate_commands(&translate_environments($after));
2501         print STDOUT "\nPREAMBLE: retaining...\n$_" if ($VERBOSITY > 4);
2502     } else {
2503         # translate only preamble here (metacommands etc.)
2504         # there should be no textual results, if so, discard them
2505         &translate_commands(&translate_environments($_));
2506         print STDOUT "\nPREAMBLE: discarding...\n$_" if ($VERBOSITY > 4);
2507         $_="";
2508     };
2509     $_ = &do_AtBeginDocument($_);
2510     if (! $SEGMENT) { $_ = ''} # segmented documents have a heading already
2511     $_;
2514 ############################ Processing Environments ##########################
2516 sub wrap_shorthand_environments {
2517     # This wraps a dummy environment around environments that do not use
2518     # the begin-end convention. The wrapper will force them to be
2519     # evaluated by Latex rather than them being translated.
2520     # Wrap a dummy environment around matching TMPs.
2521     # s/^\$\$|([^\\])\$\$/{$1.&next_wrapper('tex2html_double_dollar')}/ge;
2522     # Wrap a dummy environment around matching $s.
2523     # s/^\$|([^\\])\$/{$1.&next_wrapper('$')}/ge;
2524     # s/tex2html_double_dollar/\$\$/go;
2525     # Do \(s and \[s
2526     #
2527     local($wrapper) = "tex2html_wrap_inline";   # \ensuremath wrapper
2528     print STDOUT "\n *** wrapping environments ***\n" if ($VERBOSITY > 3);
2530     # MRO: replaced $* with /m
2531     print STDOUT "\\(" if ($VERBOSITY > 3);
2532     s/(^\\[(])|([^\\])(\\[(])/{$2.&make_any_wrapper(1,'',$wrapper).$1.$3}/geom;
2533     print STDOUT "\\)" if ($VERBOSITY > 3);
2534     s/(^\\[)]|[^\\]\\[)])/{$1.&make_any_wrapper(0,'',$wrapper)}/geom;
2536     print STDOUT "\\[" if ($VERBOSITY > 3);
2537     s/(^\\[[])|([^\\])(\\[[])/{$2.&make_any_wrapper(1,1,"displaymath")}/geom;
2538     print STDOUT "\\]" if ($VERBOSITY > 3);
2539     s/(^\\[\]])|([^\\])(\\[\]])/{$2.&make_any_wrapper(0,1,"displaymath")}/geom;
2541     print STDOUT "\$" if ($VERBOSITY > 3);
2542     s/$enspair/print "\$";
2543        {&make_any_wrapper(1,'',$wrapper).$&.&make_any_wrapper(0,'',$wrapper)}/geom;
2545     $double_dol_rx = '(^|[^\\\\])\\$\\$';
2546     $single_dol_rx = '(^|[^\\\\])\\$';
2547     print STDOUT "\$" if ($VERBOSITY > 3);
2549     local($dollars_remain) = 0;
2550     $_ = &wrap_math_environment;
2551     $_ = &wrap_raw_arg_cmds;
2554 sub wrap_math_environment {
2556     # This wraps math-type environments
2557     # The trick here is that the opening brace is the same as the close,
2558     # but they *can* still nest, in cases like this:
2559     #
2560     # $ outer stuff ... \hbox{ ... $ inner stuff $ ... } ... $
2561     #
2562     # Note that the inner pair of $'s is nested within a group.  So, to
2563     # handle these cases correctly, we need to make sure that the outer
2564     # brace-level is the same as the inner. --- rst
2565     #tex2html_wrap
2566     # And yet another problem:  there is a scungy local idiom to do
2567     # this:  $\_$ for a boldfaced underscore.  xmosaic can't display the
2568     # resulting itty-bitty bitmap, for some reason; even if it could, it
2569     # would probably come out as an overbar because of the floating-
2570     # baseline problem.  So, we have to special case this.  --- rst again.
2572     local ($processed_text, @processed_text, $before, $end_rx, $delim, $ifclosed);
2573     local ($underscore_match_rx) = "^\\s*\\\\\\_\\s*\\\$";
2574     local ($wrapper);
2575     print STDOUT "\nwrap math:" if ($VERBOSITY > 3);
2577     #find braced dollars, in tabular-specs
2578     while (/((($O|$OP)\d+($C|$CP))\s*)\$(\s*\2)/) {
2579         push (@processed_text, $`, $1.$dol_mark.$5);
2580         $_ = $';
2581     }
2582     $_ = join('',@processed_text, $_) if (@processed_text);
2583     undef @processed_text;
2585     $dollars_remain = 0;
2586     while (/$single_dol_rx/) {
2587         $processed_text .= $`.$1;
2588         $_ = $';
2589         $wrapper = "tex2html_wrap_inline";
2590         $end_rx = $single_dol_rx; # Default, unless we begin with $$.
2591         $delim = "\$";
2593         if (/^\$/ && (! $`)) {
2594             s/^\$//;
2595             $end_rx = $double_dol_rx;
2596             $delim = "";        # Cannot say "\$\$" inside displaymath
2597             $wrapper = "displaymath";
2599         } elsif (/$underscore_match_rx/ && (! $`)) {
2601             # Special case for $\_$ ...
2603             s/$underscore_match_rx//;
2604             $processed_text .= '\\_';
2605             next;
2606         }
2608         # Have an opening $ or $$.  Find matching close, at same bracket level
2609 #       $processed_text .= &make_any_wrapper(1,'',$wrapper).$delim;
2611         print STDOUT "\$" if ($VERBOSITY > 3);
2612         $ifclosed = 0;
2613         local($thismath);
2614         while (/$end_rx/) {
2615             # Forget the $$ if we are going to replace it with "displaymath"
2616             $before = $` . (($wrapper eq "displaymath")? "$1" : $&);
2617             last if ($before =~ /\\(sub)*(item|section|chapter|part|paragraph)(star)?\b/);
2618             $thismath .= $before;
2619             $_ = $';
2620             s/^( [^\n])/\\space$1/s;  #make sure a trailing space doesn't get lost.
2622             # Found dollar sign inside open subgroup ... now see if it's
2623             # at the same brace-level ...
2625             local ($losing, $br_rx) = (0, '');
2626             print STDOUT "\$" if ($VERBOSITY > 3);
2627             while ($before =~ /$begin_cmd_rx/) {
2628                 $br_rx = &make_end_cmd_rx($1);  $before = $';
2630                 if ($before =~ /$br_rx/) { $before = $'; }
2631                 else { $losing = 1; last; }
2632             }
2633             do { $ifclosed = 1; last } unless $losing;
2635             # It wasn't ... find the matching close brace farther on; then
2636             # keep going.
2638             /$br_rx/;
2640             $thismath .= $`.$&;
2642             #RRM: may now contain unprocessed $s e.g. $\mbox{...$...$...}$
2643             # the &do_cmd_mbox uses this specially to force an image
2644             # ...but there may be other situations; e.g. \hbox
2645             # so set a flag:
2646             $dollars_remain = 1;
2648             $_ = $';
2649         }
2651         # Got to the end.  Whew!
2652         if ($ifclosed) {
2653             # also process any nested math
2654             while (($dollars_remain)&&($delim eq "\$")) {
2655                 local($saved) = $_;
2656                 $thismath =~ s/\$$//;
2657                 $_ = $thismath;
2658                 $thismath =  &wrap_math_environment;
2659                 $thismath .= "\$";
2660                 $_ = $saved;
2661             }
2662             $processed_text .= &make_any_wrapper(1,'',$wrapper) . $delim 
2663                 . $thismath . &make_any_wrapper(0,'',$wrapper);
2664         } else {
2665             print STDERR "\n\n *** Error: unclosed math or extra `\$', before:\n$thismath\n\n";
2666 #           # remove a $ to try to recover as much as possible.
2667 #           $thismath =~ s/([^\\]\\\\|[^\\])\$/$1\%\%/;
2668 #           $_ = $thismath . $_; $thismath = "";
2669         print "\n$thismath\n\n\n$_\n\n\n"; die;
2670             
2671         }
2672     }
2673     $processed_text . $_;
2676 sub translate_environments {
2677     local ($_) = @_;
2678     local($tmp, $capenv);
2679 #   print "\nTranslating environments ...";
2680     local($after, @processedE);
2681     local ($contents, $before, $br_id, $env, $pattern);
2682     for (;;) {
2683 #       last unless (/$begin_env_rx/o);
2684         last unless (/$begin_env_rx|$begin_cmd_rx|\\(selectlanguage)/o);
2685 #       local ($contents, $before, $br_id, $env, $pattern);
2686         local($this_env, $opt_arg, $style_info);
2687         $contents = '';
2688         # $1,$2 : optional argument/text --- stylesheet info
2689         # $3 : br_id (at the beginning of an environment name)
2690         # $4 : environment name
2691         # $5 : br_id of open-brace, when $3 == $4 == '';
2692         # $6 : \selectlanguage{...}
2693         if ($7) {
2694             push(@processedE,$`);
2695             $_ = $';
2696             if (defined &do_cmd_selectlanguage) {
2697                 $_ = &do_cmd_selectlanguage($_);
2698             } else {
2699                 local($cmd) = $7;
2700                 $pattern = &missing_braces unless (
2701                     s/$next_pair_rx/$pattern = $2;''/e);
2702                 local($trans) = $pattern.'_translation';
2703                 if (defined &$trans) {
2704                     &set_default_language($pattern,$_);
2705                 }
2706                 undef $cmd; undef $trans;
2707             }
2708             next;
2709         } elsif ($4) {
2710             ($before, $opt_arg, $style_info, $br_id
2711                  , $env, $after, $pattern) = ($`, $2, $3, $4, $5, $', $&);
2712             if (($before)&& (!($before =~ /$begin_env_rx|$begin_cmd_rx/))) {
2713                 push(@processedE,$before);
2714                 $_ = $pattern . $after; $before = '';
2715             }
2716         } else {
2717             ($before, $br_id, $env, $after, $pattern) = ($`, $6, 'group', $', $&);
2718             if (($before)&& (!($before =~ /$begin_env_rx|$begin_cmd_rx/))) {
2719                 push(@processedE,$before);
2720                 $_ = $pattern . $after; $before = '';
2721             }
2722             local($end_cmd_rx) = &make_end_cmd_rx($br_id);
2723             if ($after =~ /$end_cmd_rx/) {
2724                 # ... find the the matching closing one
2725                 $NESTING_LEVEL++;
2726                 ($contents, $after) = ($`, $');
2727                 $contents = &process_group_env($contents);
2728                 print STDOUT "\nOUT: {$br_id} ".length($contents) if ($VERBOSITY > 3);
2729                 print STDOUT "\n:$contents\n" if ($VERBOSITY > 7);
2730                 # THIS MARKS THE OPEN-CLOSE DELIMITERS AS PROCESSED
2731                 $_ = join("", $before,"$OP$br_id$CP", $contents,"$OP$br_id$CP", $after);
2732                 $NESTING_LEVEL--;
2733             } else {
2734                 $pattern = &escape_rx_chars($pattern);
2735                 s/$pattern//;
2736                 print "\nCannot find matching bracket for $br_id";
2737                 $_ = join("", $before,"$OP$br_id$CP", $after);
2738             }
2739             next;
2740         }
2741         $contents = undef;
2742         local($defenv) = $env =~ /deferred/;
2743 #       local($color_env);
2744         local($color_env)
2745             unless ($env =~ /tabular|longtable|in(line|display)|math/);
2746         local($closures,$reopens);
2747         local(@save_open_tags) = @$open_tags_R unless ($defenv);
2748         local($open_tags_R) = [ @save_open_tags ] unless ($defenv);
2749         local(@saved_tags) if ($env =~ /tabular|longtable/);
2750         if ($env =~ /tabular|longtable|makeimage|in(line|display)/) {
2751             @save_open_tags = @$open_tags_R;
2752             $open_tags_R = [ @save_open_tags ];
2753             # check for color
2754             local($color_test) = join(',',@$open_tags_R);
2755             if ($color_test =~ /(color{[^}]*})/g ) {
2756                 $color_env = $1;
2757             } # else { $color_env = '' }
2759             if ($env =~ /tabular|longtable|makeimage/) {
2760                 # close to the surrounding block-type tag
2761                 ($closures,$reopens,@saved_tags) = &preserve_open_block_tags();
2762                 @save_open_tags = @$open_tags_R;
2763                 $open_tags_R = [ @save_open_tags ];
2764                 if ($color_env) {
2765                     $color_test = join(',',@saved_tags);
2766                     if ($color_test =~ /(color{[^}]*})/g ) {
2767                         $color_env = $1;
2768                     }
2769                 }
2770             } elsif ($env =~ /in(line|display)/) {
2771                 $closures = &close_all_tags() if ((&defined_env($env))
2772                     &&!($defenv)&&!($env=~/inline/)&&(!$declarations{$env}));
2773                 if ($color_env) {
2774                     $color_test = $declarations{$color_env};
2775                     $color_test =~ s/<\/.*$//;
2776                     $closures .= "\n$color_test";
2777                     push (@$open_tags_R , $color_env);          
2778                 }
2779             }
2780         } elsif ($env =~ /alltt|tex2html_wrap/) {
2781             # alltt is constructed as paragraphs, not with <PRE>
2782             #  tex2html_wrap  creates an image, which is at text-level
2783         } else {
2784             $closures = &close_all_tags() if ((&defined_env($env))
2785                 &&!($defenv)&&(!$declarations{$env}) );
2786         }
2787         # Sets $contents and modifies $after
2788         if (&find_end_env($env,$contents,$after)) {
2789             print STDOUT "\nIN-A {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2790             &process_command($counters_rx, $before)
2791                 if ($before =~ /$counters_rx/);
2792             # This may modify $before and $after
2793             # Modifies $contents
2794 #RRM: the do_env_... subroutines handle when to translate sub-environments
2795 #           $contents = &translate_environments($contents) if
2796 ##              ((!$defenv) && (&defined_env($env)) && (! $raw_arg_cmds{$env})
2797 ##              && (!$declarations{$env})
2798 #               ((&defined_env($env)) && (! $raw_arg_cmds{$env})
2799 #               && (!($env =~ /latexonly|enumerate|figure|table|makeimage|wrap_inline/))
2800 #               && ((! $NO_SIMPLE_MATH)||(!($env =~ /wrap/)))
2801 #               && (!($env =~ /(math|wrap|equation|eqnarray|makeimage|minipage|tabular)/) )
2802 #               );
2803             if ($opt_arg) { 
2804                 &process_environment(1, $env, $br_id, $style_info); # alters $contents
2805             } else {
2806                 &process_environment(0, $env, $br_id, '');
2807             }
2808             undef $_;
2809             print STDOUT "\nOUT-A {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2810             #JCL(jcl-env) - insert the $O$br_id$C stuff to handle environment grouping
2811             if (!($contents eq '')) {
2812                 $after =~ s/^\n//o if ($defenv);
2813                 $this_env = join("", $before, $closures
2814                           , $contents
2815                           , ($defenv ? '': &balance_tags())
2816                           , $reopens ); $_ = $after;
2817             } else { 
2818                 $this_env = join("", $before , $closures
2819                           , ($defenv ? '': &balance_tags())
2820                           , $reopens ); $_ = $after;
2821             };
2822         ### Evan Welsh <welsh@epcc.ed.ac.uk> added the next 24 lines ##
2823         } elsif (&defined_env($env)) {
2824             print STDOUT "\nIN-B {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2825             # If I specify a function for the environment then it
2826             # calls it with the contents truncated at the next section.
2827             # It assumes I know what I'm doing and doesn't give a
2828             # deferred warning.
2829             $contents = $after;
2830             if ($opt_arg) { 
2831                 $contents = &process_environment(1, $env, $br_id, $style_info);
2832             } else {
2833                 $contents = &process_environment(0, $env, $br_id, '');
2834             }
2835             print STDOUT "\nOUT-B {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2836             $this_env = join("", $before, $closures ,$contents, $reopens);
2838             # there should not be anything left over 
2839 #           $_ = $after;
2840             $_ = '';
2841         } elsif ($ignore{$env}) {
2842             print STDOUT "\nIGNORED {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2843             # If I specify that the environment should be ignored then
2844             # it is but I get a deferred warning.
2845             $this_env = join("", $before , $closures , &balance_tags()
2846                       , $contents, $reopens );
2847             $_ = $after;
2848             &write_warnings("\n\\end{$env} not found (ignored).\n");
2849         } elsif ($raw_arg_cmds{$env}) {
2850             print "\nIN-C {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2851             # If I specify that the environment should be passed to tex
2852             # then it is with the environment truncated at the next
2853             # section and I get a deferred warning.
2855             $contents = $after;
2856             if ($opt_arg) { 
2857                 $contents = &process_environment(1, $env, $br_id, $style_info);
2858             } else {
2859                 $contents = &process_environment(0, $env, $br_id, '');
2860             }
2861             print STDOUT "\nOUT-C {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2862             $this_env = join("", $before, $closures
2863                              , $contents, &balance_tags(), $reopens );
2864             $_='';
2865             &write_warnings(
2866                 "\n\\end{$env $br_id} not found (truncated at next section boundary).\n");
2867         } else {
2868             $pattern = &escape_rx_chars($pattern);
2869             s/$pattern/$closures/;
2870             print "\nCannot find \\end{$env $br_id}\n";
2871             $_ .= join('', &balance_tags(), $reopens) unless ($defenv);
2872         }
2873         if ($this_env =~ /$begin_env_rx|$begin_cmd_rx/) {
2874             $_ = $this_env . $_;
2875         } else { push (@processedE, $this_env) }
2876     }
2877     $_ = join('',@processedE) . $_;
2878     $tmp = $_; undef $_;
2879     &process_command($counters_rx, $tmp) if ($tmp =~ /$counters_rx/);
2880     $_ = $tmp; undef $tmp;
2881     $_
2884 sub find_end_env {
2885     # MRO: find_end_env($env,$contents,$rest)
2886     #local ($env, *ref_contents, *rest) = @_;
2887     my $env = $_[0];
2888     my $be_rx = &make_begin_end_env_rx($env);
2889     my $count = 1;
2891     while ($_[2] =~ /($be_rx)(\n?)/s) { # $rest
2892         $_[1] .= $`; # $contents
2894         if ($2 eq "begin") { ++$count }
2895         else { --$count };
2897         #include any final \n at an {end} only
2898         $_[2] = (($2 eq 'end')? $5 : '') . $'; # $rest
2899         last if $count == 0;
2901         $_[1] .= $1; # $contents
2902     }
2904     if ($count != 0) {
2905         $_[2] = join('', $_[1], $_[2]); # $rest = join('', $contents, $rest);
2906         $_[1] = ''; # $contents
2907         return(0)
2908     } else { return(1) }
2912 sub process_group_env {
2913     local($contents) = @_;
2914     local(@save_open_tags) = @$open_tags_R;
2915     local($open_tags_R) = [ @save_open_tags ];
2916     print STDOUT "\nIN::{group $br_id}" if ($VERBOSITY > 4);
2917     print STDOUT "\n:$contents\n" if ($VERBOSITY > 6);
2919     # need to catch explicit local font-changes
2920     local(%font_size) = %font_size if (/\\font\b/);
2922     # record class/id info for a style-sheet entry
2923     local($env_id, $tmp, $etmp);
2924     if (($USING_STYLES) && !$PREAMBLE ) { $env_id = $br_id; }
2925 #       $env_id = "grp$br_id";
2926 #       $styleID{$env_id} = " ";
2927 #        $env_id = " ID=\"$env_id\"";
2928 #    }
2930     undef $_;
2931     $contents =~ s/^\s*$par_rx\s*//s; # don't start with a \par 
2932     if ($contents =~ /^\s*\\($image_switch_rx)\b\s*/s) {
2933         # catch TeX-like environments: {\fontcmd ... }
2934         local($image_style) = $1;
2935         if ($USING_STYLES) {
2936             $env_style{$image_style} = " " unless ($env_style{$image_style});
2937         }
2938         local($switch_cmd) = "do_cmd_${image_style}";
2939         if (defined &$switch_cmd ) {
2940             eval "\$contents = \&${switch_cmd}(\$')";
2941             print "\n*** &$switch_cmd didn't work: $@\n$contents\n\n" if ($@);
2942         } elsif ($contents =~ /$par_rx/) {
2943             # split into separate image for each paragraph
2944             local($par_style,$this_par_img) = '';
2945             local(@par_pieces) = split($par_rx, $contents);
2946             local($this_par,$par_style,$par_comment);
2947             $contents = '';
2948             while (@par_pieces) {
2949                 $this_par = shift @par_pieces;
2950                 if ($this_par =~ /^\s*\\($image_switch_rx)\b/s) {
2951                     $image_style = $1;
2952                     $par_style = 'P.'.$1;
2953                     $env_style{$par_style} = " " unless ($env_style{$par_style});
2954                 }
2955 #       no comment: source is usually too highly encoded to be meaningful
2956 #       $par_comment = &make_comment($image_style,$this_par);
2957                 $this_par_img = &process_in_latex("\{".$this_par."\}");
2958                 $contents .=  join(''  #,"\n", $par_comment
2959                         , "\n<P"
2960                         , (($USING_STYLES && $image_style)? " CLASS=\"$image_style\"" :'')
2961                         ,">", $this_par_img
2962                         , "</P>\n");
2963                 if (@par_pieces) {
2964                     # discard the pieces from matching  $par_rx
2965                     $dum = shift @par_pieces;
2966                     $dum = shift @par_pieces;
2967                     $dum = shift @par_pieces;
2968                     $dum = shift @par_pieces;
2969                     $dum = shift @par_pieces;
2970                     $dum = shift @par_pieces;
2971 #                   $contents .= "\n</P>\n<P>";
2972                 }
2973             }
2974         } else {
2975             $contents = &process_undefined_environment("tex2html_accent_inline"
2976                 , ++$global{'max_id'},"\{".$contents."\}");
2977         }
2978     } elsif ($contents =~ /^\s*\\(html)?url\b($O\d+$C)[^<]*\2\s*/) {
2979         # do nothing
2980         $contents = &translate_environments($contents);
2981         $contents = &translate_commands($contents);
2982     } elsif (($env_switch_rx)&&($contents =~ s/^(\s*)\\($env_switch_rx)\b//s)) {
2983         # write directly into images.tex, protected by \begingroup...\endgroup
2984         local($prespace, $cmd, $tmp) = ($1,$2,"do_cmd_$2");
2985         $latex_body .= "\n\\begingroup ";
2986         if (defined &$tmp) {
2987             eval("\$contents = &do_cmd_$cmd(\$contents)");
2988         }
2989         $contents = &translate_environments($contents);
2990         $contents = &translate_commands($contents);
2991         undef $tmp; undef $cmd;
2992         $contents .= "\n\\endgroup ";
2993     } elsif ($contents =~ /^\s*\\([a-zA-Z]+)\b/s) { 
2994         local($after_cmd) = $';
2995         local($cmd) = $1; $tmp = "do_cmd_$cmd"; $etmp = "do_env_$cmd";
2996         if (($cmd =~/^(rm(family)?|normalsize)$/)
2997                 ||($declarations{$cmd}&&(defined &$tmp))) {
2998             do{
2999                 local(@save_open_tags) = @$open_tags_R;
3000                 eval "\$contents = \&$tmp(\$after_cmd);";
3001                 print "\n*** eval &$tmp failed: $@\n$contents\n\n" if ($@);
3002                 $contents .= &balance_tags();
3003             };
3004         } elsif ($declarations{$cmd}&&(defined &$etmp)) {
3005             eval "\$contents = \&$etmp(\$after_cmd);";
3006         } else {
3007             $contents = &translate_environments($contents);
3008             $contents = &translate_commands($contents)
3009                 if ($contents =~ /$match_br_rx/o);
3010             # Modifies $contents
3011             &process_command($single_cmd_rx,$contents) if ($contents =~ /\\/o);
3012         }
3013         undef $cmd; undef $tmp; undef $etmp;
3014     } else { 
3015         $contents = &translate_environments($contents);
3016         $contents = &translate_commands($contents)
3017             if ($contents =~ /$match_br_rx/o);
3018         # Modifies $contents
3019         &process_command($single_cmd_rx,$contents)
3020             if ($contents =~ /\\/o);
3021     }
3022     $contents . &balance_tags();
3025 # MODIFIES $contents
3026 sub process_environment {
3027     local($opt, $env, $id, $styles) = @_;
3029     local($envS) = $env; $envS =~ s/\*\s*$/star/;
3030     local($env_sub,$border,$attribs,$env_id) = ("do_env_$envS",'','','');
3031     local($original) = $contents;
3033     if ($env =~ /tex2html_deferred/ ) {
3034         $contents = &do_env_tex2html_deferred($contents);
3035         return ($contents);
3036     }
3037     $env_id = &read_style_info($opt, $env, $id, $styles) 
3038         if (($USING_STYLES)&&($opt));
3040     if (&defined_env($env)) {
3041         print STDOUT ",";
3042         print STDOUT "{$env $id}" if ($VERBOSITY > 1);
3043 #       $env_sub =~ s/\*$/star/;
3044         $contents = &$env_sub($contents);
3046     } elsif ($env =~ /tex2html_nowrap/) {
3047         #pass it on directly for LaTeX, via images.tex
3048         $contents = &process_undefined_environment($env, $id, $contents);
3049         return ($contents);
3051 #    elsif (&special_env) {     # &special_env modifies $contents
3052     } else {
3053         local($no_special_chars) = 0;
3054         local($failed) = 0;
3055         local($has_special_chars) = 0;
3056         &special_env; #  modifies $contents
3057         print STDOUT "\n<MATH $env$id $contents>" if ($VERBOSITY > 3);
3058         if ($failed || $has_special_chars) {
3059             $contents = $original;
3060             $failed = 1;
3061             print STDOUT " !failed!\n" if ($VERBOSITY > 3);
3062         }
3063     }
3064     if (($contents) && ($contents eq $original)) {
3065         if ($ignore{$env}) {  return(''); }
3066         # Generate picture
3067         if ($contents =~ s/$htmlborder_rx//o) {
3068             $attribs = $2; $border = (($4)? "$4" : 1)
3069         } elsif ($contents =~ s/$htmlborder_pr_rx//o) { 
3070             $attribs = $2; $border = (($4)? "$4" : 1)
3071         }
3072         $contents = &process_undefined_environment($env, $id, $contents);
3073         $env_sub = "post_latex_$env_sub"; # i.e. post_latex_do_env_ENV
3074         if ( defined &$env_sub) {
3075             $contents = &$env_sub($contents);
3076         } elsif (($border||($attributes))&&($HTML_VERSION > 2.1)) {
3077             $contents = &make_table($border,$attribs,'','','',$contents);
3078         } else {
3079             $contents = join('',"<BR>\n",$contents,"\n<BR>")
3080                 unless (!($contents)||($inner_math)||($env =~
3081                       /^(tex2html_wrap|tex2html_nowrap|\w*math|eq\w*n)/o ));
3082         }
3083     }
3084     $contents;
3088 #RRM: This reads the style information contained in the optional argument
3089 #   to the \begin command. It is stored to be recovered later as an entry
3090 #   within the automatically-generated style-sheet, if $USING_STYLES is set.
3091 # Syntax for this info is:
3092 #   <style names> ; <extra style-info> 
3094 sub read_style_info {
3095     local($opt, $envS, $id, $styles) = @_;
3096     return() unless (($opt)&&($USING_STYLES));
3097     # allow macro-expansion within the style-info
3098     $opt = &translate_commands($opt) if ($opt =~ /\\/);
3100     # record class/id info for a style-sheet entry
3101     local($style_names, $style_extra, $env_id)=(''," ",'');
3102     if ($opt) {
3103         # if there is a `;'  then <names> ; <extra>
3104         if ($styles =~ /^\s*([^\|]*)\|\s*(.*)$/) {
3105             $style_names = $1; $style_extra = $2;
3106             if ($style_names =~ /[=:;]/) {
3107                 # cannot be <names>, so is <extra>
3108                 $style_extra = $style_names.$style_extra;
3109                 $style_names = '';
3110             }
3111         } elsif ($styles =~ /[\=\:]/) {
3112             # cannot be <names>, so is <extras>
3113             $style_extra = $styles;
3114         } else { $style_names = $styles }
3115         $style_extra =~ s/\s*[=:]\s*/ : /go;
3116         $style_extra =~ s/([\w,\-]+)\s+([\w,\-]+)/$1 ; $2/go;
3117         $style_extra =~ s/\s*,\s*/ /go;
3119         if ($style_names) {
3120             local($sname);
3121             local(@names) = split ( /\s+/ , $style_names );
3122             # ensure a style-sheet entry for each new name
3123             foreach $sname (@names) {
3124                 $env_style{$sname} = " "
3125                     unless (($env_style{$sname})||($sname =~ /^\s*$/));         
3126             }
3127         }
3128     }
3129     # remove uninformative part of internally-defined env names
3130     $envS =~ s/tex2html_(\w+_)?(\w+)/$2/; $envS =~ s/preform/pre/;
3131     $env_id = $envS.$id;
3132     $styleID{$env_id} = $style_extra unless ($PREAMBLE);
3133     
3134     if ($style_names) { $envS = "$style_names" }
3135     elsif (($envS =~ /^pre$/)&&
3136         (/^\\begin.*preform($O|$OP)\d+($C|$CP)$verbatim_mark(\w*[vV]erbatim)(\*?)/))
3137             { $envS = $3.($4 ? 'star' : '') };
3138     $env_style{$envS} = " " unless (($style_names)||($env_style{$envS}));
3139     $env_id = " ID=\"$env_id\"".(($envS) ? " CLASS=\"$envS\"" : '');
3140     return($env_id);
3143 # RRM: This provides the mechanism to save style information in %env_style
3144 #      using LaTeX macros  \htmlsetstyle  and  \htmladdtostyle
3146 sub process_htmlstyles {
3147     local($mode, $_) = @_;
3148     local($pre_tags) = &get_next_optional_argument;
3149     local($class) = &missing_braces unless (
3150         (s/$next_pair_pr_rx/$class = $2;''/e)
3151         ||(s/$next_pair_rx/$class = $2;''/e));
3152     local($sinfo) = &missing_braces unless (
3153         (s/$next_pair_pr_rx/$sinfo = $2;''/e)
3154         ||(s/$next_pair_rx/$sinfo = $2;''/e));
3155     return ($_) unless ($class||$pre_tags);
3157     $class = $pre_tags.($class ?'.':'').$class;
3158     $sinfo =~ s/\s*[:=]\s*/ : /g;
3159     $sinfo =~ s/\s*,\s*/ /g;
3160     if ($mode =~ /add/) {
3161         $sinfo = '; '.$sinfo if ($env_style{$class}); 
3162         $env_style{$class} .= $sinfo;
3163     } else { $env_style{$class} = $sinfo }
3164     $_;
3166 sub do_cmd_htmlsetstyle   { &process_htmlstyles('set',@_) }
3167 sub do_cmd_htmladdtostyle { &process_htmlstyles('add',@_) }
3170 # The $<$, $>$, $|$ and $=>$, etc strings are replaced with their textual
3171 # equivalents instead of passing them on to latex for processing in math-mode.
3172 # This will not be necessary when the mechanism for passing environments
3173 # to Latex is improved.
3174 # RETURNS SUCCESS OR FAILURE
3175 sub special_env {
3176     # Modifies $contents in its caller
3177     local($next)='';
3178     local ($allow) = $HTML_VERSION ge '3.0' ?
3179          "[^#\$%&~\\\\{}]|\\limits" : "[^^#\$%&~_\\\\{}]";
3180     #JKR: Use italics instead of bold #HWS: Generalize to include more symbols.
3181 #    $contents =~ s/^\$(\s*($html_specials_inv_rx|$allow)*\s*)\$(.)?/
3182 #       $next=$3;&simple_math_env($1).(($next =~ m|\w|)? " ":'').$next/ige;
3183     $contents =~ s/^\$(\s*($html_specials_inv_rx|$allow)*\s*)\$$/
3184         &simple_math_env($1)." "/ige;
3185     if ($contents =~ /\&\w*;/) { $has_math_chars=1 }
3186     if ($contents =~ /;SPM([a-zA-Z]+);/) { $has_special_chars=1 };
3189 # Translate simple math environments into italic.
3190 # Only letters should become italic; symbols should stay non-italic.
3191 sub simple_math_env {
3192     local($mathcontents) = @_;
3193     if ($mathcontents eq '') { return("$mathcontents"); }
3194     elsif ($NO_SIMPLE_MATH) {  # always make an image
3195         $failed = 1; return($mathcontents);
3196     } elsif ($mathcontents =~ /\\/) { # any macro kills "simple-math"
3197         local($save_math) = $mathcontents;
3198         local(@text_only) = ();
3199         while ((!$failed)&&($mathcontents =~
3200                 /\\((boldsymbol|bm)|(math|text)(bf|rm|it|tt)|times|[{}@#^_])(\b|[^A-Za-z]|$)/)) {
3201             # ...except when only simple styles
3202             push (@text_only, $`, ("$2$4" ? "\\simplemath".($4 ? $4 :"bf") :"\\$1") );
3203             $mathcontents = $5.$';
3204             $failed = 1 if ($` =~ /\\/);
3205         }
3206         $failed = 1 if ($mathcontents =~ /\\/);
3207         return($save_math) if $failed;
3208         $mathcontents = join('',@text_only,$mathcontents);
3209     }
3210     # Is there a problem here, with nested super/subscripts ?
3211     # Yes, so do each pattern-match for bracketings within a while-loop
3212     while ($mathcontents =~ s/\^$any_next_pair_rx/<SUP>$2<\/SUP>/go){};
3213     while ($mathcontents =~ s/\^$any_next_pair_pr_rx/<SUP>$2<\/SUP>/go){};
3214     while ($mathcontents =~ s/_$any_next_pair_rx/<SUB>$2<\/SUB>/g){};
3215     while ($mathcontents =~ s/_$any_next_pair_pr_rx/<SUB>$2<\/SUB>/g){};
3217     $mathcontents =~ s/\^(\\[a-zA-Z]+|.)/<SUP>$1<\/SUP>/g;
3218     $mathcontents =~ s/_(\\[a-zA-Z]+|.)/<SUB>$1<\/SUB>/g;
3219     $mathcontents =~ s/(^|\s|[,;:'\?\.\[\]\(\)\+\-\=\!>]|[^\\<]\/|\d)(<(I|TT|B)>)?([a-zA-Z]([a-zA-Z ]*[a-zA-Z])?)(<\/\3>)?/
3220         $1.(($2)? $2 :'<I>').$4.(($6)? $6 : '<\/I>')/eig;
3222     $mathcontents =~ s/\\times($|\b|[^A-Za-z])/ x $1/g;
3223     $mathcontents =~ s/\\times($|\b|[^A-Za-z])/ x $1/g;
3224     $mathcontents =~ s/\\\\/<BR>\n/g;
3225     $mathcontents =~ s/\\\\/<BR>\n/g;
3226     $mathcontents =~ s/\\([,;])/ /g;
3227     $mathcontents =~ s/\\(\W)/$1/g;
3228     $mathcontents =~ s/ {2,}/ /g;
3230     # any simple style changes remove enclosed <I> tags
3231     $mathcontents = &translate_commands($mathcontents)
3232         if ($mathcontents =~ /\\/);
3234     $mathcontents =~ s/<I><\/(SUB|SUP)>/<\/$1><I>/g;
3235     $mathcontents =~ s/<(SUB|SUP)><\/I>/<\/I><$1>/g;
3236     $mathcontents =~ s/;<I>SPM([a-zA-Z]+)<\/I>;/;SPM$1;/go;
3237     $mathcontents =~ s/<(\/?)<I>(SUB|SUP|I|B|TT)<\/I>>/<$1$2>/g;
3238     $mathcontents =~ s/<\/(B|I|TT)><\1>//g;
3239     $mathcontents;
3242 sub do_cmd_simplemathrm { 
3243     local ($_) = @_;
3244     local($text);
3245     $text = &missing_braces unless (
3246         (s/$next_pair_pr_rx/$text = $2;''/e)
3247         ||(s/$next_pair_rx/$text = $2;''/e));
3248     $text =~ s/<\/?I>//g;
3249     join('', $text, $_)
3251 sub do_cmd_simplemathbf { 
3252     local ($_) = @_;
3253     local($text);
3254     $text = &missing_braces unless (
3255         (s/$next_pair_pr_rx/$text = $2;''/e)
3256         ||(s/$next_pair_rx/$text = $2;''/e));
3257     $text =~ s/<\/?I>//g;
3258     join('','<B>', $text, '</B>', $_)
3260 sub do_cmd_simplemathtt {
3261     local ($_) = @_;
3262     local($text);
3263     $text = &missing_braces unless (
3264         (s/$next_pair_pr_rx/$text = $2;''/e)
3265         ||(s/$next_pair_rx/$text = $2;''/e));
3266     $text =~ s/<\/?I>//g;
3267     join('','<TT>', $text, '</TT>', $_)
3270 sub process_math_in_latex {
3271     local($mode,$style,$level,$math) = @_;
3272     local(@anchors);
3273     if ($level) {
3274         $style = (($level > 1) ? "script" : "") . "script";
3275     } elsif (! $style) { 
3276         $style = (($mode =~/display|equation/)? "display" : "")
3277     }
3278     $style = "\\${style}style" if ($style);
3280     #  &process_undefined_environment  changes $_ , so save it.
3281     local($after) = $_;
3283     # the 'unless' catches nested AMS-aligned environments
3284     $mode = "tex2html_wrap_" .
3285         (($mode =~/display|equation|eqnarray/) ? 'indisplay' : 'inline')
3286             unless ($mode =~ /^equationstar/ && $outer_math =~ /^equationstar/);
3288     $global{'max_id'}++;
3289     $math =~ s/\\(\n|$)/\\ $1/g;        # catch \ at end of line or string
3290     $math =~ s/^\s*((\\!|;SPMnegsp;)\s*)*//g;           # remove neg-space at start of string
3291     if ($mode =~ /tex2html_wrap_/ ) {
3292         $math = &process_undefined_environment( $mode
3293             , $global{'max_id'}, join('', "\$$style ", $math, "\$"));
3294     } else {
3295         # some AMS environments must be within {equation} not {displaymath}
3296         $math =~ s/displaymath/equation*/
3297                 if ($math =~ /\\begin\{(x+|fl)*align/);
3298         $math = &process_undefined_environment($mode, $global{'max_id'}, $math);
3299     }
3300     $math .= "\n" if ($math =~ /$comment_mark\s*\d+$/s);
3301     $_ = $after;
3302     # the delimiter \001 inhibits an unwanted \n at image-replacement
3303     $math . ($math =~ /$image_mark/? "\001" : '');
3305      
3306 #RRM: Explicit font switches need images. Use the image_switch mechanism.
3307 sub do_cmd_font {
3308     local($_) = @_;
3309     local($fontinfo,$fontname,$size) = ('','','10pt');
3310     s/\s*\\(\w+)\s*=?\s*(.*)(\n|$)/$fontname=$1;$fontinfo=$2;''/eo;
3311     $image_switch_rx .= "|$fontname";
3313     if ($fontinfo =~ /([.\d]+\s*(true)?(pt|mm|cm))/ ) { $size = $1 }
3314     elsif ( $fontinfo =~ /[a-zA-Z]+(\d+)\b/ ) { $size = $1.'pt' }
3315     if  ( $fontinfo =~ /(scaled|at)\s*\\?(.+)/) { $size .= " scaled $1" }
3316     $font_size{$fontname} = $size;
3317     $_;
3319 sub wrap_cmd_font {
3320     local($cmd, $_) = @_;
3321     local ($args, $dummy, $pat) = "";
3322     if (/\n/) { $args .= $`.$& ; $_ = $' } else {$args = $_; $_ = ''};
3323     (&make_deferred_wrapper(1).$cmd.$padding.$args.&make_deferred_wrapper(0),$_)
3326 sub do_cmd_newfont {
3327     local($_) = @_;
3328     local($fontinfo,$fontname,$size) = ('','','10pt');
3329     $fontname = &missing_braces unless (
3330         (s/$next_pair_pr_rx/$fontname=$2;''/eo)
3331         ||(s/$next_pair_rx/$fontname=$2;''/eo));
3332     $fontname=~ s/^\s*\\|\s*$//g;
3333     $image_switch_rx .= "|$fontname";
3335     $fontinfo = &missing_braces unless (
3336         (s/$next_pair_pr_rx/$fontinfo=$2;''/eo)
3337         ||(s/$next_pair_rx/$fontinfo=$2;''/eo));
3338     if ($fontinfo =~ /([.\d]+\s*(true)?(pt|mm|cm))/ ) { $size = $1 }
3339     elsif ( $fontinfo =~ /[a-zA-Z]+(\d+)\b/ ) { $size = $1.'pt' }
3340     if  ( $fontinfo =~ /(scaled|at)\s*\\?(.+)/) { $size .= " scaled $1" }
3341     $font_size{$fontname} = $size;
3342     $_;
3345 sub defined_env {
3346     local($env) = @_;
3347     $env =~ s/\*$/star/;
3348     local($env_sub) = ("do_env_$env");
3349     # The test using declarations should not be necessary but 'defined'
3350     # doesn't seem to recognise subroutines generated dynamically using 'eval'.
3351     # Remember that each entry in $declarations generates a dynamic prodedure ...
3352     ((defined &$env_sub) || ($declarations{$env}));
3355 # RRM: utility to add style information to stored image-parameters
3356 #      currently only (math) scaling info is included;
3357 #      current color, etc.  could also be added here.
3358 sub addto_encoding {
3359     local($env, $contents) = @_;
3360 #    $contents =~ s/(\\(begin|end)\s*)?<<\d*>>|\n//g;   # RRM: remove env delimiters
3361     $contents =~ s/(\\(begin|end)\s*(<<\d*>>))|\n//g;   # RRM: remove env delimiters
3362     # append scaling information for environments using it
3363     if (($MATH_SCALE_FACTOR)
3364         &&(($contents =~ /makeimage|inline|indisplay|entity|displaymath|eqnarray|equation|xy|diagram/)
3365            ||($env =~ /makeimage|inline|indisplay|entity|displaymath|eqnarray|equation|xy|diagram/))
3366         ) { $contents .= ";MSF=$MATH_SCALE_FACTOR" }
3368     if ($LATEX_FONT_SIZE =~ /([\d\.]+)pt/) {
3369         local($fsize) = $1;
3370         $contents .= ";LFS=$fsize" unless ($fsize ==10);
3371     }
3373     if (($EXTRA_IMAGE_SCALE)
3374         &&(($contents =~ /makeimage|inline|indisplay|entity|displaymath|eqnarray|equation|xy|diagram/)
3375            ||($env =~ /makeimage|inline|indisplay|entity|displaymath|eqnarray|equation|xy|diagram/))
3376         ) { $contents .= ";EIS=$EXTRA_IMAGE_SCALE" }
3378     if (($DISP_SCALE_FACTOR)
3379         &&(($contents =~ /indisplay|displaymath|eqnarray|equation/)
3380            ||($env =~ /indisplay|displaymath|eqnarray|equation/))
3381         &&!(($contents =~ /makeimage/)||($env =~ /makeimage/))
3382         ) { $contents .= ";DSF=$DISP_SCALE_FACTOR" }
3384     if (($EQN_TAGS)
3385         &&(($env =~ /eqnarray($|[^_\*])|equation/)
3386            ||($contents =~ /eqnarray($|[^_\*])|equation/))
3387         &&!(($contents =~ /makeimage/)||($env =~ /makeimage/))
3388         ) { $contents .= ";TAGS=$EQN_TAGS" }
3390     if (($FIGURE_SCALE_FACTOR)
3391         &&!(($contents =~ /makeimage/)||($env =~ /makeimage/))
3392         &&(($contents =~ /figure/)||($env =~ /figure/))
3393         ) { $contents .= ";FSF=$FIGURE_SCALE_FACTOR"}
3395     if (($ANTI_ALIAS)
3396         &&(($contents =~ /figure/)||($env =~ /figure/))
3397         &&!(($contents =~ /makeimage/)||($env =~ /makeimage/))
3398         ) { $contents .= ";AAF" }
3399     elsif ($ANTI_ALIAS_TEXT) { $contents .= ";AAT" }
3400     if (!$TRANSPARENT_FIGURES) { $contents .= ";NTR" }
3402     $contents;
3405 sub process_undefined_environment {
3406     local($env, $id, $contents) = @_;
3407     if ($env =~ s/\*{2,}/*/) { print "\n*** $_[0] has too many \*s ***"};
3409     local($name,$cached,$raw_contents,$uucontents) = ("$env$id");
3410     $name =~ s/\*/star/;
3411     local($oldimg,$size,$fullcontents,$imgID);
3412     return if ($AUX_FILE);
3414     # catch \footnotemark within an image, especially if in math
3415     local(@foot_anchors,$foot_anchor);
3416     local($im_footnote,$im_mpfootnote) = ($global{'footnote'},$global{'mpfootnote'});
3417     @foot_anchors = &process_image_footnote($contents)
3418         if ($contents =~ /\\footnote(mark)?\b/s);
3419     if ((@foot_anchors)&&($eqno)) {
3420         # append the markers to the equation-numbers
3421         $eqno .= join(' ', ' ', @foot_anchors);
3422         @foot_anchors = ();
3423     }
3424     
3425     print STDOUT "\nUNDEF-IN {$env $id}:\n$contents\n" if ($VERBOSITY > 4);
3426     #RRM - LaTeX commands wrapped with this environment go directly into images.tex.
3427     if ($env =~ /tex2html_nowrap|^lrbox$/){ # leave off the wrapper, do not cache
3428         # totally ignore if in preamble...
3429         # ...since it will be put into  images.tex  anyway!!
3430         if (!($PREAMBLE)) {
3431             $contents =~ s/^\n+|\n+$/\n/g;
3432             local($lcontents) = join('', "\\begin{$env}", $contents , "\\end{$env}" );
3433             $lcontents =~ s/\\(index|label)\s*(($O|$OP)\d+($C|$CP)).*\2//sg;
3434             print STDOUT "pre-LATEX {$env}:\n$lcontents\n" if ($VERBOSITY > 3);
3435             $raw_contents = &revert_to_raw_tex($lcontents);
3436             print STDOUT "LATEX {$env}:\n$raw_contents\n" if ($VERBOSITY > 3);
3437             $latex_body .= "\n$raw_contents"."%\n\n" ;
3438         }
3439         return("") if ($env =~ /^lrbox/);
3440         # ignore enclosed environments; e.g. in  \settolength  commands
3441 #       $contents = &translate_environments($contents); # ignore environments
3442 #       $contents = &translate_commands($contents);
3443         # ...but apply any Perl settings that may be defined
3444         $contents = &process_command($single_cmd_rx,$contents);
3445         print STDOUT "\nOUT {$env $id}:\n$contents\n" if ($VERBOSITY > 4);
3446         return("");
3447     }
3448     # catch pre-processor environments
3449     if ($PREPROCESS_IMAGES) {
3450         local($pre_env,$which, $done, $indic);
3451         while ($contents =~ /$pre_processor_env_rx/) {
3452             $done .= $`; $pre_env = $5; $which =$1; $contents = $';
3453             if (($which =~ /begin/)&&($pre_env =~ /indica/)) {
3454                 if ($contents =~ s/^\[(\w+)]//o) { $done .= '#'.$1 }
3455             } elsif (($which =~ /end/)&&($pre_env =~ /indica/)) {
3456                 $done .= '#NIL';
3457             } elsif (($which =~ /begin/)&&($pre_env =~ /itrans/)) {
3458                 if ($contents =~ s/^\[(\w+)]/$indic=$1;''/e)
3459                     { $done .= "\#$indic" }
3460             } elsif (($which =~ /end/)&&($pre_env =~ /itrans/)) {
3461                 $done .= "\#end$indic";
3462             } elsif ($which =~ /begin/) {
3463                 $done .= (($which =~ /end/)? $end_preprocessor{$pre_env}
3464                           : $begin_preprocessor{$pre_env} )
3465             }
3466         }
3467         $contents = $done . $contents;
3468     }
3469     $fullcontents =  $contents; # save for later \label search.
3470     # MRO: replaced $* with /m
3471     $contents =~ s/\n?$labels_rx(\%([^\n]+$|$EOL))?/\n/gm;
3473     local($tmp) = $contents;
3474     $tmp =~ s/^((\\par|\%)?\s*\n)+$//g;
3475     return( &do_labels($fullcontents, "\&nbsp;") ) unless $tmp;
3477     # just a comment as the contents of a cell in a math-display
3478     if ($tmp =~ /\$\\(display|text|(script)+)style\s*$comment_mark\d+\s*\$$/)
3479         { return ( &do_labels($fullcontents, "\&nbsp;") ) };
3481     $contents = "\n% latex2html id marker $id\n$contents" if
3482         (!$PREAMBLE &&($contents =~ /$order_sensitive_rx/)
3483                 &&(!($env =~ /makeimage/)));
3485     $env =~ s/displaymath/equation*/
3486         if ($contents =~ /\\begin\{(x+|fl)*align/);
3487     #RRM: include the inline-color, when applicable
3488     $contents = join(''
3489             , (($inner_math =~ /in(display|line)/) ? '$' : '')
3490             , "\\begin{$env}"
3491             , ($color_env ? "\\bgroup\\$color_env" : '')
3492             , $contents , ($color_env ? "\\egroup" : '')
3493             , "\\end{$env}"
3494             , (($inner_math =~ /in(display|line)/) ? '$' : '')
3495         ) if ($contents);
3497     # append to the name of special environments found within math
3498     if ($inner_math) {
3499         local($ext) = $inner_math;
3500         if ($inner_math =~ /(display|line)/){ $ext = 'in'.$1;};
3501         $name =~ s/(\d+)$/_$ext$1/;
3502     }
3504     if (!($latex_body{$name} = $contents)) {
3505         print "\n *** code for $name is too long ***\n"}
3506     if ($contents =~ /$htmlimage_rx/) {
3507         $uucontents = &special_encoding($env,$2,$contents);
3508     } elsif ($contents =~ /$htmlimage_pr_rx/) {
3509         $uucontents = &special_encoding($env,$2,$contents);
3510     } else {
3511         $uucontents = &encode(&addto_encoding($env,$contents));
3512     }
3513     $cached = $cached_env_img{$uucontents};
3514     print STDOUT "\nCACHED: $uucontents:\n$cached\n" if ($VERBOSITY > 4);
3515     if ($NOLATEX) { 
3516         $id_map{$name} = "[$name]";
3517     } elsif (defined ($_ = $cached)) { # Is it in our cache?
3518         # Have we already used it?
3519         if (($oldimg) = /SRC="$PREFIX$img_rx\.$IMAGE_TYPE"/o) {
3520             # No, check its size
3521             local($eis) = 1;
3522             # Does it have extra scaling ?
3523             if ($uucontents =~ /EIS=(.*);/) { $eis = $1 }
3524             ($size, $imgID) = &get_image_size("$PREFIX$oldimg.old", $eis);      
3525             # Does it have extra scaling ?
3526 #           if ($uucontents =~ /EIS=(.*);/) {
3527 #               local($eis) = $1; local($w,$h);
3528 #               # quotes will not be there with HTML 2.0
3529 #               $size =~ s/(WIDTH=\")(\d*)(\".*HEIGHT=\")(\d*)\"/
3530 #                   $w = int($2\/$eis + .5); $h=int($4\/$eis + .5);
3531 #                   "$1$w$3$h\""/e ; # insert the re-scaled size
3532 #           }
3533             # quotes will not be there with HTML 2.0
3534             $size =~ s/\"//g if ($HTML_VERSION < 2.2);
3535             if ($size && /\s$size\s/) {
3536                 # Size is OK; recycle it!
3537                 ++$global_page_num;
3538                 $_ = $cached ;    # ...perhaps restoring the desired size.
3539                 s/(${PREFIX}T?img)\d+\.($IMAGE_TYPE|html)/
3540                         &rename_html($&,"$1$global_page_num.$2")/geo;
3541             } else {
3542                 if ($env =~ /equation/) { &extract_eqno($name,$cached) }
3543                 $_ = "";                                # The old Image has wrong size!
3544                 undef($cached);                 #  (or it doesn't exist)
3545             }
3546         }
3547         s/(IMG\n)/$1$imgID/ if $imgID;
3549         s/$PREFIX$img_rx\.new/$PREFIX$1.$IMAGE_TYPE/go; # Point to the actual image file(s)
3550         $id_map{$name} = $_;
3551         s/$PREFIX$img_rx\.$IMAGE_TYPE/$PREFIX$1.new/go; # But remember them as used.
3552         $cached_env_img{$uucontents} = $_;
3553     }
3555     if (! defined($cached)) {                           # Must generate it anew.
3556         &clear_images_dbm_database
3557             unless ($new_page_num ||($NO_SUBDIR && $FIXEDDIR));
3558         $new_id_map{$name} = $id_map{$name} = ++$global_page_num . "#" .
3559             ++$new_page_num;
3560         $orig_name_map{$id_map{$name}} = $name;
3561         $cached_env_img{$uucontents} = $id_map{$name} if ($REUSE == 2);
3563         #RRM: this (old) code frequently crashes NDBM, so do it in 2 steps
3564 #       $img_params{$name} = join('#', &extract_parameters($contents));
3565         local(@params) = &extract_parameters($contents);
3566         $img_params{$name} = join('#',@params); undef $params;
3567         print "\nIMAGE_PARAMS $name: ".$img_params{$name} if ($VERBOSITY > 3);
3569         $contents =~ s/\\(index|label)\s*(($O|$OP)\d+($C|$CP)).*\2//sg;
3570         print STDOUT "\nLATEX {$env}:\n$contents" if ($VERBOSITY > 3);
3571         $raw_contents = &revert_to_raw_tex($contents) unless ($contents =~ /^\s*$/) ;
3572         $raw_contents =~ s/\\pagebreak|\\newpage|\\clearpage/\\\\/go;
3573         print STDOUT "\nLATEX {$env}:\n$raw_contents\n" if ($VERBOSITY > 3);
3574         local($box_type) = '';
3575         if ($raw_contents =~ /\\special\s*\{/) { 
3576             $tex_specials{$name} = "1";
3577             &write_warnings("\nenvironment $name contains \\special commands");
3578             print STDOUT "\n *** environment $name contains \\special commands ***\n"
3579                 if ($VERBOSITY);
3580         } elsif (($env =~ /$inline_env_rx/)||($inner_math =~ /in(line|display)/)) {
3581             # crop to the marks only... or shave a bit off the bottom
3582             if (($env =~ /tex2html_[^w]/)||$inner_math) {
3583                 # e.g. accents, indic  but not wrap
3584                 $crop{$name} = "bl";
3585                 $box_type = "i";                
3586             } else {
3587             # ...or shave a bit off the bottom as well
3588                 $crop{$name} = "bls";
3589                 $box_type = "h";
3590             }
3591         } elsif (($env =~ /(eqnarray|equation)(\*|star)/)||($inner_math)) {
3592             # crop to minimum size...
3593             $crop{$name} = "blrl";
3594             $box_type = "v";
3595         } elsif ($env =~ /(picture|tex2html_wrap)(\*|star)?/) {
3596             # crop hbox to minimum size...
3597             $crop{$name} = "";
3598             $box_type = "p";
3599         } elsif ($env =~ /$display_env_rx/) {
3600             # crop vbox to minimum size...
3601             $crop{$name} = "blrl" ;
3602             if ($env =~ /(equation|eqnarray)((s)?$|\d)/) {
3603                 # ... unless equation numbers are included ...
3604                 if ($3) { #  AMS {subequations}
3605                     $global{'eqn_number'}=$prev_eqn_number if $prev_eqn_number;
3606                     --$global{'eqn_number'};
3607                 }
3608                 $raw_contents = join('' ,
3609                     (($eqno{$name}||$global{'eqn_number'})?
3610                       &set_equation_counter($eqno{$name}) : '')
3611                     , $raw_contents);
3612                 $crop{$name} = "bl" ;
3613             } elsif ($HTML_VERSION < 2.2) {
3614                 # ... HTML 2.0 cannot align images, so keep the full typeset width
3615                 $crop{$name} = "bl" ;           
3616             }
3617             $box_type = "v";
3618         }
3619         
3620         #RRM: include the TeX-code for the appropriate type of box.
3621         eval "\$raw_contents = \&make_$box_type"."box($name, \$raw_contents);";
3623         # JCL(jcl-pag) - remember html text if debug is set.
3624         local($_);
3625         if ($DEBUG) {
3626             $_ = $contents;
3627             s/\n/ /g;
3628             $_ = &revert_to_raw_tex($_);
3629             # incomplete or long commented code can break pre-processors
3630             if ($PREPROCESS_IMAGES) {
3631                 $_ = ((/^(\\\w+)?\{[^\\\}\<]*\}?/)? $& : '').'...' ;
3632                 $_ = '{ ... }' if ( length($_) > 100);
3633             } elsif ( length($_) > 200) {
3634                     $_ = join('',substr($_,0,200),"...\}");
3635             }
3636             s/\\(begin|end)/$1/g; s/[\000-\020]//g;
3637             $_ = join('',"% contents=",$_,"\n");
3638         }
3639         $raw_contents = '\setcounter{equation}{'.$prev_eqn_number."}\n".$raw_contents
3640             if ($env =~ /subequations/);
3642 # JCL(jcl-pag) - build the page entries for images.tex:  Each page is embraced to
3643 # let most statements have only local effect. Each page must compile into a
3644 # single dvi page to get proper image translation. Hence the invisible glue to
3645 # get *at least* one page (raw_contents alone might not wield glue), and
3646 # sufficing page length to get *exactly* one page.
3648         $latex_body .= "{\\newpage\\clearpage\n$_" .
3649 #           "$raw_contents\\hfill\\vglue1pt\\vfill}\n\n";
3650 #           "$raw_contents\\hfill\\vss}\n\n" if ($raw_contents);
3651 #           "$raw_contents\\hfill\\lthtmlcheckvsize\\clearpage}\n\n" if ($raw_contents);
3652             "$raw_contents\\lthtmlcheckvsize\\clearpage}\n\n" if ($raw_contents);
3653     }
3654     print STDOUT "\nIMAGE_CODE:{$env $id}:\n$raw_contents\n" if ($VERBOSITY > 4);
3656     # Anchor the labels and put a marker in the text;
3657     local($img) = &do_labels($fullcontents,"$image_mark#$name#");
3658     print STDOUT "\nUNDEF_OUT {$env $id}:\n$img\n" if ($VERBOSITY > 4);
3659     return($img) unless (@foot_anchors);
3661     # use the image as source to the 1st footnote, unless it is already an anchor.
3662     if ($img =~ /<\/?A>/) {
3663         join(' ', $img, @foot_anchors);         
3664     } elsif ($#foot_anchors ==0) {
3665         $foot_anchor = shift @foot_anchors;
3666         $foot_anchor =~ s/<SUP>.*<\/SUP>/$img/;
3667 #       join(' ', $foot_anchor, @foot_anchors);         
3668         $foot_anchor;
3669     } else {
3670         join(' ', $img, @foot_anchors);         
3671     }
3674 sub special_encoding { # locally sets $EXTRA_IMAGE_SCALE
3675     local($env,$_,$contents) = @_; 
3676     local($exscale) = /extrascale=([\.\d]*)/;
3677     local($EXTRA_IMAGE_SCALE) = $exscale if ($exscale);
3678     &encode(&addto_encoding($env,$contents));
3682 sub extract_eqno{
3683     local($name,$contents) = @_;
3684     if ($contents =~ /<P ALIGN="\w+">\(([^<>])\)<\/P>$/) {
3685         if (($eqno{$name})&&!($eqno{$name} eq $1)) {
3686             &write_warnings("\nequation number for $name may be wrong.")};
3687         $eqno{$name}="$1";
3688     }
3690 sub set_equation_counter{
3691     if ( $global{'eqn_number'}) {
3692         "\\setcounter{equation}{". $global{'eqn_number'} ."}\n"
3693     } else { "\\setcounter{equation}{0}\n" }
3696 # RRM: 3 different types of boxing, for image environments.
3698 #       general environments --- crops to width & height
3699 sub make_box {
3700     local($id,$contents) = @_;
3701     "\\lthtmlfigureA{". $id ."}%\n". $contents ."%\n\\lthtmlfigureZ\n";
3704 #       inline math --- horizontal mode, captures height/depth + \mathsurround
3705 sub make_hbox {
3706     local($id,$contents) = @_;
3707     if ($id =~ /indisplay/) {
3708         "\\lthtmlinlinemathA{". $id ."}%\n". $contents ."%\n\\lthtmlindisplaymathZ\n";
3709     } else {
3710         "\\lthtmlinlinemathA{". $id ."}%\n". $contents ."%\n\\lthtmlinlinemathZ\n";
3711     }
3714 #       inline text-image (e.g. accents) --- horizontal mode, captures height/depth
3715 sub make_ibox {
3716     local($id,$contents) = @_;
3717     "\\lthtmlinlineA{". $id ."}%\n". $contents ."%\n\\lthtmlinlineZ\n";
3720 #       centered images (e.g. picture environments) --- horizontal mode
3721 sub make_pbox {
3722     local($id,$contents) = @_;
3723     "\\lthtmlpictureA{". $id ."}%\n". $contents ."%\n\\lthtmlpictureZ\n";
3726 #       displayed math --- vertical mode, captures height/depth + page-width
3727 sub make_vbox {
3728     local($id,$contents) = @_;
3729     if (($HTML_VERSION >=3.2)&&($id =~/(equation|eqnarray)($|\d)/) &&! $failed ) {
3730         if ($contents =~ s/^\\setcounter\{equation\}\{\d+\}/$&%\n\\lthtmldisplayB\{$id\}%/)
3731             { $contents ."%\n\\lthtmldisplayZ\n" }
3732         else { "\\lthtmldisplayB{$id}%\n". $contents ."%\n\\lthtmldisplayZ\n" }
3733     } else { "\\lthtmldisplayA{$id}%\n". $contents ."%\n\\lthtmldisplayZ\n"}
3736 sub preprocess_images {
3737     do {
3738         print "\nWriting image.pre file ...\n";
3739         open(ENV,">.$dd${PREFIX}images.pre")
3740             || die "\nCannot write '${PREFIX}images.pre': $!\n";
3741         print ENV &make_latex($latex_body);
3742         print ENV "\n";
3743         close ENV;
3744         &copy_file($FILE, "bbl");
3745         &copy_file($FILE, "aux");
3746         local($num_cmds, $cnt, $this, @cmds);
3747         @cmds = (split ('\n', $preprocessor_cmds));
3748         $this_cmd = $num_cmds = 1+$#cmds;
3749         $cnt = $num_cmds; $preprocessor_cmds = '';
3750         while (@cmds) {
3751             $this_cmd = shift @cmds; last unless ($this_cmd);
3752             $this_cmd =~ s/.pre /.tex$cnt / if(($cnt)&&($cnt < $num_cmds));
3753             $cnt--; $this_cmd .= $cnt if ($cnt);
3754             $preprocessor_cmds .= $this_cmd."\n";
3755             L2hos->syswait($this_cmd);
3756         }
3757         # save pre-processor commands in a file:  preproc
3758         open(CMDS,">.$dd${PREFIX}preproc")
3759             || die "\nCannot write '${PREFIX}preproc': $!\n";
3760         print CMDS $preprocessor_cmds ;
3761         close CMDS;
3763     } if ((%latex_body) && ($latex_body =~ /newpage/));
3765 sub make_image_file {
3766     do {
3767         print "\nWriting image file ...\n";
3768         open(ENV,">.$dd${PREFIX}images.tex")
3769             || die "\nCannot write '${PREFIX}images.tex': $!\n";
3770         print ENV &make_latex($latex_body);
3771         print ENV "\n";
3772         close ENV;
3773         &copy_file($FILE, "bbl");
3774         &copy_file($FILE, "aux");
3775     } if ((%latex_body) && ($latex_body =~ /newpage/));
3778 sub make_latex_images{
3779     &close_dbm_database if $DJGPP;
3780     local($dd) = $dd; $dd = '/' if ($dd eq "\\"); 
3781     local($latex_call) = "$LATEX .$dd${PREFIX}images.tex";
3782     print "$latex_call\n" if (($DEBUG)||($VERBOSITY > 1));
3783     L2hos->syswait($latex_call);
3784     &open_dbm_database if $DJGPP;
3787 sub make_off_line_images {
3788     local($name, $page_num);
3789     if (!$NOLATEX && -f ".${dd}${PREFIX}images.tex") {
3790         &make_tmp_dir;  # sets  $TMPDIR  and  $DESTDIR
3791         $IMAGE_PREFIX =~ s/^_//o if ($TMPDIR);
3793         &make_latex_images();
3795         print "\nGenerating postscript images using dvips ...\n";
3796         &process_log_file(".$dd${PREFIX}images.log"); # Get eqn size info
3797         unless ($LaTeXERROR) {
3798             local($dvips_call) = 
3799                 "$DVIPS -S1 -i $DVIPSOPT -o$TMPDIR$dd${IMAGE_PREFIX} .${dd}${PREFIX}images.dvi";
3800             print "$dvips_call\n" if (($DEBUG)||($VERBOSITY > 1));
3802             &close_dbm_database if $DJGPP;
3803             L2hos->syswait($dvips_call) && print "Error: $!\n";
3804             undef $dvips_call;
3805             &open_dbm_database if $DJGPP;
3807             # add suffix .ps to the file-names for each image
3808             if(opendir(DIR, $TMPDIR || '.')) {
3809                 #  use list-context instead; thanks De-Wei Yin <yin@asc.on.ca>
3810                 my (@ALL_IMAGE_FILES) = grep /^$IMAGE_PREFIX\d+$/o, readdir(DIR);
3811                 foreach (@ALL_IMAGE_FILES) {
3812                         L2hos->Rename("$TMPDIR$dd$_", "$TMPDIR$dd$_.ps");
3813                 }
3814                 closedir(DIR);
3815             } else {
3816                 print "\nError: Cannot read dir '$TMPDIR': $!\n";
3817             }
3818         }
3819     }
3820     if ($LaTeXERROR) {
3821         print "\n\n*** LaTeXERROR\n"; return();
3822     }
3824     while ( ($name, $page_num) = each %new_id_map) {
3825         # Extract the page, convert and save it
3826         &extract_image($page_num,$orig_name_map{$page_num});
3827     }
3830 # Generate images for unknown environments, equations etc, and replace
3831 # the markers in the main text with them.
3832 # - $cached_env_img maps encoded contents to image URL's
3833 # - $id_map maps $env$id to page numbers in the generated latex file and after
3834 # the images are generated, maps page numbers to image URL's
3835 # - $page_map maps page_numbers to image URL's (temporary map);
3836 # Uses global variables $id_map and $cached_env_img,
3837 # $new_page_num and $latex_body
3840 sub make_images {
3841     local($name, $contents, $raw_contents, $uucontents, $page_num,
3842           $uucontents, %page_map, $img);
3843     # It is necessary to run LaTeX this early because we need the log file
3844     # which contains information used to determine equation alignment
3845     if ( $latex_body =~ /newpage/) {
3846         print "\n";
3847         if ($LATEX_DUMP) {
3848             # dump a pre-compiled format
3849             if (!(-f "${PREFIX}images.fmt")) {
3850                 print "$INILATEX ./${PREFIX}images.tex\n" 
3851                     if (($DEBUG)||($VERBOSITY > 1));
3852                 print "dumping ${PREFIX}images.fmt\n"
3853                     unless ( L2hos->syswait("$INILATEX ./${PREFIX}images.tex"));
3854             }
3855             local ($img_fmt) = (-f "${PREFIX}images.fmt");
3856             if ($img_fmt) {
3857                 # use the pre-compiled format
3858                 print "$TEX \"&./${PREFIX}images\" ./${PREFIX}images.tex\n"
3859                     if (($DEBUG)||($VERBOSITY > 1));
3860                 L2hos->syswait("$TEX \"&./${PREFIX}images\" ./${PREFIX}images.tex");
3861             } elsif (-f "${PREFIX}images.dvi") {
3862                 print "${PREFIX}images.fmt failed, proceeding anyway\n";
3863             } else {
3864                 print "${PREFIX}images.fmt failed, trying without it\n";
3865                 print "$LATEX ./${PREFIX}images.tex\n"
3866                     if (($DEBUG)||($VERBOSITY > 1));
3867                 L2hos->syswait("$LATEX ./${PREFIX}images.tex");
3868             }
3869         } else { &make_latex_images() }
3870 #           local($latex_call) = "$LATEX .$dd${PREFIX}images.tex";
3871 #           print "$latex_call\n" if (($DEBUG)||($VERBOSITY > 1));
3872 #           L2hos->syswait("$latex_call");
3873 ##          print "$LATEX ./${PREFIX}images.tex\n" if (($DEBUG)||($VERBOSITY > 1));
3874 ##          L2hos->syswait("$LATEX ./${PREFIX}images.tex");
3875 ##        }
3876         $LaTeXERROR = 0;
3877         &process_log_file("./${PREFIX}images.log"); # Get image size info
3878     }
3879     if ($NO_IMAGES) {
3880         my $img = "image.$IMAGE_TYPE";
3881         my $img_path = "$LATEX2HTMLDIR${dd}icons$dd$img";
3882         L2hos->Copy($img_path, ".$dd$img")
3883             if(-e $img_path && !-e $img);
3884     }
3885     elsif ((!$NOLATEX) && ($latex_body =~ /newpage/) && !($LaTeXERROR)) {
3886         print "\nGenerating postscript images using dvips ...\n";
3887         &make_tmp_dir;  # sets  $TMPDIR  and  $DESTDIR
3888         $IMAGE_PREFIX =~ s/^_//o if ($TMPDIR);
3890         local($dvips_call) = 
3891                 "$DVIPS -S1 -i $DVIPSOPT -o$TMPDIR$dd$IMAGE_PREFIX .${dd}${PREFIX}images.dvi\n";
3892         print $dvips_call if (($DEBUG)||($VERBOSITY > 1));
3893         
3894         if ((($PREFIX=~/\./)||($TMPDIR=~/\./)) && not($DVIPS_SAFE)) {
3895             print " *** There is a '.' in $TMPDIR or $PREFIX filename;\n"
3896                 . "  dvips  will fail, so image-generation is aborted ***\n";
3897         } else {
3898             &close_dbm_database if $DJGPP;
3899             L2hos->syswait($dvips_call) && print "Error: $!\n";
3900             &open_dbm_database if $DJGPP;
3901         }
3903         # append .ps suffix to the filenames
3904         if(opendir(DIR, $TMPDIR || '.')) {
3905             # use list-context instead; thanks De-Wei Yin <yin@asc.on.ca>
3906             my @ALL_IMAGE_FILES = grep /^$IMAGE_PREFIX\d+$/o, readdir(DIR);
3907             foreach (@ALL_IMAGE_FILES) {
3908                 L2hos->Rename("$TMPDIR$dd$_", "$TMPDIR$dd$_.ps");
3909             }
3910             closedir(DIR);
3911         } else {
3912             print "\nError: Cannot read dir '$TMPDIR': $!\n";
3913         }
3914     }
3915     do {print "\n\n*** LaTeXERROR"; return()} if ($LaTeXERROR);
3916     return() if ($LaTeXERROR); # empty .dvi file
3917     L2hos->Unlink(".$dd${PREFIX}images.dvi") unless $DEBUG;
3919     print "\n *** updating image cache\n" if ($VERBOSITY > 1);
3920     while ( ($uucontents, $_) = each %cached_env_img) {
3921         delete $cached_env_img{$uucontents}
3922             if ((/$PREFIX$img_rx\.$IMAGE_TYPE/o)&&!($DESTDIR&&$NO_SUBDIR));
3923         $cached_env_img{$uucontents} = $_
3924             if (s/$PREFIX$img_rx\.new/$PREFIX$1.$IMAGE_TYPE/go);
3925     }
3926     print "\n *** removing unnecessary images ***\n" if ($VERBOSITY > 1);
3927     while ( ($name, $page_num) = each %id_map) {
3928         $contents = $latex_body{$name};
3929         if ($page_num =~ /^\d+\#\d+$/) { # If it is a page number
3930             do {                # Extract the page, convert and save it
3931                 $img = &extract_image($page_num,$orig_name_map{$page_num});
3932                 if ($contents =~ /$htmlimage_rx/) {
3933                     $uucontents = &special_encoding($env,$2,$contents);
3934                 } elsif ($contents =~ /$htmlimage_pr_rx/) {
3935                     $uucontents = &special_encoding($env,$2,$contents);
3936                 } else {
3937                     $uucontents = &encode(&addto_encoding($contents,$contents));
3938                 }
3939                 if (($HTML_VERSION >=3.2)||!($contents=~/$order_sensitive_rx/)){
3940                     $cached_env_img{$uucontents} = $img;
3941                 } else {
3942                     # Blow it away so it is not saved for next time
3943                     delete $cached_env_img{$uucontents};
3944                     print "\nimage $name not recycled, contents may change (e.g. numbering)";
3945                 }
3946                 $page_map{$page_num} = $img;
3947             } unless ($img = $page_map{$page_num}); # unless we've just done it
3948             $id_map{$name} = $img;
3949         } else {
3950             $img = $page_num;   # it is already available from previous runs
3951         }
3952         print STDOUT " *** image done ***\n" if ($VERBOSITY > 2);
3953     }
3954     &write_warnings(
3955                     "\nOne of the images is more than one page long.\n".
3956                     "This may cause the rest of the images to get out of sync.\n\n")
3957         if (-f sprintf("%s%.3d%s", $IMAGE_PREFIX, ++$new_page_num, ".ps"));
3958     print "\n *** no more images ***\n"  if ($VERBOSITY > 1);
3959     # MRO: The following cleanup seems to be incorrect: The DBM is
3960     # still open at this stage, this causes a lot of unlink errors
3961     #
3962     #do { &cleanup; print "\n *** clean ***\n"  if ($VERBOSITY > 1);}
3963     #   unless $DJGPP;
3966 # MRO: This copies the navigation icons from the distribution directory
3967 # or an alternative specified in $ALTERNATIVE_ICONS
3968 # to the document directory.
3970 sub copy_icons {
3971     local($icon,$_);
3972     print "\nCopying navigation icons ...";
3973     foreach (keys %used_icons) {
3974         # each entry ends in gif or png
3975         if ($ALTERNATIVE_ICONS) {
3976             L2hos->Copy("$ALTERNATIVE_ICONS$dd$_", ".$dd$_")
3977                 if (-e "$ALTERNATIVE_ICONS$dd$_" && !-e $_);
3978         } elsif (/(gif|png)$/) {
3979             L2hos->Copy("$LATEX2HTMLDIR${dd}icons$dd$_", ".$dd$_")
3980                 if (-e "$LATEX2HTMLDIR${dd}icons$dd$_" && !-e $_);
3981         }
3982     }
3985 sub process_log_file {
3986     local($logfile) = @_;
3987     local($name,$before,$lengthsfound);
3988     local($TeXpt)= 72/72.27;
3989     local($image_counter);
3990     open(LOG, "<$logfile") || die "\nCannot read logfile '$logfile': $!\n";
3991     while (<LOG>) {
3992         if (/Overfull/) { $before .= $_ }
3993         elsif (/latex2htmlLength ([a-zA-Z]+)=(\-?[\d\.]+)pt/) {
3994             ${$1} = 0.0+$2; $lengthsfound = 1;
3995         } elsif (/latex2htmlSize|l2hSize/) {
3996             /:([^:]*):/;
3997             $name = $1; $name =~ s/\*//g;
3998             ++$image_counter;
3999             s/:([0-9.]*)pt/$height{$name} = $1*$TeXpt;''/e;
4000             s/::([0-9.]*)pt/$depth{$name} = $1*$TeXpt;''/e;
4001             s/::([0-9.]*)pt/$width{$name} = $1*$TeXpt;''/e;
4002             s/\((.*)\)/$eqno{$name} = 1+$1;''/e;
4003             if ($before) {
4004                 local($tmp);
4005                 if ($before =~ /hbox\s*\((\d+\.?\d*)pt/) {
4006                     $width{$name} = $width{$name}+$1*$TeXpt;
4007                 }
4008                 if ($before =~ /vbox\s*\((\d+\.?\d*)pt/) {
4009                     $height{$name} = $height{$name}+$1*$TeXpt;
4010                 }
4011                 $before = '';
4012             }
4013         }
4014     $LaTeXERROR = 1 if (/^No pages of output./);
4015     }
4017     if ($LaTeXERROR) {
4018         print STDERR "\n\n *** LaTeX produced no output ***\n"
4019             . " *** no new images can be created\n"
4020             . " *** Examine the  images.log  file.\n\n";
4021         return;
4022     }
4023     print STDOUT "\n *** processing $image_counter images ***\n";
4024     print STDOUT "\n *** LATEX LOG OK. ***\n" if ($VERBOSITY > 1);
4026     if ($lengthsfound) {
4027         $ODD_HMARGIN  = $hoffset + $oddsidemargin;
4028         $EVEN_HMARGIN = $hoffset + $evensidemargin;
4029         $VMARGIN = $voffset + $topmargin + $headheight + $headsep;
4030         if ($dvi_mag >0 && $dvi_mag != 1000) {
4031             $ODD_HMARGIN = int($dvi_mag /1000 * $ODD_HMARGIN);
4032             $EVEN_HMARGIN = int($dvi_mag /1000 * $EVEN_HMARGIN);
4033             $VMARGIN = int($dvi_mag /1000 * $VMARGIN);
4034         }
4035     } else {
4036         $ODD_HMARGIN = 0;
4037         $EVEN_HMARGIN = 0;
4038         $VMARGIN = 0;
4039     }
4040     $ODD_HMARGIN  = int($ODD_HMARGIN*$TeXpt  + 72.5);
4041     $EVEN_HMARGIN = int($EVEN_HMARGIN*$TeXpt + 72.5);
4042     $VMARGIN = int($VMARGIN*$TeXpt + 72.5);
4043     close(LOG);
4046 sub extract_image { # clean
4047     my ($page_num,$name) = @_;
4049     # The followin come out of %img_params
4050     my ($scale, $external, $thumbnail, $map, $psimage, $align, $usemap,
4051           $flip, $aalias, $trans, $exscale, $alt, $exstr);
4053     my ($lwidth, $val) = (0, '');
4054     my ($custom_size,$color_depth,$height,$width,$croparg);
4056     print STDOUT "\nextracting $name as $page_num\n" if ($VERBOSITY > 1);
4057     # $global_num identifies this image in the original source file
4058     # $new_num identifies this image in images.tex
4059     my ($global_num, $new_num) = split(/#/, $page_num);
4060     $name =~ s/\*/star/;
4061     my ($env,$basename,$img) = ($name,"img$global_num",'');
4062     $env =~ s/\d+$//;
4063     $psname = sprintf("%s%.3d", "$TMPDIR$dd$IMAGE_PREFIX", $new_num);
4064     if ( $EXTERNAL_IMAGES && $PS_IMAGES ) {
4065         $img =  "$basename.ps";
4066         L2hos->Copy("$psname.ps", "${PREFIX}$img");
4067     } else {
4068         $img = "$basename.$IMAGE_TYPE";
4069         ($scale, $external, $thumbnail, $map, $psimage, $align, $usemap, 
4070             $flip, $aalias, $trans, $exscale, $alt, $exstr) =
4071             split('#', $img_params{$name});
4072         $lwidth = ($align =~ s/nojustify/middle/) ? 0 : $LINE_WIDTH;
4073         $alt = "ALT=\"$name\"" unless $alt;
4074         $exscale = $EXTRA_IMAGE_SCALE unless($exscale);
4075         if ($NO_IMAGES) {
4076             L2hos->Symlink("image.$IMAGE_TYPE", "${PREFIX}$img");
4077             if ($thumbnail) {
4078                 L2hos->Symlink("image.$IMAGE_TYPE", "${PREFIX}T$img");
4079                 $thumbnail = "${PREFIX}T$img";
4080             }
4081         } else {
4082             # RRM: deal with size data
4083             if ($width{$name} < 0) {
4084                 if ($exscale && $PK_GENERATION) {
4085                     $height = int(                              
4086                         $exscale*$height{$name}+        
4087                         $exscale*$depth{$name} +.5);
4088                     $width = int($exscale*$width{$name}-.5);
4089                 } else {
4090                     $height = int($height{$name}+$depth{$name}+.5);
4091                     $width = int($width{$name}-.5);
4092                 }
4093                 $custom_size = "${width}x$height";
4094             } elsif ($width{$name}) {
4095                 if ($exscale && $PK_GENERATION) {
4096                     $height = int( $height{$name} * $exscale +
4097                         $depth{$name} * $exscale +.5);
4098                     $width = int($width{$name} * $exscale +.5);
4099                 } else {
4100                     $height = int($height{$name}+$depth{$name}+.5);
4101                     $width = int($width{$name}+.5);
4102                 }
4103                 $custom_size = "${width}x$height";
4104             } else {
4105                 $custom_size = '';
4106             }
4107             # MRO: add first overall crop
4108             $croparg = '-crop a' . ($crop{$name} || '') . ' ';
4109             $page_num  =~ s/^\d+#//o;
4110             $custom_size .= " -margins "
4111                 . (($page_num % 2) ? $ODD_HMARGIN:$EVEN_HMARGIN)
4112                 . ",$VMARGIN" if ($custom_size);
4114             #RRM: \special commands may place ink outside the expected bounds:
4115             $custom_size = '' if ($tex_specials{$name});
4117             # MRO: Patches for image conversion with pstoimg
4118             # RRM: ...with modifications and fixes
4119             L2hos->Unlink("${PREFIX}$img");
4120             &close_dbm_database if $DJGPP;
4121             print "Converting image #$new_num\n";
4123             if ( ($name =~ /figure/) || $psimage || $scale || $thumbnail) {
4124                 $scale = $FIGURE_SCALE_FACTOR unless ($scale);
4125                 print "\nFIGURE: $name scaled $scale  $aalias\n" if ($VERBOSITY > 2);
4126                 (L2hos->syswait( "$PSTOIMG -type $IMAGE_TYPE "
4127                 . ($DEBUG ? '-debug ' : '-quiet ' )
4128                 . ($TMPDIR ? "-tmp $TMPDIR " : '' )
4129                 . (($DISCARD_PS && !$thumbnail && !$psimage)? "-discard " :'')
4130                 . (($INTERLACE) ? "-interlace " : '' )
4131                 . (((($ANTI_ALIAS)||($aalias))&&($aalias !~ /no|text/))? "-antialias ":'')
4132                 . (($ANTI_ALIAS_TEXT||(($aalias =~/text/)&&($aalias !~/no/)))?
4133                         "-aaliastext ":'') 
4134                 . (($custom_size) ? "-geometry $custom_size ": '' )
4135                 . $croparg
4136                 . ($color_depth || '')
4137                 . (($flip) ? "-flip $flip " : '' )
4138                 . (($scale > 0) ? "-scale $scale " : '' )
4139                 . (((($TRANSPARENT_FIGURES && ($env =~ /figure/o))||($trans))
4140                      &&(!($trans =~ /no/))) ? "-transparent " : '')
4141                 . (($WHITE_BACKGROUND) ? "-white " : '' )
4142                 . "-out ${PREFIX}$img $psname.ps"
4143                 ) ) # ||!(print "\nWriting image: ${PREFIX}$img"))
4144                     && print "\nError while converting image: $!\n";
4146                 if ($thumbnail) { # $thumbnail contains the reduction factor
4147                     L2hos->Unlink("${PREFIX}T$img");
4148                     print "\nIMAGE thumbnail: $name" if ($VERBOSITY > 2);
4149                     (L2hos->syswait( "$PSTOIMG -type $IMAGE_TYPE "
4150                     . ($DEBUG ? '-debug ' : '-quiet ' )
4151                     . ($TMPDIR ? "-tmp $TMPDIR " : '' )
4152                     . (($DISCARD_PS && !$psimage) ? "-discard " : '' )
4153                     . (($INTERLACE) ? "-interlace " : '' )
4154                     . ((($ANTI_ALIAS||($aalias))&&(!($aalias =~/no/)))? "-antialias " :'')
4155                     . (($ANTI_ALIAS_TEXT||(($aalias =~/text/)&&($aalias !~/no/)))?
4156                         "-aaliastext ":'') 
4157                     . (($custom_size) ? "-geometry $custom_size " : '' )
4158                     . ($color_depth || '')
4159                     . (($flip) ? "-flip $flip " : '' )
4160                     . (($thumbnail > 0) ? "-scale $thumbnail " : '' )
4161                     . ((($trans)&&(!($trans =~ /no/))) ? "-transparent " : '')
4162                     . (($WHITE_BACKGROUND) ? "-white " : '' )
4163                     . "-out ${PREFIX}T$img $psname.ps"
4164                     ) ) # ||!(print "\nWriting image: ${PREFIX}T$img"))
4165                         && print "\nError while converting thumbnail: $!\n";
4166                     $thumbnail = "${PREFIX}T$img";
4167                 }
4168             } elsif (($exscale &&(!$PK_GENERATION))&&($width{$name})) {
4169                 my $under = '';
4170                 my $mathscale = ($MATH_SCALE_FACTOR > 0) ? $MATH_SCALE_FACTOR : 1;
4171                 if (($DISP_SCALE_FACTOR > 0) &&
4172                     ( $name =~ /equation|eqnarray|display/))
4173                         { $mathscale *= $DISP_SCALE_FACTOR; };
4174                 if ($scale) {
4175                     $scale *= $exscale if ($name =~ /makeimage|tab/);
4176                 } else {
4177                     $scale = $mathscale*$exscale;
4178                     $under = "d" if (($name =~/inline|indisplay/)&&($depth{$name}));
4179                 }
4180                 print "\nIMAGE: $name  scaled by $scale \n" if ($VERBOSITY > 2);
4181                 (L2hos->syswait( "$PSTOIMG -type $IMAGE_TYPE "
4182                 . ($DEBUG ? '-debug ' : '-quiet ' )
4183                 . ($TMPDIR ? "-tmp $TMPDIR " : '' )
4184                 . (($DISCARD_PS)? "-discard " : '' )
4185                 . (($INTERLACE)? "-interlace " : '' )
4186                 . ((($ANTI_ALIAS_TEXT||($aalias))&&($aalias !=~/no/))? 
4187                     "-antialias -depth 1 " :'')
4188                 . (($custom_size)? "-geometry $custom_size " : '' )
4189                 . $croparg
4190                 . (($scale != 1)? "-scale $scale " : '' )
4191                 . ((($exscale)&&($exscale != 1)&&
4192                     !($ANTI_ALIAS_TEXT &&($LATEX_COLOR)))? 
4193                         "-shoreup $exscale$under " :'')
4194                 . ((($TRANSPARENT_FIGURES ||($trans))
4195                      &&(!($trans =~ /no/)))? "-transparent " : '')
4196                 . (($WHITE_BACKGROUND && !$TRANSPARENT_FIGURES) ? "-white " : '' )
4197                 . "-out ${PREFIX}$img $psname.ps"
4198                 ) ) # ||!(print "\nWriting image: ${PREFIX}$img"))
4199                     && print "\nError while converting image: $!\n";
4200             } else {
4201                 print "\nIMAGE: $name\n" if ($VERBOSITY > 2);
4202                 my $under = '';
4203                 my $mathscale = ($MATH_SCALE_FACTOR > 0) ? $MATH_SCALE_FACTOR : 1;
4204                 if (($DISP_SCALE_FACTOR > 0) &&
4205                     ( $name =~ /equation|eqnarray|display/))
4206                         { $mathscale *= $DISP_SCALE_FACTOR; };
4207                 if (($scale)&&($exscale)) {
4208                     $scale *= $exscale if ($name =~ /makeimage|tab/);
4209                 } elsif ($scale) {
4210                 } elsif (($mathscale)&&($exscale)) {
4211                     $scale = $mathscale*$exscale;
4212                     $under = "d" if (($name =~/inline|indisplay/)&&($depth{$name}));
4213                 } elsif ($mathscale) { $scale = $mathscale; }
4215                 (L2hos->syswait("$PSTOIMG -type $IMAGE_TYPE "
4216                 . ($DEBUG ? '-debug ' : '-quiet ' )
4217                 . ($TMPDIR ? "-tmp $TMPDIR " : '' )
4218                 . (($DISCARD_PS) ? "-discard " : '' )
4219                 . (($INTERLACE) ? "-interlace " : '' )
4220                 . ((($ANTI_ALIAS_TEXT||($aalias))&&(!($aalias =~ /no/)))?
4221                     "-antialias -depth 1 " :'')
4222                 . ((($exscale)&&($exscale != 1)&&
4223                     !($ANTI_ALIAS_TEXT &&($LATEX_COLOR)))? 
4224                         "-shoreup $exscale " :'')
4225                 . (($scale ne 1) ? "-scale $scale " : '' )
4226                 . (($custom_size) ? "-geometry $custom_size " : '' )
4227                 . $croparg
4228 #               .  (($name =~ /(equation|eqnarray)/) ? "-rightjustify $lwidth " : '')
4229 #               .  (($name =~ /displaymath/) ? "-center $lwidth " : '')
4230                 . (($name =~ /inline|indisplay/ && (!($custom_size))&&$depth{$name}!= 0) ?
4231                     do {$val=($height{$name}-$depth{$name})/($height{$name}+$depth{$name});
4232                         "-topjustify x$val "} : '')
4233                 . ((($TRANSPARENT_FIGURES||($trans))
4234                     &&(!($trans =~ /no/))) ? "-transparent " : '')
4235                 . (($WHITE_BACKGROUND && !$TRANSPARENT_FIGURES) ? "-white " : '' )
4236                 . "-out ${PREFIX}$img $psname.ps")
4237                 ) #|| !(print "\nWriting image: ${PREFIX}$img"))
4238                     && print "\nError while converting image\n";
4239             }
4240             if (! -r "${PREFIX}$img") {
4241                 &write_warnings("\nFailed to convert image $psname.ps")
4242             } else { } #L2hos->Unlink("$psname.ps") unless $DEBUG }
4243             &open_dbm_database if $DJGPP;
4244         }
4245     }
4246     print "\nextracted $name as $page_num\n" if ($VERBOSITY > 1);
4247     &embed_image("${PREFIX}$img", $name, $external, $alt, $thumbnail, $map,
4248         $align, $usemap, $exscale, $exstr);
4251 sub extract_parameters {
4252     local($contents) = @_;
4253     local($_, $scale, $external, $thumbnail, $map, $psimage, $align,
4254           $usemap, $flip, $aalias, $trans, $pagecolor, $alt, $exscale,
4255           $cdepth, $htmlparams);
4257     #remove the \htmlimage commands and arguments before...
4258     $contents =~ s/$htmlimage_rx/$_ = $2;''/ego;
4259     $contents =~ s/$htmlimage_pr_rx/$_ .= $2;''/ego;
4261     # code adapted from original idea by Stephen Gildea:
4262     # If the document specifies the ALT tag explicitly
4263     # with \htmlimage{alt=some text} then use it.
4264     s!alt=([^,]+)!$alt = $1;
4265         $alt =~ s/^\s+|\s+$//g; $alt =~ s/"//g;
4266         $alt="ALT=\"$alt\"";
4267     ''!ie;
4269   if (!$alt) {
4270     #...catching all the code for the ALT text.
4271     local($keep_gt)=1;
4272     $alt = &flatten_math($contents); undef $keep_gt;
4273     #RRM: too long strings upset the DBM. Truncate to <= 165 chars.
4274     if ( length($alt) > 163 ) {
4275         local($start,$end);
4276         $start = substr($alt,0,80);
4277         $end = substr($alt,length($alt)-80,80);
4278         $alt = join('',$start,"...\n ...",$end);
4279     }
4280     s/ALT\s*=\"([\w\W]*)\"/$alt=$1;''/ie;
4281     if ($alt) {
4282         if ($alt =~ /\#/) {
4283             $alt =~ s/^(\\vbox\{)?\#[A-Za-z]*\s*//;
4284             $alt =~ s/\n?\#[A-Za-z]*\s*\}?$//s;
4285             if ($alt =~ /\#/) { $alt = $` . " ... " };
4286         }
4287         $alt =~ s/\`\`/\\lq\\lq /g; $alt =~ s/\`/\\lq /g;
4288         $alt =~ s/(^\s*|\s*$)//mg;
4289         $alt = "ALT=\"$alt\"" if ($alt);
4290     } else { $alt = 'ALT="image"' }
4291   }
4293     $psimage++ if ($contents =~ /\.ps/);
4294 #    $contents =~ s/\s//g;      # Remove spaces   Why ?
4295     s/extrascale=([\.\d]*)/$exscale=$1;''/ie;
4296     s/\bscale=([\.\d]*)/$scale=$1;''/ie;
4297     s/(^|,\s*)external/$external=1;''/ie;
4298     s/(^|,\s*)((no)?_?anti)alias(_?(text))?/$aalias = $2.$4;''/ie;
4299     s/(^|,\s*)((no)?_?trans)parent/$trans = $2;''/ie;
4300     s/thumbnail=([\.\d]*)/$thumbnail=$1;''/ie;
4301     s/usemap=([^\s,]+)/$usemap=$1;''/ie;
4302     s/map=([^\s,]+)/;$map=$1;''/ie;
4303     s/align=([^\s,]+)/$align=$1;''/ie;
4304     s/flip=([^\s,]+)/$flip=$1;''/ie;
4305     s/color_?(depth)?=([^\s,]+)/$cdepth=$2;''/ie;
4306     ($scale,$external,$thumbnail,$map,$psimage,$align
4307      ,$usemap,$flip,$aalias,$trans,$exscale,$alt,$_);
4311 # RRM: Put the raw \TeX code into the ALT tag
4312 # replacing artificial environments and awkward characters
4313 sub flatten_math {
4314     local ($_) = @_;
4315     $_ = &revert_to_raw_tex($_);
4316     s/[ \t]+/ /g;
4317     # MRO: replaced $* with /m
4318     s/$tex2html_wrap_rx//gm;
4319     s/(\\begin\s*\{[^\}]*\})(\s*(\[[^]]*\]))?[ \t]*/$1$3/gm;
4320     s/(\\end\{[^\}]*\})\n?/$1/gm;
4321     s/>(\w)?/($1)?"\\gt $1":"\\gt"/eg unless ($keep_gt); # replace > by \gt
4322     s/\\\|(\w)?/($1)?"\\Vert $1":"\\Vert"/eg;   # replace \| by \Vert
4323     s/\|(\w)?/($1)?"\\vert $1":"\\vert"/eg;     # replace | by \vert
4324     s/\\\\/\\\\ /g;     # insert space after \\ 
4325     s/\\"/\\uml /g;     # screen umlaut accents...
4326     s/"/\'\'/g;         # replace " by ''
4327     s/\\\#/\\char93 /g; # replace \# by \char93 else caching fails
4328 #    s/"(\w)?/($1)?"\\rq\\rq $1":"\'\'"/eg;     # replace " by \rq\rq
4329 #    s/\&\\uml /\\\"/g; # ...reinstate umlauts
4330     $_;
4333 sub scaled_image_size {
4334     local($exscale,$_) = @_;
4335     local($width,$height) = ('','');
4336     /WIDTH=\"?(\d*)\"?\s*HEIGHT=\"?(\d*)\"?$/o;
4337     $width=int($1/$exscale + .5);
4338     $height=int($2/$exscale + .5);
4339     "WIDTH=\"$width\" HEIGHT=\"$height\""
4342 sub process_in_latex {
4343     # This is just a wrapper for process_undefined_environment.
4344     # @[0] = contents
4345     $global{'max_id'}++;
4346     &process_undefined_environment('tex2html_wrap',$global{'max_id'},$_[0]);
4349 # MRO: cp deprecated, replaced by L2hos->Copy
4351 # Marcus Hennecke  6/3/96
4352 # MRO: test for existance
4353 sub copy_file {
4354     local($file, $ext) = @_;
4355     $file =  &fulltexpath("$FILE.$ext");
4356     if(-r $file) {
4357         print "\nNote: Copying '$file' for image generation\n"
4358             if($VERBOSITY > 2);
4359         L2hos->Copy($file, ".$dd${PREFIX}images.$ext");
4360     }
4363 sub rename_image_files {
4364     local($_, $old_name, $prefix);
4365     if ($PREFIX) {
4366         foreach (<${PREFIX}*img*.$IMAGE_TYPE>) {
4367             $old_name = $_;
4368             s/\.$IMAGE_TYPE$/\.old/o;
4369             L2hos->Rename($old_name, $_);
4370             }
4371         }
4372     else {
4373         foreach (<img*.$IMAGE_TYPE>) {
4374             $old_name = $_;
4375             s/\.$IMAGE_TYPE$/\.old/o;
4376             L2hos->Rename($old_name, $_);
4377         }
4378         foreach (<Timg*.$IMAGE_TYPE>) {
4379             $old_name = $_;
4380             s/\.$IMAGE_TYPE$/\.old/o;
4381             L2hos->Rename($old_name, $_);
4382         }
4383     }
4387 ############################ Processing Commands ##########################
4389 sub ignore_translate_commands {
4390     local ($_) = @_;
4391 #   print "\nTranslating commands ...";
4393     local(@processedC);
4394     &replace_strange_accents;
4395     local($before, $contents, $br_id, $after, $pattern, $end_cmd_rx);
4396     s/$begin_cmd_rx/&replace_macro_expansion($`, $1, $&, $')/eg;
4399 sub replace_macro_expansion {
4400     push(@processedC,$_[1]);
4401     $end_cmd_rx = &make_end_cmd_rx($_[2]);
4402     $pattern = $_[3];
4403     $_ = join('',$_[3],$_[4]);
4404     $after = $_[4];
4405     if (($before)&&(!($before =~ /$begin_cmd_rx/))) {
4406         push(@processedC,$before);
4407             $_ = join('',$pattern,$after); $before = '';
4408         }
4409         local($end_cmd_rx) = &make_end_cmd_rx($br_id);
4410     
4413 sub translate_aux_commands {
4414     s/^(.*)$/&translate_commands($1)/s;
4417 sub translate_commands {
4418     local ($_) = @_;
4419 #   print "\nTranslating commands ...";
4421     local(@processedC);
4422     &replace_strange_accents;
4423     for (;;) {                  # For each opening bracket ...
4424         last unless ($_ =~ /$begin_cmd_rx/);
4425         local($before, $contents, $br_id, $after, $pattern);
4426         ($before, $br_id, $after, $pattern) = ($`, $1, $', $&);
4427         if (($before)&&(!($before =~ /$begin_cmd_rx/))) {
4428             push(@processedC,$before);
4429             $_ = join('',$pattern,$after); $before = '';
4430         }
4431         local($end_cmd_rx) = &make_end_cmd_rx($br_id);
4432         if ($after =~ /$end_cmd_rx/) { # ... find the the matching closing one
4433             $NESTING_LEVEL++;
4434             ($contents, $after) = ($`, $');
4435             do {
4436                 local(@save_open_tags) = @$open_tags_R;
4437                 local($open_tags_R) = [ @save_open_tags ];
4438                 print STDOUT "\nIN::{$br_id}" if ($VERBOSITY > 4);
4439                 print STDOUT "\n:$contents\n" if ($VERBOSITY > 7);
4440                 undef $_;
4441                 $contents = &translate_commands($contents)
4442                     if ($contents =~ /$match_br_rx/o);
4443                 # Modifies $contents
4444                 &process_command($single_cmd_rx,$contents)
4445                     if ($contents =~ /\\/o);
4447                 $contents .= &balance_tags();
4448             };
4450             print STDOUT "\nOUT: {$br_id}" if ($VERBOSITY > 4);
4451             print STDOUT "\n:$contents\n" if ($VERBOSITY > 7);
4452             # THIS MARKS THE OPEN-CLOSE DELIMITERS AS PROCESSED
4453             $_ = join("", $before,"$OP$br_id$CP", $contents,"$OP$br_id$CP", $after);
4454             $NESTING_LEVEL--;
4455         }
4456         else {
4457             $pattern = &escape_rx_chars($pattern);
4458             s/$pattern//;
4459             print "\nCannot find matching bracket for $br_id" unless $AUX_FILE;
4460         }
4461         last unless ($_ =~ /$begin_cmd_rx/o);
4462     }
4463     $_ = join('',@processedC) . $_;
4464     # Now do any top level commands that are not inside any brackets
4465     # MODIFIES $_
4466     print $_ if ($VERBOSITY > 8);
4467     &process_command($single_cmd_rx,$_);
4470 #RRM: based on earlier work of Marcus Hennecke
4471 # makes sure the $open_tags_R at the end of an environment
4472 # is the same as @save_open_tags from the start,
4473 # ensuring that the HTML page indeed has balanced tags
4474 sub balance_tags {
4475     local($tag_cmd, $tags, $save_tags, $open_tags, @reopen_tags);
4476     $save_tags = join(',',@save_open_tags) if (@save_open_tags);
4477     $open_tags = join(',',@$open_tags_R) if (@$open_tags_R);
4478     if ($open_tags eq $save_tags) { return(); }
4479     if ($save_tags =~ s/^$open_tags//) {
4480         @reopen_tags = split (',',$');
4481     } else {
4482         @reopen_tags = @save_open_tags;
4483         while (@$open_tags_R) {
4484             $tag_cmd = pop (@$open_tags_R);
4485             print STDOUT "\n</$tag_cmd>" if $VERBOSITY > 2;
4486             $declarations{$tag_cmd} =~ m|</.*$|;
4487             $tags .= $& unless ($` =~ /^<>$/);
4488             $open_tags = join(',',@$open_tags_R) if (@$open_tags_R);
4489             last if ( $save_tags =~ s/^$open_tags/
4490                      @reopen_tags = split (',',$');''/e);
4491         }
4492     }
4493     while (@reopen_tags) {
4494         $tag_cmd = shift @reopen_tags;
4495         if ($tag_cmd) {
4496             push (@$open_tags_R, $tag_cmd) if ($tag_cmd);
4497             print STDOUT "\n<$tag_cmd>" if $VERBOSITY > 2;
4498             $declarations{$tag_cmd} =~ m|</.*$|;
4499             $tags .= $` unless ($` =~ /^<>$/);
4500         }
4501     }
4502     $tags;
4505 sub close_all_tags {
4506     return() if (!@$open_tags_R);
4507     local($tags,$tag_cmd);
4508     while (@$open_tags_R) {
4509         $tag_cmd = pop (@$open_tags_R);
4510         print STDOUT "\n</$tag_cmd>" if $VERBOSITY > 2;
4511         $declarations{$tag_cmd} =~ m|</.*$|;
4512         $tags .= $& unless ($` =~ /^<>$/);
4513     }
4514     $tags;
4517 sub preserve_open_tags {
4518     local(@save_open_tags) = @$open_tags_R;
4519     local($open_tags_R) = [ @save_open_tags ];
4520     # provides the markup to close and reopen the current tags
4521     (&close_all_tags(), &balance_tags());
4524 sub preserve_open_block_tags {
4525     local($tag_cmd,$tags_open,$tags_close,$pre,$post,@tags);
4526     while (@$open_tags_R) {
4527         $tag_cmd = pop (@$open_tags_R);
4528         print STDOUT "\n</$tag_cmd>" if $VERBOSITY > 2;
4529         $declarations{$tag_cmd} =~ m|</.*$|;
4530         ($pre,$post) = ($`,$&);
4531         if ($post =~ /$block_close_rx/) {
4532             # put it back and exit
4533             push(@$open_tags_R,$tag_cmd);
4534             last;
4535         } else {
4536             # leave it closed, collecting tags for it
4537             $tags_close .= $post;
4538             $tags_open = $pre . $tags_open;
4539             unshift(@tags,$tag_cmd);
4540         }
4541     }
4542     ($tags_close , $tags_open, @tags);  
4545 sub minimize_open_tags {
4546     local($this_tag, $close_only) = @_;
4547     local($pre,$post,$decl);
4548     $decl = $declarations{$this_tag};
4549     if ($decl) {
4550     # if it is a declaration, get the corresponding tags...
4551         $decl =~ m|</.*$|;
4552         ($pre,$post) = ($`,$&) unless ($` =~ /^<>$/);
4553         if (!@$open_tags_R) { # when nothing else is open...
4554             # pushing the style, when appropriate
4555             push (@$open_tags_R, $this_tag)
4556                 unless ($close_only ||($post =~ /$block_close_rx/));
4557             print STDOUT "\n<$this_tag>" if $VERBOSITY > 2;
4558             # and return the tags
4559             return($pre,$post) unless ($USING_STYLES);
4560             local($env_id) = '' if ($env_id =~/^\w+$/);
4561             $pre =~ s/>$/ $env_id>/ if ($env_id);
4562             return($pre,$post);
4563         }
4564     } else { # ...else record the argument as $pre
4565         $pre = $this_tag unless $close_only;
4566     }
4567     local($env_id) = '' if ($env_id =~/^\w+$/);
4568     $pre =~ s/>$/ ID="$env_id">/ if ($USING_STYLES &&($env_id));
4570     # return the tags, if nothing is already open
4571     if (!@$open_tags_R) { 
4572         return($pre,$post);
4573     }
4574 #    elsif ($close_only) { push (@$open_tags_R, $this_tag) }
4576     local($tags,$tag_cmd,$tag_open);
4577     local($closures,$reopens,@tags);
4578     local($tag_close,$tag_open);
4579     local($size_cmd,$size_open);
4580     local($font_cmd,$font_open);
4581     local($fontwt_cmd,$fontwt_open);
4582     local($color_cmd,$color_open);
4583      if ($decl) {
4584         if ($this_tag =~ /$sizechange_rx/) { 
4585             $size_cmd = $this_tag;
4586         } else {
4587             if ($this_tag =~ /$fontchange_rx/) { 
4588                 $font_cmd = $this_tag }
4589             if ($this_tag =~ /$fontweight_rx/) { 
4590                 $fontwt_cmd = $this_tag }
4591         }
4592     }
4593     while (@$open_tags_R) {
4594         ($tag_close,$tag_open) = ('','');
4595         $tag_cmd = pop (@$open_tags_R);
4596         print STDOUT "\n</$tag_cmd>" if $VERBOSITY > 2;
4597         $declarations{$tag_cmd} =~ m|</.*$|;
4598         ($tag_close,$tag_open) = ($&,$`) unless ($` =~ /<>/);
4599         $closures .= $tag_close;
4601         if ((!$size_cmd)&&($tag_cmd =~ /$sizechange_rx/)) {
4602             $size_cmd = $tag_cmd;
4603             $size_open = $tag_open;
4604         }
4605         elsif ((!$font_cmd)&&($tag_cmd =~ /$fontchange_rx/)) {
4606             $font_cmd = $tag_cmd;
4607             $font_open = $tag_open;
4608         }
4609         elsif ((!$fontwt_cmd)&&($tag_cmd =~ /$fontweight_rx/)) {
4610             $fontwt_cmd = $tag_cmd;
4611             $fontwt_open = $tag_open;
4612         }
4613         elsif ((!$color_cmd)&&($tag_cmd =~ /$colorchange_rx/)) {
4614             $color_cmd = $tag_cmd;
4615             $color_open = $tag_open;
4616         } 
4617         elsif ($tag_cmd =~ 
4618              /$sizechange_rx|$fontchange_rx|$fontweight_rx|$colorchange_rx/) {
4619         } else {
4620             unshift (@tags, $tag_cmd);
4621             print STDOUT "\n<<$tag_cmd>" if $VERBOSITY > 2;
4622             $reopens = $tag_open . $reopens;
4623         }
4624     }
4625     if ($USING_STYLES) {
4626         local($TAG) = "DIV";
4627         if ($pre =~ /^<(DIV|SPAN|PRE)/) { $TAG = $1 };
4628         if (($pre =~ /^<$TAG/)&&($env_id =~ /^\s+(CLASS|ID)/)) {
4629             $pre =~ s/<$TAG/<$TAG$env_id/;
4630         } elsif ($pre =~ /<P>/) {
4631             $TAG = 'P';
4632         } else {
4633         }
4634 #       $post .= "</$TAG>";
4635     }
4636     push (@$open_tags_R, @tags);
4637     $tags .= $pre if ($pre && $post =~ /$block_close_rx/);
4638     if ($font_cmd && !($font_cmd eq $this_tag)) {
4639         push (@$open_tags_R,$font_cmd);
4640         print STDOUT "\n<$font_cmd>" if $VERBOSITY > 2;
4641         $tags .= $font_open;
4642     }
4643     if ($fontwt_cmd && !($fontwt_cmd eq $this_tag)) {
4644         push (@$open_tags_R,$fontwt_cmd);
4645         print STDOUT "\n<$fontwt_cmd>" if $VERBOSITY > 2;
4646         $tags .= $fontwt_open;
4647     }
4648     if ($size_cmd && !($size_cmd eq $this_tag)) {
4649         push (@$open_tags_R,$size_cmd);
4650         print STDOUT "\n<$size_cmd>" if $VERBOSITY > 2;
4651         $tags .= $size_open;
4652     }
4653     if ($color_cmd && !($color_cmd eq $this_tag)) {
4654         push (@$open_tags_R,$color_cmd);
4655         print STDOUT "\n<$color_cmd>" if $VERBOSITY > 2;
4656         $tags .= $color_open;
4657     }
4658     $tags .= $pre unless ($pre && $post =~ /$block_close_rx/);
4659     push (@$open_tags_R, $this_tag)
4660         if ($decl &&!($post =~ /$block_close_rx|$all_close_rx/));
4661     print STDOUT "\n<$this_tag>" if $VERBOSITY > 2;
4662     ($closures.$reopens.$tags , $post );
4666 sub declared_env {
4667     local($decl, $_, $deferred) = @_;
4668     local($after_cell,$pre,$post);
4669     local($decls) = $declarations{$decl};
4670     $decls =~ m|</.*$|;
4671     ($pre,$post) = ($`,$&);
4672     if ($USING_STYLES) {
4673         $env_style{$decl} = " " unless ($env_style{$decl});
4674         $pre =~ s/>$/$env_id>/ if ($env_id);
4675     }
4676     local($closing_tag) = 1 if ($pre =~ /^<>$/);
4677     $pre = $post = '' if $closing_tag;
4678     local($closures,$reopens);
4680     local(@save_open_tags) = @$open_tags_R
4681         unless ($closing_tag || $deferred);
4682     local($open_tags_R) = [ @save_open_tags ]
4683         unless ($closing_tag || $deferred );
4685     if ($post =~ /$block_close_rx/) {
4686         local($last_tag) = pop (@$open_tags_R);
4687         local($ldecl) = $declarations{$last_tag};
4688         if ($ldecl =~ m|</.*$|) { $ldecl = $& }
4689         if (($last_tag)&&!($ldecl =~ /$block_close_rx/)) {
4690             # need to close tags, for re-opening inside
4691             push (@$open_tags_R, $last_tag);
4692             ($closures,$reopens) = &preserve_open_tags();
4693             $pre = join('', $closures, "\n", $pre, $reopens);
4694             $post = join('', $closures, $post, $reopens);
4695         } elsif ($last_tag) {
4696             $pre = "\n".$pre;
4697             push (@$open_tags_R, $last_tag);
4698             undef $ldecl;
4699         } else {
4700         }
4702         if ($deferred) {
4703             if (defined $ldecl) {
4704                 print STDOUT "\n<<$decl>" if $VERBOSITY > 2;
4705                 unshift(@$open_tags_R, $decl);
4706             } else {
4707                 print STDOUT "\n<$decl>" if $VERBOSITY > 2;
4708                 push(@$open_tags_R, $decl);
4709             }
4710             return ( $pre . $_ );
4711         } else {
4712             if (defined $ldecl) {
4713                 print STDOUT "\n<<$decl>" if $VERBOSITY > 2;
4714                 unshift(@$open_tags_R, $decl);
4715             } else {
4716                 print STDOUT "\n<$decl>" if $VERBOSITY > 2;
4717                 push(@$open_tags_R, $decl);
4718             }
4719         }
4720     } elsif ($post =~/$all_close_rx/) {
4721         ($closures,$reopens) = &preserve_open_tags();
4722         ($pre,$post) = &minimize_open_tags($decl,1);
4723         $pre = join('', $closures, $pre);
4724     } elsif ($closing_tag) {
4725         $prev_open = $pre;
4726         ($pre,$post) = &minimize_open_tags($decl,1);
4727         $pre =~ s/<\/?>//g; $post =~ s/<\/?>//;
4728     } else {
4729         ($pre,$post) = &minimize_open_tags($decl); 
4730     }
4731     $_ =~ s/^\s+//s; #RRM:28/4/99 remove spaces at the beginning
4732     $_ = &translate_environments($_);
4733     $_ = &translate_commands($_) if (/\\/);
4734     if ($post =~ /$block_close_rx/) {
4735         s/^\n?/\n/o; 
4736         if (defined $ldecl) {
4737             $post = &close_all_tags();
4738         } else {
4739             $post = "\n";
4740         }
4741     } elsif ($post =~/$all_close_rx/) {
4742     } else { $post = '' };
4744     join('', $pre, $_, $post
4745            , ($closing_tag ? '' : &balance_tags()) );
4748 sub do_cmd_centering{&declared_env('center',$_[0],$tex2html_deferred)}
4749 sub do_cmd_raggedright{&declared_env('flushleft',$_[0],$tex2html_deferred)}
4750 sub do_cmd_raggedleft{&declared_env('flushright',$_[0],$tex2html_deferred)}
4752 sub do_env_verse { &declared_env('verse',@_) }
4753 sub do_env_quote { &declared_env('quote', @_) }
4754 sub do_env_quotation { &declared_env('quote', @_) }
4755 sub do_env_tex2html_preform { &declared_env('preform', @_) }
4756 sub do_env_tex2html_ord { &declared_env('ord', @_) }
4757 sub do_env_tex2html_unord { &declared_env('unord', @_) }
4758 sub do_env_tex2html_desc { &declared_env('desc', @_) }
4761 # Modifies $contents
4762 sub process_command {
4763     # MRO: modified to use $_[1]
4764     # local ($cmd_rx, *ref_contents) = @_;
4765     local ($cmd_rx) = @_;
4766     local($ref_before, $cmd , $pc_after);
4767     local($cmd_sub, $cmd_msub, $cmd_trans, $mathentity);
4768     local (@open_font_tags,@open_size_tags);
4769     $_[1] = &convert_iso_latin_chars($_[1])
4770         unless (($cmd =~ /(Make)?([Uu]pp|[Ll]ow)ercase/)||
4771             ((!$cmd)&&($_[1] =~ /^\\(Make)?([Uu]pp|[Ll]ow)ercase/s)));
4773     local(@ref_processed);
4774     for (;;) {                  # Do NOT use the o option
4775         last unless ($_[1] =~ /$cmd_rx/ );
4776         print ".";
4777         #JCL(jcl-del) - use new regexp form which handles white space
4778         ($ref_before, $cmd, $pc_after) = ($`, $1.$2, $4.$');
4779         push(@ref_processed,$ref_before);
4780 #print "\nAFTER:$1.$2:".$4."\n" if ($cmd_rx eq $single_cmd_rx);
4781         print STDOUT "$cmd" if ($VERBOSITY > 2);
4782         print STDOUT "\nIN: $_[1]\n" if ($VERBOSITY > 6);
4783         #
4784         if ( $cmd = &normalize($cmd,$pc_after) ) {
4785             ($cmd_sub, $cmd_msub, $cmd_trans, $mathentity) =
4786                 ("do_cmd_$cmd", "do_math_cmd_$cmd"
4787                 , $declarations{$cmd}, $mathentities{$cmd});
4788             if ($new_command{$cmd}||$renew_command{$cmd}) { 
4789                 # e.g. some \the$counter 
4790                 local($argn, $body, $opt) = split(/:!:/, $new_command{$cmd});
4791                 &make_unique($body) if ($body =~ /$O/);
4792                 if ($argn) {
4793                     do { 
4794                         local($before) = '';
4795                         local($_) = "\\$cmd ".$pc_after;
4796                         # &substitute_newcmd  may need what comes after the $cmd
4797                         # from the value of $after 
4798                         #RRM: maybe best to pass it as a parameter ?
4799                         my $keep_after = $after;
4800                         $after = $pc_after;
4801                         $pc_after = &substitute_newcmd;   # may change $after
4802                         $pc_after =~ s/\\\@#\@\@/\\/o ;
4803                         $pc_after .= $after;
4804                         $after = $keep_after;
4805                     }
4806                 } else {
4807                     $pc_after = $body . $pc_after;
4808                 }
4809             } elsif (defined &$cmd_sub) {
4810                 # $ref_before may also be modified ...
4811                 if ($cmd =~ /$sizechange_rx/o) {
4812                     $pc_after = &$cmd_sub($pc_after, $open_tags_R);
4813                 } else {
4814                     $pc_after = &$cmd_sub($pc_after, $open_tags_R);
4815                 };
4816             } elsif ((defined &$cmd_msub)&&!$NO_SIMPLE_MATH) {
4817 #print "\nMCMD:$cmd_msub :  ";
4818                 # $ref_before may also be modified ...
4819                 $pc_after = &$cmd_msub($pc_after, $open_tags_R);
4820                 if ( !$math_mode ) {
4821                     $pc_after = "<MATH>" . $pc_after . "</MATH>";
4822                     ++$commands_outside_math{$cmd};
4823                 };
4824             } elsif ($cmd_trans) { # One to one transform
4825 #print "\nCMD-DECL: $inside_tabular : $cmd_trans". join(',',@$open_tags_R);
4826                 if ($inside_tabular) {
4827                     push (@ref_processed , "\\$cmd ")
4828                 } else {
4829                     $cmd_trans =~ m|</.*$|;
4830                     $pc_after = $` . $pc_after unless ($` =~ /^<>/);
4831                     push(@$open_tags_R, $cmd)
4832                         if ($cmd =~ /$fontchange_rx|$fontweight_rx|$sizechange_rx/o);
4833                 }
4834             } elsif ($mathentity) {
4835 #print "\nM-ENT:$mathentity :  ";
4836                 if ( $math_mode ) {
4837                     $pc_after = "&$mathentity#$cmd;" . $pc_after;
4838                 } elsif ($NO_SIMPLE_MATH) {
4839                     $pc_after = "&$mathentity#$cmd;" . $pc_after;
4840 #                   ++$commands_outside_math{$cmd};
4841                 } else {
4842                     $pc_after = "<MATH>&$mathentity#$cmd;</MATH>" . $pc_after;
4843                     ++$commands_outside_math{$cmd};
4844                 }
4845             } elsif ($ignore{$cmd}) { # Ignored command
4846                 print "\nignoring \\$cmd" if $VERBOSITY > 5;
4847                 $pc_after = join('', " ", $pc_after) if ($cmd eq " "); # catches `\ '
4848                 $pc_after = join(''," ", $pc_after)
4849                     if (($cmd eq ',')&&($pc_after =~ /^\-/s)&&($ref_before =~/\-$/s));
4850             } elsif ($cmd =~ /^the(.+)$/){
4851                 $counter = $1;
4852                 local($tmp)="do_cmd_$cmd";
4853                 if (defined &$tmp) { # Counter
4854                     $pc_after = &do_cmd_thecounter($pc_after);
4855                 } else {
4856                     if (defined $failed) {
4857                         $failed = 1;
4858 #                       $ref_before .= "$cmd";
4859                         push(@ref_processed,$cmd);  # $ref_before .= "$cmd";
4860                     } else {  &declare_unknown_cmd($cmd) }
4861 #                   $ref_before .= "$cmd" if ($failed);
4862                 }
4863             } elsif ($cmd eq "\n") { push(@ref_processed," ");  # $ref_before .= " "; 
4864             } else {
4865                 # Do not add if reading an auxiliary file
4866                 if (defined $failed) { 
4867                     $failed = 1;
4868                 } else { &declare_unknown_cmd($cmd) }
4869             }
4870         } else {
4871             # &normalize should have already handled it adequately
4872             # '\ ' (space) gets thru to here. Perhaps some others too ?
4873 #           print "\n ?? This should not happen: \\$cmd ??\n";
4874         }
4875 #       $_[1] = join('', $ref_before, $pc_after);
4876         $_[1] = $pc_after;
4877         print STDOUT "\n-> $ref_before\n" if ($VERBOSITY > 6);
4878     }
4879     $_[1] = join('',@ref_processed).$_[1];
4882 sub declare_unknown_cmd {
4883     local($this_cmd) = @_;
4884     local($tmp) = "wrap_cmd_$cmd";
4885     do { ++$unknown_commands{$cmd};
4886         print STDOUT "\n*** Unknown command[1]: \\$cmd *** \n" 
4887             if ($VERBOSITY > 2);
4888     } unless ($AUX_FILE||(defined &$tmp)||($image_switch_rx=~/\b\Q$cmd\E\b/));
4892 # This makes images from the code for math-entities,
4893 # when $NO_SIMPLE_MATH is set and the  math  extension is loaded.
4895 sub replace_math_constructions {
4896     local($math_mode) = @_;
4897     &make_math_box_images($math_mode) if (/<BOX>/);
4898     &make_math_entity_images($math_mode) if (/\&\w+#\w+;/);
4901 sub make_math_box_images {
4902     local($math_mode) = @_;
4903     local($pre,$this,$post,$tmp) = ('','','');
4904     local($slevel,$blevel) = 0;
4906     while (/<BOX>/) {
4907         $pre .= $`; $tmp = $`; $this = ''; $post = $';  
4908         # compute the super/sub-scripting level for each entity
4909         $tmp =~ s/<(\/?)SU[BP]>/
4910             if ($1) { $slevel--} else { $slevel++};''/eog;
4912         $tmp = $post;
4913         if ($tmp =~ /<(\/?)BOX>/o ) {
4914             if ($1) { $this = $`; $post = $' }
4915             else { $failed = 1 } # nested box, too complicated !
4916         } else {
4917             &write_warnings("\nLost end of a <BOX> ?");
4918             $failed = 1;
4919         }
4920         last if ($failed);
4922         ($this,$_) = &process_box_in_latex(
4923                     $math_mode, $slevel, $this, $post);
4924         $_ =~ s/^\s*//; # remove any leading spaces
4925         $pre .= $this ."\001"; 
4926     }
4927     return  if ($failed);
4928     $_ = $pre . $_;
4931 sub make_math_entity_images {
4932     local($math_mode) = @_;
4933     local($pre,$this,$post,$tmp) = ('','','');
4934     local($slevel) = 0;
4935     # compute the super/sub-scripting level for each entity
4936     while (/\&\w+#(\w+);/) {
4937         $pre .= $`; $tmp = $`; $this = $1; $post = $';
4938         $tmp =~ s/<(\/?)SU[BP]>/
4939             if ($1) { $slevel--} else { $slevel++};''/eog; 
4940         ($this,$_) = &process_entity_in_latex(
4941                 $math_mode, $slevel, $this, $post);
4942         $_ =~ s/^\s*//; # remove any leading spaces
4943         $pre .= $this ."\001"; 
4944     }
4945     $_ = $pre . $_;
4949 #RRM:  Revert a math-entity to create image using LaTeX, together with
4950 # any super/sub-scripts (possibly nested or with \limits ).
4951 # Must also get the correct  \display/text/(script)script  style.
4953 sub process_entity_in_latex {
4954     local($mode,$level,$entity,$after) = @_;
4955     local($math_style,$supsub,$rest) = ('','','');
4956     $level++ if ($mode =~/box/); # for top/bottom of inline fractions, etc.
4958     if ($level) {
4959         $math_style = "\\". (($level > 1) ? "script" : "")."scriptstyle"
4960     } else {
4961         $math_style = "\\displaystyle" unless ($mode =~ /inline/);
4962     }
4963     while ($after =~ s/^\s*((\\limits|\&limits;)?\s*<SU(P|B)>)\s*/$supsub .= $1;''/eo) {
4964         local($slevel) = 1;
4965         local($aftersupb) = '';
4966         while ($slevel) {
4967             $after =~ s/(<(\/)SU(B|P)>)/($2)? $slevel-- : $slevel++;''/oe;
4968             $supsub .= $`.$&;
4969             $aftersupb = $';
4970         }
4971         $after = $aftersupb;
4972     }
4974     local($latex_code) = "\$$math_style\\$entity$supsub\$";
4976     $global{'max_id'}++;
4977     ( &process_undefined_environment('tex2html_wrap_inline'
4978              ,$global{'max_id'}, $latex_code ) , $after);
4981 sub process_box_in_latex {
4982     local($mode,$level,$inside,$after) = @_;
4983     local($math_style,$which,$pre,$post,$tmp) = ('','',"\{","\}");
4984     
4985     if ($level) {
4986         $math_style = "\\". (($level > 1) ? "script" : "")."scriptstyle"
4987     } else {
4988         $math_style = "\\displaystyle" unless ($mode =~ /inline/);
4989     }
4991     if ($inside =~ /<((LEFT)|(RIGHT))>/ ) {
4992         $pre = "\\left"; $post = "\\right";
4993         if ($2) { 
4994             $tmp = $`; $inside = $';
4995             $pre .= (($tmp) ? $tmp : ".") . "\{";
4996             if ( $inside =~ /<RIGHT>/ ) {
4997                 $tmp = $';
4998                 $inside = $`;
4999                 $post = "\}". (($tmp) ? $tmp : ".");
5000             }
5001         } else {
5002             $pre .= ".\{"; $tmp = $'; $inside = $`;
5003             $post = "\}". (($tmp) ? $tmp : ".");
5004         }
5005     }
5006     if ( $inside =~ /<((OVER)|(ATOP)|(CHOOSE))>/ ) {
5007         $pre .= $`;
5008         $post = $' . $post ;
5009         if ($2) { $which = "over " }
5010         elsif ($3) { $which = "atop " }
5011         elsif ($4) { $which = "atopwithdelims\(\)" }
5012     }
5014     local($latex_code) = join('', "\$" , $math_style , " ", $pre 
5015           , (($which)? "\\$which" : "") , $post , "\$" );
5017     if ($after =~ s/<SUP ALIGN=\"CENTER\">([^<]*)<\/SUP>/
5018         $tmp =$1;''/eo ) {
5019         $latex_code = join('', "\\stackrel" , $latex_code
5020                            , "\{" , $tmp , "\}" );
5021     }
5022     
5023     $global{'max_id'}++;
5024     ( &process_undefined_environment('tex2html_wrap_inline'
5025              ,$global{'max_id'}, $latex_code ) , $after);
5028 ####################### Processing Meta Commands ############################
5029 # This is a specialised version of process_command above.
5030 # The special commands (newcommand, newenvironment etc.)
5031 # must be processed before translating their arguments,
5032 # and before we cut up the document into sections
5033 # (there might be sectioning commands in the new definitions etc.).
5034 # \newtheorem commands are treated during normal processing by
5035 # generating code for the environments they define.
5037 sub substitute_meta_cmds {
5038     local ($next_def);
5039     local ($cmd, $arg, $argn, $opt, $body, $before, $xafter);
5040     local ($new_cmd_no_delim_rx, $new_cmd_rx, $new_env_rx, $new_cmd_or_env_rx);
5041     local ($new_end_env_rx);
5042     &tokenize($meta_cmd_rx);    #JCL(jcl-del) - put delimiter after meta command
5043     print "\nProcessing macros ..." if (%new_command || %new_environment);
5044     # First complete any replacement left-over from the previous part.
5045     if ($UNFINISHED_ENV) { 
5046         s/$UNFINISHED_ENV/$REPLACE_END_ENV/;
5047         $UNFINISHED_ENV = '';
5048         $REPLACE_END_ENV = '';
5049     }
5051     local(@processed);
5052     local($processed, $before, $after)=('', '', $_);
5053     while ($after =~ /$meta_cmd_rx$EOL/o) {     # ... and uses the delimiter
5054         ($cmd, $after) = ($1.$2, $');
5055         $before .= $`;
5056 #       $next_def = '';
5057         if (!($before =~ /$meta_cmd_rx$EOL/)) {
5058             push(@processed, $before); $before = '';
5059         }
5060                  
5061         print ",";
5062 #       $next_def = "\\$cmd" unless (($cmd =~ /renewcommand/));
5063         local($cmd_sub) = "get_body_$cmd";
5064         if (defined &$cmd_sub) {
5065 #           $processed = &$cmd_sub(*after);
5066             $processed = &$cmd_sub(\$after);
5067 #           if ($processed) { $after = $before . $processed; }
5068 #           $next_def = '' 
5069 #               if (($PREAMBLE > 1)&&($cmd =~ /(re)?newcommand/));
5070 #           &add_to_preamble($cmd, $next_def)
5071 #               unless ($next_def =~ /^\s*$/);
5072 ### new style of handling meta-commands
5073             if ($processed) { push(@processed, "\\".$processed) }
5074         }
5075         elsif ($before) {
5076             # this shouldn't happen !!
5077             print STDERR "\nCannot handle \\$cmd , since there is no $cmd_sub ";
5078             $after = $before . $cmd . $after;
5079             $before = '';
5080         } else { 
5081             push(@processed, "\\$cmd ") if $cmd;
5082         }
5083     }
5084     print "\nmeta-commands: ". (0+@processed) ." found "
5085         if ((@processed)&&($VERBOSITY > 1));
5086     $_ = join('',@processed, $after); undef @processed;
5087     if ($PREAMBLE) {
5088         # MRO: replaced $* with /m
5089         s/((\n$comment_mark\d*)+\n)//gm;
5090         s/(\\par\b\s*\n?)+/\\par\n/gm;
5091         s/(\\par\b\n?)+/\\par\n/gm;
5092     }
5094     # hard-code the new-command replacements for these
5095     $new_command{'begingroup'} = "0:!:\\begin<<0>>tex2html_begingroup<<0>>:!:}";
5096     $new_command{'endgroup'} = "0:!:\\end<<0>>tex2html_begingroup<<0>>:!:}";
5097     $new_command{'bgroup'} = "0:!:\\begin<<0>>tex2html_bgroup<<0>>:!:}";
5098     $new_command{'egroup'} = "0:!:\\end<<0>>tex2html_bgroup<<0>>:!:}";
5100     # All the definitions have now moved to the $preamble and their bodies
5101     # are stored in %new_command and %new_environment
5102     #
5103     # Now substitute the new commands and environments:
5104     # (must do them all together because of cross definitions)
5105     $new_cmd_rx = &make_new_cmd_rx(keys %new_command);
5106     $new_cmd_no_delim_rx = &make_new_cmd_no_delim_rx(keys %new_command);
5107     $new_env_rx = &make_new_env_rx;
5108     $new_end_env_rx = &make_new_end_env_rx;
5109 #    $new_cnt_rx = &make_new_cnt_rx(keys %new_counter);
5110     $new_cmd_or_env_rx = join("|", $new_cmd_no_delim_rx." ", $new_env_rx);
5111 #    $new_cmd_or_env_rx = join("|", $new_cmd_no_delim_rx." ", $new_env_rx, " ".$new_cnt_rx);
5112     $new_cmd_or_env_rx =~ s/^ \||\|$//;
5114     print STDOUT "\nnew commands:\n" if ($VERBOSITY > 2);
5115     while (($cmd, $body) = each %new_command) {
5116         unless ($expanded{"CMD$cmd"}++) {
5117             print STDOUT ".$cmd " if ($VERBOSITY > 2);
5118             $new_command{$cmd} = &expand_body;
5119             print STDOUT " ".$new_command{$cmd}."\n" if ($VERBOSITY > 4);
5120             &write_mydb("new_command", $cmd, $new_command{$cmd});
5121         }
5122     }
5124     print STDOUT "\nnew environments:\n" if ($VERBOSITY > 2);
5125     while (($cmd, $body) = each %new_environment) {
5126         unless ($expanded{"ENV$cmd"}++) {
5127             print STDOUT ".$cmd" if ($VERBOSITY > 2);
5128             $new_environment{$cmd} = &expand_body;
5129             &write_mydb("new_environment", $cmd, $new_environment{$cmd});
5130         }
5131     }
5133     print STDOUT "\nnew counters and dependencies:\n" if ($VERBOSITY > 2);
5134     &clear_mydb("dependent") if ($DEBUG);     #avoids appending to a previous version
5135     while (($cmd, $body) = each %dependent) {
5136         print STDOUT ".($cmd,$body)" if ($VERBOSITY > 2);
5137         &write_mydb("dependent", $cmd, $dependent{$cmd});
5138     }
5139     &clear_mydb("img_style") if ($DEBUG);     #avoids appending to a previous version
5140     while (($cmd, $body) = each %img_style) {
5141         &write_mydb("img_style", $cmd, $img_style{$cmd});
5142     }
5144     &clear_mydb("depends_on") if ($DEBUG);     #avoids appending to a previous version
5145     while (($cmd, $body) = each %depends_on) {
5146         print STDOUT ".($cmd,$body)" if ($VERBOSITY > 2);
5147         &write_mydb("depends_on", $cmd, $depends_on{$cmd});
5148     }
5151     &clear_mydb("styleID") if ($DEBUG);     #avoids appending to a previous version
5152     while (($cmd, $body) = each %styleID) {
5153         &write_mydb("styleID", $cmd, $styleID{$cmd});
5154     }
5156     &clear_mydb("env_style") if ($DEBUG);     #avoids appending to a previous version
5157     while (($cmd, $body) = each %env_style) {
5158         &write_mydb("env_style", $cmd, $env_style{$cmd});
5159     }
5160     &clear_mydb("txt_style") if ($DEBUG);     #avoids appending to a previous version
5161     while (($cmd, $body) = each %txt_style) {
5162         &write_mydb("txt_style", $cmd, $txt_style{$cmd});
5163     }
5165     print STDOUT "\ntheorem counters:\n" if ($VERBOSITY > 2);
5166     &clear_mydb("new_theorem") if ($DEBUG);     #avoids appending to a previous version
5167     while (($cmd, $body) = each %new_theorem) {
5168         print STDOUT ".($cmd,$body)" if ($VERBOSITY > 2);
5169         &write_mydb("new_theorem", $cmd, $new_theorem{$cmd});
5170     }
5173     print "+";
5174     if (length($new_env_rx)) {
5175         local(@pieces);
5176         print STDOUT "\nsubstituting new environments: $new_env_rx\n" if ($VERBOSITY > 3);
5177 #       while (/\n?$new_env_rx/ && (($before, $cmd, $after) = ($`, $2, $'))) {
5178         while (/$new_env_rx/ && (($before, $cmd, $after) = ($`, $2, $'))) {
5179             print STDOUT ",";
5180             print STDOUT "{$cmd}" if ($VERBOSITY > 1);
5181             if (!($before =~ /$new_env_rx/)) {
5182                 push (@pieces, $before); $before = ''; print "{}";
5183             }
5184             $_ = join('',$before, &substitute_newenv);
5185         }
5186         print "\n ".(0+@pieces). " new environments replaced\n" if (@pieces);
5187         $_ = join('', @pieces, $_); undef @pieces;      
5188     }
5191     print "+";
5192     if (length($new_cmd_rx)) {
5193         print STDOUT "\ntokenizing: $new_cmd_rx\n" if ($VERBOSITY > 2);
5194         &tokenize($new_cmd_rx); # Put delimiter after the new commands
5196         # and use the delimiter.
5197         print STDOUT "\nsubstituting new commands: $new_cmd_rx\n" if ($VERBOSITY > 2);
5198         print STDOUT "\ninitial size: ".length($after) if ($VERBOSITY > 1);
5199         # store processed pieces in an array
5200         local($this_cmd, @pieces);
5201         # speed-up processing of long files by splitting into smaller segments
5202         # but don't split within the preamble, else \newenvironment may break
5203         local($pre_segment,@segments); &make_sections_rx;
5204         local($within_preamble,$this_section) = 1 if ($PREAMBLE>1);
5205         while (/$sections_rx/) {
5206             $pre_segment .= $`; $_ = $'; $this_section = $&;
5207             do {
5208                 push(@segments,$pre_segment);
5209                 $pre_segment = '';
5210             } unless ($within_preamble);
5211             $within_preamble = 0 if ($within_preamble && ($pre_segment =~ 
5212                     /\\(startdocument|begin\s*($O\d+${C})\s*document\s*\2)/));
5213             $pre_segment .= $this_section;
5214         }
5215         push(@segments,$pre_segment.$_);
5216         local($replacements,$seg) ; $before = ''; # count the segments
5217         local($within_preamble) = 1 if ($PREAMBLE>1);
5218         foreach $after (@segments) {
5219           while ($after =~ /(\\(expandafter|noexpand)\b\s*)?$new_cmd_no_delim_rx\b\s?/) {
5220             ($before, $xafter, $cmd, $after) = ($`, $2, $3, $');
5221             $within_preamble = 0
5222                 if ($before =~ /\\(startdocument|begin\s*($O\d+${C})\s*document\s*\2)/);
5223             push(@pieces, $before);
5224             print "."; ++$replacements;
5225             print STDOUT "$cmd" if ($VERBOSITY > 2);
5226             if ($xafter =~ /no/) { $this_cmd = "\\\@#\@\@".$cmd  }
5227             elsif (($xafter =~ /after/)&&($after =~ /^\s*\\/)) {
5228                 local($delayed) = $cmd;
5229                 local($nextcmd);
5230                 $after =~ s/^\s*\\([a-zA-Z]+|.)/$nextcmd = $1;''/eo;
5231                 ($cmd,$nextcmd) = ($nextcmd, "do_cmd_$nextcmd");
5232                 if (defined &$nextcmd) { $after = &$nextcmd($after); }
5233                 elsif ($new_command{$cmd}) { 
5234                     local($argn, $body, $opt) = split(/:!:/, $new_command{$cmd});
5235                     &make_unique($body) if ($body =~ /$O/);
5236                     if ($argn) {
5237                         do { 
5238                             local($before) = '';
5239                             $after = join('',&substitute_newcmd, $after);
5240                             $after =~ s/\\\@#\@\@/\\/o ;
5241                         };
5242                     } else { $after = $body . $after; }
5243                 } else { print "\nUNKNOWN COMMAND: $cmd "; }
5244                 $cmd = $delayed;
5245                 if ($new_command{$cmd}) {
5246                     if ($renew_command{$cmd}) {
5247 #                       # must wrap it in a deferred environment
5248 #                       $this_cmd = join('', &make_deferred_wrapper(1)
5249 #                               ,"\\$cmd".(($cmd =~ /\w$/)? " ":'')
5250 #                               , &make_deferred_wrapper(0));
5251 #                       push(@pieces, $this_cmd); $this_cmd = '';
5252                         push(@pieces, "\\$cmd".(($cmd =~ /\w$/)? " ":''));
5253                         $this_cmd = '';
5254                     } elsif ($provide_command{$cmd}&&$within_preamble) {
5255                         # leave it alone
5256                         push(@pieces, "\\$cmd".(($cmd =~ /\w$/)? " ":''));
5257                         $this_cmd = '';
5258                     } else {
5259                         # do the substitution
5260                         $this_cmd = &substitute_newcmd;
5261                     }
5262                 }
5263             } elsif ($renew_command{$cmd}) {
5264                 # leave it alone
5265                 push(@pieces, "\\$cmd".(($cmd =~ /\w$/)? " ":''));
5266                 $this_cmd = '';
5267             } elsif (($provide_command{$cmd})&&($within_preamble)) {
5268                 # leave it alone
5269                 push(@pieces, "\\$cmd".(($cmd =~ /\w$/)? " ":''));
5270                 $this_cmd = '';
5271             } else {
5272                 # do the substitution
5273                 $this_cmd = &substitute_newcmd if ($new_command{$cmd});
5274             }
5275             if ($this_cmd =~ /(\\(expandafter|noexpand)\s*)?$new_cmd_no_delim_rx\b\s?/)
5276                 { $after = $this_cmd . $after }
5277             elsif ($this_cmd) { push(@pieces, $this_cmd) }
5278           }
5279           push(@pieces, $after);
5280                 # after the first segment we should no longer be in the preamble
5281                 $within_preamble = 0;
5282         }
5283         print " $replacements new-command replacements\n"
5284             if (($VERBOSITY>1) && $replacements);
5285         # recombine the processed pieces
5286         $_ = join('', @pieces); undef @pieces;
5287         print STDOUT ", resulting size: ".length($_)." " if ($VERBOSITY > 1);
5288         $_ =~ s/\\\@#\@\@/\\/go;
5289     }
5291     print STDOUT "\n *** substituting metacommands done ***\n" if ($VERBOSITY > 3);
5294 sub insert_command_expansion {
5295     ($xafter, $cmd) = @_;
5296 #   push(@pieces, $_[1]);
5297     print ".$cmd";
5298     print STDOUT "$_[3]" if ($VERBOSITY > 2);
5299 #   $xafter = $_[2];
5300 #   $cmd = $_[3];
5301     if ($xafter =~ /no/) { $this_cmd = "\\\@#\@\@".$cmd }
5302     elsif (($xafter =~ /after/)&&($after =~ /^\s*\\/)) {
5303         local($delayed,$nextcmd) = ($_[3],'');
5305         $after =~ s/^\s*\\([a-zA-Z]+|.)/$nextcmd = $1;''/eo;
5306         ($cmd,$nextcmd) = ($nextcmd, "do_cmd_$nextcmd");
5307         if (defined &$nextcmd) { $after = &$nextcmd($after); }
5308         elsif ($new_command{$cmd}) { 
5309             local($argn, $body, $opt) = split(/:!:/, $new_command{$cmd});
5310             &make_unique($body) if ($body =~ /$O/);
5311             if ($argn) {
5312                 do { 
5313                     local($before) = '';
5314                     $after = join('',&substitute_newcmd, $after);
5315                     $after =~ s/\\\@#\@\@/\\/o ;
5316                 };
5317             } else { $after = $body . $after; }
5318         } else { print "\nUNKNOWN COMMAND: $cmd "; }
5319         $cmd = $delayed;
5320         $this_cmd = &substitute_newcmd if ($new_command{$cmd});         
5321     } else {
5322         $this_cmd = &substitute_newcmd if ($new_command{$cmd});
5323     }
5324 #   if ($this_cmd =~ /(\\(expandafter|noexpand)\s*)?$new_cmd_no_delim_rx\s?/){
5325 #       $after = $this_cmd . $after
5326 #   } else { push(@pieces, $this_cmd); }
5327     $this_cmd;
5331 sub expand_body {
5332     return unless length($new_cmd_or_env_rx);
5333     local($_) = $body;
5334     local($cmd,$saveafter,$avoid_looping);
5335     # Uses $before, $body, $arg, etc. of the caller, but not $cmd.
5336     # Uses $new_cmd_rx (resp. $new_cmd_no_delim_rx) and $new_env_rx
5337     # set in the caller, of which one might be empty.
5339     # Puts delimiter after the new commands ...
5340     &tokenize($new_cmd_rx) if length($new_cmd_rx);
5342     while (/$new_cmd_or_env_rx/) {
5343         # $new_cmd_rx binds $1, and $new_env_rx binds $3.
5344         ($before,$cmd,$after,$saveafter) = ($`,$1.$3,$',$');
5345         if (length($new_command{$cmd})) { # We have a command
5346             # this tokenizes again
5347             local($replace) = &substitute_newcmd; # sets $_, changes $after
5348             if (!($replace)) {
5349                 # protect name of unexpanded macro
5350                 $_ = join('', $before ,"\\@#@@", $cmd, $saveafter );
5351             } else {
5352                 $_ = join('', $before , $replace, $after );
5353             }
5354         } elsif (length($new_environment{$cmd})) {
5355             $_ = join('',$before, &substitute_newenv);
5356         }
5357         last if $avoid_looping;
5358     }
5359     # remove protection from unreplaced macro names
5360     s/\\\@#\@\@/\\/go;
5362     # remove trivial comments
5363     s/(\\\w+)$comment_mark\d*\n[ \t]*/$1 /go;
5364     s/$comment_mark\d*\n[ \t]*//go;
5365 #    s/($O\d+$C)?($comment_mark\n)[ \t]*/($1 ? $1.$2 : '')/eg;
5367     $_;
5371 sub substitute_newcmd {
5372     # Modifies $after in the caller
5373     # Get the body from the new_command array
5374     local($tmp,$cnt,$saved, $arg, $isword) = ('',0,$cmd);
5375     local($argn, $_, $opt) = split(/:!:/, $new_command{$cmd});
5376     $avoid_looping = 1 if ($new_command{$cmd} =~ /\\$cmd\b/);
5378     &tokenize($new_cmd_rx); # must do it again for newly inserted cmd bodies
5379     print STDOUT "\nNEW:$cmd:$_" if ($VERBOSITY > 5);
5380     foreach $i (1..$argn) {
5381         $arg = $isword = '';
5382         if ($i == 1 && $opt ne '}') {
5383             $arg = ($after =~ s/$optional_arg_rx//o) ? $1 : $opt;
5384         }
5385         else {
5386             # Get the next argument, if not in braces, get next character
5387             #RRM: allow also for processed braces, in case substitution
5388             #     was delayed; e.g. by \renewcommand
5389             if (!(($after =~ s/$next_pair_rx/$arg = $2;''/e)
5390                   ||($after =~ s/$next_pair_pr_rx/$arg = $2;''/e))) {
5391                 $after =~ s/^\s*(\\[a-zA-Z]+|.)/$arg = $1;''/e;
5392             }
5393             if ($arg eq '#') { 
5394                 &write_warnings("\nSubstitution of arg to $cmd delayed."); 
5395                 $_ = "\\\@#\@\@$saved";
5396                 return ();
5397             };
5398         }
5399         $arg =~ s/(^|\G|[^\\])\\\#/$1$hash_mark/gs;
5400         $arg =~ s/\#/$param_mark/gs;
5402         #RRM: Substitute the arguments in the body one at a time
5403         #     else multiple instances would fail in  &make_unique
5405         # First protect ## parameters in TeX-like substitutions
5406         # suggested by Dirk Pleiter (Berlin)
5407         s/((^|[^\\])(\\\\)*)\#\#$i/$1$protected_hash/gs;
5408         $tmp = $_;
5409         $cnt = $tmp =~ s/\#$i//g ;
5410         $isword = 1 if ($arg =~ /^\w/);
5411         if ($cnt > 1 ) {
5412             $tmp = $_;
5413             while ($cnt > 1) {
5414                 if ( s/(\\\w+)?\#$i/(($1&&$isword)? $1.' ': '').$arg/e) { 
5415                     &make_unique($_) if ($arg =~ /$O/ ); 
5416                     &make_unique_p($_) if ($arg =~ /$OP/ );
5417                 }
5418                 $cnt--;
5419             }
5420             $tmp = $_;
5421         }
5422 #       s/(\\\w+)?\#$i/(($1&&$isword)? $1.' ': '').$arg/e ;
5423         s/(\\\w+)?\#$i/$1.(($1&&$isword)? ' ': '').$arg/e ;
5424         print "\n *** substitution: $arg \nfor \#$i in \\$cmd did not take ***\n"
5425            if (/\#$i/);
5426         &write_warnings("incomplete substitution in a \\$cmd command:\n$_") if (/\#$i/);
5427         s/$protected_hash/\#$i/g;
5428     }
5429     s/$param_mark/\#/g;
5430     s/$hash_mark/\\\#/g;
5431     s/(\\\w+)$/$1 /s;
5433     # Make the body unique (give unique id's to the brackets),
5434     # translate, and return it
5435     &make_unique($_);
5436     if ($avoid_looping) {
5437         s/\\$cmd\b/\\csname $cmd\\endcsname/g;
5438         print STDERR "\n *** possible looping with new-command \\$cmd ***\n";
5439         &write_warnings("\npossible looping with new-command \\$cmd ");
5440     }
5441     print STDOUT "\nOUT:$cmd:$_" if ($VERBOSITY > 5);
5443 # Insert a space to prevent letters from clashing together with a
5444 # letter command. Consider this:
5445 # New command substitution is restricted to commands introduced by
5446 # \newcommand etc. (so-called meta commands), but it is not done
5447 # for already defined commands, eg. \large.
5448 # But new command, as well as new environment, substitution is done
5449 # prior to any other substitution.
5450 # So \newcommand{\this}{...} {\large\this b} will get expanded the
5451 # following way:
5452 # 1. \newcommand{\this}{...}
5453 #    is handled by &substitute_meta_cmds, it gets the definition
5454 #    of \this and stores it within a table, %new_command.
5455 #    After all new commands are recognized, &expand_body is called
5456 #    to expand one command body from each other. That's O(n*n)!
5457 # 2. A regular expression $new_cmd_rx is built containing a pattern
5458 #    that matches all occurrences of a properly delimited \this
5459 #    macro. When matching, ensuing white space gets lost.
5460 #    (But only for letter commands, see also &make_new_cmd_rx.)
5461 #    Another regular expression called $new_cmd_no_delim_rx is built
5462 #    which matches exact the \this, and would also match the prefix
5463 #    of \thisx.
5464 # 3. The *whole* text is tokenized using $new_cmd_rx, with separates
5465 #    \this from the ensuing text by one white space.
5466 # 4. Then $new_cmd_no_delim_rx together with the delimiting space
5467 #    is used to substitute \this with its body.
5468 # 5. The following situations may occur:
5469 #  a) ... is some text (no macros) => {\large<text>yyy}
5470 #     Then we must prevent that the text clashes into \large.
5471 #     This is only dangerous when <text> begins with a letter.
5472 #  b) ... contains another, not expanded new command.
5473 #     This happens during &expand_body.
5474 #     In this case, make sure to &tokenize the body before giving
5475 #     the result to the caller. Also take care that leading letters
5476 #     of the body cannot clash into \large.
5477 #  e) ... contains a macro not known as new command:
5478 #     Make sure that the macro cannot clash with the ensuing yyy.
5479 #  f) ... is empty:
5480 #     Make sure that \large cannot clash with yyy.
5481 # 6. We prevent clashing by inserting a delimiting blank.
5482 #    Out of the scetched situation, there are three conditions to
5483 #    take care of:
5484 #  a) empty body, left a letter command, right a letter => blank
5485 #  b) body starts with letter, left a letter command    => blank
5486 #  c) body ends with letter command, right a letter     => blank
5487 #  d) else => no blank, clash all together, it will work.
5488 # 7. With this rules, the expansion should work quite well,
5489 #    concerning letter/non-letter commands and white space
5490 #    handling.
5491 # 8. Deficiencies:
5492 # 8.1 Consider \this<CR>that. It's handled this way:
5493 #  a) The \this swallows the <CR> in LaTeX, but what LaTeX2HTML does
5494 #     is to &tokenize the expression into \this <CR>that.
5495 #  b) If ... is some text, it results in <text><CR>that.
5496 #  c) If ... is a macro (or command, or control sequence, these
5497 #     terms are often mixed up, but effectively mean the same),
5498 #     then if the macro later takes at least one argument, the <CR>
5499 #     might get swallowed, this depends on the grace of $next_pair_rx
5500 #     resp. $next_pair_pr_rx.
5501 #     If the macro takes no arguments, the <CR> remains in the text.
5502 #  d) If ... ends in another new command, the problem repeats.
5503 # 8.2 The new commands are substituted in a very insensitive way.
5504 #     If \this occurs within an environment which sees \this
5505 #     totally different, there's no chance to substitute \this in
5506 #     a different way.
5507 # 8.3 In relation to 8.2 a similar problem arises when the meta
5508 #     command, or several meta commands redefining \this, occur
5509 #     amongst several \this macros.
5510 # 8.4 In raw TeX like environments it is not possible to revert the
5511 #     expansion of \this, but \this probably *must* occur in its
5512 #     raw form.
5514 # Handle the cases as depicted in the description of new command
5515 # substitution.
5516     local($befdel,$aftdel);
5517     $befdel = ' '
5518         if ($before=~/(^|[^\\])\\[a-zA-Z]+$/ && /^$/ && $after=~/^[a-zA-Z]/) ||
5519             ($before=~/(^|[^\\])\\[a-zA-Z]+$/ && /^[a-zA-Z]/);
5520     $aftdel = ' '
5521         if /(^|[^\\])\\[a-zA-Z]+$/s && $after=~/^[a-zA-Z]/;
5522     join('', $befdel, $_, $aftdel);
5525 #RRM:  use this to test whether a specific command is substituting correctly
5526 sub trace_cmd {
5527     local($this) = @_;
5528     if ($cmd eq $this) { print "\n$1=>$id:$2::"}
5531 # Make the text unique (give unique id's to the brackets).
5532 # The text shouldn't contain processed brackets.
5533 sub make_unique {
5534     # MRO: Change to references $_[0]
5535     # local(*_) = @_;
5536     my $id = $global{'max_id'};
5537     # MRO: replaced $* by /m
5538     # this looks quite funny but is optimized
5539     1 while($_[0] =~ s/$O(\d+)$C([\w\W]*)$O\1$C/$id++;"\000$id $2\000$id "/geom);
5540     $_[0] =~ s/\000(\d+) /$O$1$C/gom;
5541     $global{'max_id'} = $id;
5544 #RRM: this shouldn't be needed, but just in case...
5545 sub make_unique_p {
5546     # MRO: Change to references $_[0]
5547     my $id = $global{'max_id'};
5548     # MRO: replaced $* by /m
5549     # this looks quite funny but is optimized
5550     1 while($_[0] =~ s/$OP(\d+)$CP([\w\W]*)$OP\1$CP/$id++;"\000$id $2\000$id "/geom);
5551     $_[0] =~ s/\000(\d+) /$OP$1$CP/gom;
5552     $global{'max_id'} = $id;
5556 sub substitute_newenv {
5557     # Modifies $cmd and $after in the caller
5558     # Get the body from the new_environment array
5559     local($argn, $begdef, $enddef, $opt) = split(/:!:/, $new_environment{$cmd});
5560     local($arg,$new_def_rx,$tmp,$cnt);
5562     # Note that latex allows argument substitution only in the
5563     # \begin part of the new definition
5564     foreach $i (1..$argn) {     # Process the arguments
5565         if (($i == 1) && ($opt ne '}')) {
5566             $after =~ s/$optional_arg_rx/$arg = $1;''/eo;
5567             $arg = $opt unless $arg;
5568         }
5569         else {
5570             $after =~ s/$next_pair_rx/$arg = $2;''/eo;
5571         }
5572         $arg =~ s/(^|[^\\])\\\#/$1$hash_mark/g;
5573         $arg =~ s/\#/$param_mark/g;
5575         #RRM: multiple instances can fail later in  &make_unique
5576 #       s/\#$i/$arg/g;          # Substitute the arguments in the body
5577         #RRM: ...so do one at a time and  &make_unique_p
5578         $tmp = $begdef;
5579         $cnt = $tmp =~ s/\#$i//g ;
5580         if ($cnt > 1) {
5581             $tmp = $begdef;
5582             while ($cnt > 1) {
5583                 if ( $begdef =~ s/\#$i/$arg/) { 
5584                     &make_unique($begdef) if ($arg =~ /$O/ ); 
5585                     &make_unique_p($begdef) if ($arg =~ /$OP/ );
5586                 }
5587                 $cnt--;
5588             }
5589             $tmp = $_;
5590         }
5591         $begdef =~ s/\#$i/$arg/ ;
5592         print "\n *** substitution: $arg \nfor \#$i in {$cmd} did not take ***\n"
5593            if ($begdef =~ /\#$i/);
5594         &write_warnings("incomplete substitution in a {$cmd} environment:\n$begdef")
5595             if ($begdef =~ /\#$i/);
5596     }
5597     $begdef =~ s/$param_mark/\#/g;
5598     $begdef =~ s/$hash_mark/\\\#/g;
5599     $begdef =~ s/(\\\w+)$/$1 /s;
5601     # Make the body unique (Give unique id's to the brackets),
5602     # translate, and return it
5603 #RRM: when are these needed ?
5604 #    $_ = &revert_to_raw_tex($_);
5605 #    &pre_process;
5607     &make_unique($begdef);              # Make bracket IDs unique   
5608     print STDOUT "\nBEGIN:$cmd:$begdef" if ($VERBOSITY > 4);
5610     # Now substitute the \end part:
5611 #RRM: when are these needed ?
5612 #    $_ = &revert_to_raw_tex($enddef);
5613 #    &pre_process;
5615     &make_unique($enddef);              # Make bracket IDs unique
5616     print STDOUT "\nEND:$cmd:$enddef" if (($enddef)&&($VERBOSITY > 4));
5617     $enddef =~ s/(\\\w+)$/$1 /s;
5619     local($new_end_def_rx) = &make_end_env_rx($cmd);
5620     if (($enddef)&&!($after =~ s/\n?$new_end_def_rx/$enddef/ )) {
5621         $UNFINISHED_ENV = $new_end_def_rx;
5622         $REPLACE_END_ENV = $enddef;
5623     };
5624     join('',$begdef,$after);
5627 sub substitute_pars {
5628     s/((\%|$comment_mark\d*)|.)(\r*\n[ \t]*){2,}[ \t]*/$1\n\\par \n/og;
5629 #    s/((\%|$comment_mark\d*)|\d|.)[\r\n\015]{2,}/print "\nPAR:".$`.$&;"$1\n\\par \n"/egs;
5632 sub do_cmd_end { #RRM:  catches the end of any unclosed environments
5633     local($_) = @_;
5634     &missing_braces unless (
5635         (s/$next_pair_pr_rx//o)||(s/$next_pair_rx//o));
5636     s/^\n//;
5637     $_;
5640 # Removes the definition from the input string, 
5641 # adds to the preamble unless it is part of the preamble already
5642 # and stores the body in %new_command;
5643 sub get_body_newcommand {
5644     local($newed, $n_after) = &process_body_newcommand(0,@_);
5645     (($PREAMBLE)? "newed".$newed : '');
5648 sub process_body_newcommand {
5649 #    local($renewed,*_) = @_;
5650     local($renewed,$after_R) = @_;
5651     local($_) = $$after_R;
5652     local($no_change) = $_;
5653     local($argn,$newcmd,$cmd_br,$body,$body_br,$tmp,$tmp1,$opt,$pat);
5654     local($new_cmd) = 'command';
5655     if ($renewed =~ /provide/||$renewed == 2) {
5656         # $newcmd = &missing_braces unless (
5657         ($newcmd,$pat) = &get_next(1) unless (
5658                 (s/$next_pair_pr_rx/$pat=$&;$newcmd=$2;''/e)
5659                 ||(s/$next_pair_rx/$pat=$&;$newcmd=$2;''/e));
5660         if (!$pat) {
5661             local($br_id) = ++$global{'max_id'};
5662             $pat = "$O$br_id$C".$newcmd."$O$br_id$C";
5663         }
5664     } else {
5665         ($newcmd,$pat) = &get_next(1); # Get command name
5666     }
5667     $pat =~ s/\\//; $new_cmd .= $pat;
5668     $newcmd =~ s/^\s*\\//;
5669     ($argn,$pat) = &get_next(0);        # Get optional no. of args
5670     $argn = 0 unless $argn; $new_cmd .= $pat if $argn;
5671     local($cmd) = $newcmd;
5673     # Get the body of the code and store it with the name and number of args
5674     # UNLESS THE COMMAND IS ALREADY DEFINED
5675     # ...in which case $ALLOW_REDEFINE must also have been set.  # RRM
5676     # (This is the mechanism with which raw html can be ignored in a Latex document
5677     # but be recognised as such by the translator).
5678     $opt = '}';                 # Flag for no optional arg
5679     local($bodyA) = '';
5680     if (/^\[/) {
5681         ($opt,$pat) = &get_next(0);
5682         $new_cmd .= $pat;
5683         $bodyA .= "\n".'($dummy, $pat) = &get_next_optional_argument;' .
5684                     "\n". '$args .= $pat;';
5685     }
5686     local($nargs) = $argn;
5687     while ($nargs > 0) { $nargs--;
5688         $bodyA .=
5689             "\n".'$args .= $`.$& if ((s/$next_pair_pr_rx//o)||(s/$next_pair_rx//o));';
5690     }
5691     if ($renewed =~ /provide/||$renewed == 2 ) {
5692         $body = &missing_braces unless (
5693                 (s/$next_pair_pr_rx/$pat=$&;$body=$2;''/e)
5694                 ||(s/$next_pair_rx/$pat=$&;$body=$2;''/e));
5695         $new_cmd .= $pat;
5696     } else {
5697         ($body,$pat) = &get_next(4);  #get the body
5698         $new_cmd .= $pat;
5699     }
5701     local($thisone);
5702 #    $thisone = 1 if ($cmd =~ /div|vec/);  # for debugging
5704     $tmp = "do_cmd_$cmd";
5705     local($wtmp) = "wrap_cmd_$cmd";
5706     if ((defined &$tmp)||(defined &$wtmp)){
5707         # command already exists, so \providecommand  does nothing
5708         # but may still be needed in  images.tex
5709         $$after_R = $_;
5710         return ($new_cmd) if ($renewed =~ /provide/);
5712         print "\n*** redefining \\$cmd ***\n";
5713         &write_warnings("\nredefining command \\$cmd ");
5714         if (!$ALLOW_REDEFINE) {
5715             print "*** overriding previous meaning ***\n";
5716             &write_warnings("\nprevious meaning of \\$cmd will be lost");
5717         }
5718 #       local($code) = "undef \&$tmp"; eval ($code);
5719 #       if ($@) {print "\n*** undef \&$cmd failed \n"}
5720         if ((!$PREAMBLE)||($renewed>1)) {
5721             $new_command{$cmd} = join(':!:',$argn,$body,$opt);
5722 #           local($code) = "sub $tmp\{\&replace_new_command(\"$cmd\");\}";
5723 #           eval $code;
5724 #           print STDERR "\n*** sub do_cmd_$cmd failed:\nPERL: $@\n" if ($@);
5725 #           &replace_new_command($cmd);
5726         }
5728         $renew_command{$cmd} = 1;
5729         &write_mydb("renew_command", $cmd, $renew_command{$cmd});
5730         local($padding) = " ";
5731         $padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
5732         # Generate a new subroutine
5733         local($codeA) = "sub wrap_cmd_$cmd {" . "\n"
5734             .'local($cmd, $_) = @_; local ($args, $dummy, $pat) = "";'
5735             . $bodyA
5736             . (($thisone)? "\nprint \"\\nwrap $cmd:\".\$args.\"\\n\";" : '')
5737             . "\n".'(&make_deferred_wrapper(1).$cmd.'
5738             . "\"$padding\"".'.$args.&make_deferred_wrapper(0),$_)}'
5739             . "\n";
5740         print "\nWRAP_CMD: $codeA " if ($thisone); # for debugging
5741         eval $codeA;
5742         print STDERR "\n\n*** sub wrap_cmd_$cmd  failed: $@\n" if ($@);
5743         $raw_arg_cmds{$cmd} = 1;
5745     } elsif (($ALLOW_REDEFINE)&&($PREAMBLE < 2)) {
5746         print "\n*** redefining \\$cmd ***\n";
5747         &write_warnings("\ncommand \\$cmd had no previous definition")
5748             if (!($new_command{$cmd}));
5749     }
5750     if ($renewed && ($PREAMBLE > 1) &&($new_command{$cmd})) {
5751         $raw_arg_cmds{$cmd} = 1 ;
5752         $renew_command{$cmd} = 1;
5753         local($padding) = " ";
5754         $padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
5755         # Generate a new subroutine
5756         local($codeA) = "sub wrap_cmd_$cmd {" . "\n"
5757             .'local($cmd, $_) = @_; local ($args, $dummy, $pat) = "";'
5758             . $bodyA
5759             . (($thisone)? "\nprint \"\\nwrap $cmd:\".\$args.\"\\n\";" : '')
5760             . "\n".'(&make_deferred_wrapper(1).$cmd.'
5761             . "\"$padding\"".'.$args.&make_deferred_wrapper(0),$_)}'
5762             . "\n";
5763         print "\nWRAP_CMD: $codeA " if ($thisone); # for debugging
5764         eval $codeA;
5765         print STDERR "\n\n*** sub wrap_cmd_$cmd  failed: $@\n" if ($@);
5767         &write_mydb("renew_command", $cmd, $renew_command{$cmd});
5768     } elsif ($renewed) {
5769         $new_command{$cmd} = join(':!:',$argn,$body,$opt);
5770     } else {
5771         $new_command{$cmd} = join(':!:',$argn,$body,$opt)
5772             unless (($PREAMBLE > 1)&&($renew_command{$cmd}));
5773     }
5775     local($this_cmd);
5776     $this_cmd = join(''
5777         , "command{\\$cmd}"
5778         , ($argn ? "[$argn]" :'') 
5779         , (($opt =~ /^}$/) ? '' : "[$opt]" )
5780         , "{", $body , "}" );
5781     $this_cmd = &revert_to_raw_tex($this_cmd);
5782     if ($renewed) {
5783         if ($renewed=~/provide/){
5784             $provide_command{$cmd} = 1;
5785             &write_mydb("provide_command", $cmd, $provide_command{$cmd});
5786 #       } else {
5787 #           print "\n ** marking $cmd as renewed **";
5788 #           $renew_command{$cmd} = 1;
5789         };
5790         if ((!$PREAMBLE)&&($renewed>1)) {
5791 #           local($this_cmd) = join(''
5792 #               , "\n\\renewcommand{\\$cmd}"
5793 #               , ($argn ? "[$argn]" :'') 
5794 #               , (($opt =~ /^}$/) ? '' : "[$opt]" )
5795 #               , "{", $body , "}\n" );
5796 #           $latex_body .= &revert_to_raw_tex($this_cmd);
5797             $latex_body .= "\n\\renew". $this_cmd."\n";
5798         } else {
5799 ##          &add_to_preamble('command',"\\" . $this_cmd);
5800         }
5801     } else {
5802         &add_to_preamble('command',"\\new" . $this_cmd)
5803             unless ($PREAMBLE);
5804     }
5805     undef $body;
5806     if ($renewed == 2) {
5807         # there is no output to return
5808         $$after_R = $_;
5809         return();
5810     } 
5812     if (!$PREAMBLE) {
5813         $$after_R = $_;
5814         return ($new_cmd) if ($renewed);
5815 #           $cmd_br =~ s/\\//;
5816 #       ( join ('', &make_deferred_wrapper(1)
5817 #           , "\\". ($renewed ? (($renewed =~ /provide/)? 'provid' : 'renew')
5818 #               : 'new')."edcommand"
5819 #           , $cmd_br , ($argn ? "[$argn]" :'') 
5820 #           , ( ($opt =~ /^\}$/ ) ? '' : "[$opt]" ) , $body_br
5821 #           , &make_deferred_wrapper(0)) , $_ );
5822         $new_cmd = join('', "command{\\$cmd}"
5823                          , ($argn ? "[$argn]" :'') 
5824                          , (($opt =~ /^\}$/) ? '' : "[$opt]" )
5825                          , "{", $body , "}" );
5826         $new_cmd = &revert_to_raw_tex($new_cmd);
5827         &add_to_preamble('command', "\\provide".$new_cmd );
5828         $$after_R = $_;
5829         return();
5830     }
5831     $new_cmd =~ s/\\$cmd([\d\W]|$)/$cmd$1/s;
5832     $$after_R = $_;
5833     $new_cmd;
5836 sub replace_new_command {
5837     local($cmd) = @_;
5838     local($argn, $body, $opt) = split(/:!:/, $new_command{$cmd});
5839     do { ### local($_) = $body;
5840          &make_unique($body);
5841          } if ($body =~ /$O/);
5842     $body =~ s/(^|[^\\])\~/$1\\nobreakspace /g;
5843     if ($argn) {
5844         do { 
5845             local($before) = '';
5846             local($after) = "\\$cmd ".$_;
5847             $after = &substitute_newcmd;   # may change $after
5848             $after =~ s/\\\@#\@\@/\\/o ;
5849         };
5850     } elsif ($body =~ /\\/) {
5851         $body = &translate_commands($body);  # ???
5852         $_ = $body . $_;
5853     } else { $_ = $body . $_; }
5854     $_;
5857 sub get_body_let {
5858 #    local(*_) = @_;
5859     local($_) = @_;
5860     local($cmd,$body,$replace,$tmp,$pat);
5861     ($cmd,$body) = &get_next_tex_cmd;
5862     s/^\s*=?\s*/$body .= $&;''/e;
5863     ($replace,$pat) = &get_next_tex_cmd;
5864 #    return() if ($replace eq $cmd);
5865     $body .= $pat;
5866     $body = &revert_to_raw_tex($body);
5867     &add_to_preamble('', "\\let ".$body );
5868     $_[0] = $_;
5869     if (($replace eq $cmd)||($cmd="\\")||($cmd =~/(style|size)$/)) {
5870         "let ".$body
5871     } else {
5872         $new_command{$cmd} = join(':!:','',"\\$replace ",'}');
5873         '';
5874     }
5878 #  do not remove the \renewcommand code, since it may be needed
5879 #  within images. Instead replace it with \renewedcommand;
5880 #  This will be reverted in &revert_to_raw_tex
5881 sub get_body_renewcommand {
5882     local($ALLOW_REDEFINE) = 1;
5883     local($renew, $n_after) = &process_body_newcommand(1,@_);
5884     ($renew ? 'renewed' . $renew : '');
5887 sub do_cmd_renewedcommand {
5888     local($_) = @_;
5889     local($ALLOW_REDEFINE) = 1;
5890     &process_body_newcommand(2,\$_);
5891     $_ ;
5894 sub get_body_providecommand {
5895     local($provide, $n_after) = &process_body_newcommand('provide',@_);
5896     (($PREAMBLE && $provide) ? 'provided'.$provide : '');
5899 sub do_cmd_providedcommand{ &do_cmd_renewedcommand(@_) }
5901 sub get_body_DeclareRobustCommand {
5902     local($provide, $n_after) = &process_body_newcommand('provide',@_);
5903     (($PREAMBLE && $provide) ? 'provided'.$provide : '');
5906 sub get_body_DeclareMathOperator {
5907     local($after_R) = @_;
5908     local($_) = $$after_R;
5909     my $star;
5910     s/^\\DeclareMathOperator\s*(\*|star)/$star = $1;''/s;
5911     my ($mcmd,$patA) = &get_next(1);
5912     my ($mop,$patB) = &get_next(1);
5913     if ($star) {
5914         $patA .= "${O}0$C\\mathop${O}1$C\\mathrm${patB}${O}1$C${O}0$C".$_;
5915     } else {
5916         $patA .= "${O}0$C${O}1$C\\mathrm${patB}${O}1$C${O}0$C".$_;
5917     }
5918     local($provide, $n_after) = &process_body_newcommand('provide',\$patA);
5919     $$after_R = $patA;
5920     (($PREAMBLE && $provide) ? 'provided'.$provide : '');
5923 sub get_body_DeclareMathOperatorstar {
5924     local($after_R) = @_;
5925     local($_) = $$after_R;
5926     my $star;
5927     s/^\\DeclareMathOperator\s*(\*|star)/$star = $1;''/s;
5928     my ($mcmd,$patA) = &get_next(1);
5929     my ($mop,$patB) = &get_next(1);
5930     $patA .= "${O}0$C\\mathop${O}1$C\\mathrm${patB}${O}1$C${O}0$C".$_;
5931     local($provide, $n_after) = &process_body_newcommand('provide',\$patA);
5932     $$after_R = $patA;
5933     (($PREAMBLE && $provide) ? 'provided'.$provide : '');
5937 # Removes the definition from the input string, adds to the preamble
5938 # and stores the body in %new_environment;
5939 sub get_body_newenvironment {
5940     local($newed,$after) = &process_body_newenvironment(0,@_);
5941     ( $PREAMBLE ? "newed".$newed : '');
5944 sub process_body_newenvironment {
5945 #    local($renew,*_) = @_;
5946     local($renew,$after_R) = @_;
5947     local($_) = $$after_R;
5948     local($no_change) = $_;
5949     local($argn,$env,$begin,$end,$tmp,$opt,$pat);
5950     local($new_env) = 'environment';
5951     if ($renew == 2) {
5952         $env = &missing_braces unless (
5953                 (s/$next_pair_pr_rx/$pat=$&;$env=$2;''/e)
5954                 ||(s/$next_pair_rx/$pat=$&;$env=$2;''/e));
5955         $new_env .= $pat;
5956     } else {
5957         ($env,$pat) = &get_next(1);     # Get the environment name
5958         $env =~ s/^\s*\\//; $new_env .= $pat;
5959     }
5960     ($argn,$pat) = &get_next(0);        # Get optional no. of args
5961     $argn = 0 unless $argn; $new_env .= $pat if $argn;
5963     # Get the body of the code and store it with the name and number of args
5964     # UNLESS THE COMMAND IS ALREADY DEFINED (see get_body_newcommand)
5965     # ...in which case $ALLOW_REDEFINE must also have been set.  # RRM
5966     $opt = '}';                 # Flag for no optional arg
5967     if (/^\[/) {
5968         ($opt,$pat) = &get_next(0);
5969         $new_env .= $pat;
5970     }
5971     $tmp = "do_env_$env";
5973     if ($renewed == 2 ) {
5974         $begin = &missing_braces unless (
5975                 (s/$next_pair_pr_rx/$pat=$&;$begin=$2;''/e)
5976                 ||(s/$next_pair_rx/$pat=$&;$begin=$2;''/e));
5977         $new_env .= $pat;
5978         $end = &missing_braces unless (
5979                 (s/$next_pair_pr_rx/$pat=$&;$end=$2;''/e)
5980                 ||(s/$next_pair_rx/$pat=$&;$end=$2;''/e));
5981         $new_env .= $pat;
5982     } else {
5983         ($begin,$pat) = &get_next(1); $new_env .= $pat;
5984         ($end,$pat) = &get_next(1); $new_env .= $pat;
5985     }
5986     if ((defined &$tmp)&&($ALLOW_REDEFINE)) {
5987         print STDOUT "\n*** redefining environment {$env} ***\n";
5988         &write_warnings("\nredefined environment {$env} ");
5989     }
5990     $new_environment{$env} = join(':!:', $argn, $begin, $end, $opt)
5991         unless ((defined &$tmp)&&(! $ALLOW_REDEFINE));
5993     if (!$PREAMBLE) {
5994         $new_env = join ('', 
5995             , "environment{$env}" 
5996             , ($argn ? "[$argn]" : '')
5997             , (($opt ne '}')? "[$opt]" : '')
5998             , "{$begin}{$end}"
5999             );
6000         &revert_to_raw_tex($new_env);
6001         if ($renew == 2) {
6002             $latex_body .= "\n\\".($renew ? 're':'').'new'.$new_env."\n";
6003         } else {
6004             &add_to_preamble ('environment'
6005                 , "\\".($renew ? 're':'').'new'.$new_env );
6006         }
6007         $$after_R = $_;
6008         return();
6009     }
6010     if ($new_env =~ /$sections_rx/) {
6011         $new_env = join('', $`,'\csname ',$2,'\endcsname',$3,$');
6012     }
6013     $new_env =~ s/$par_rx/\\par /g;
6014     $$after_R = $_;
6015     $new_env;
6018 sub get_body_renewenvironment {
6019     local($ALLOW_REDEFINE) = 1;
6020     local($renewed, $after) = &process_body_newenvironment(1,@_);
6021     'renewed'.$renewed;
6024 sub do_cmd_renewedenvironment {
6025     local($ALLOW_REDEFINE) = 1;
6026     local($_) = @_;
6027     &process_body_newenvironment(2,\$_);
6028     $_;
6031 # Instead of substituting as with newcommand and newenvironment,
6032 # or generating code to handle each new theorem environment,
6033 # it now does nothing. This forces theorem environments to be passed
6034 # to latex. Although it would be possible to handle theorem
6035 # formatting in HTML as it was done previously it is impossible
6036 # to keep the theorem counters in step with other counters (e.g. equations)
6037 # to which only latex has access to. Sad...
6038 sub get_body_newtheorem {
6039 #    local(*_) = @_;
6040     local($after_R) = @_;
6041     local($_) = $$after_R;
6042     my ($orig, $body) = ($_, '');
6043     my ($title, $env, $ctr, $within, $cmd, $tmp, $begin, $end, $pat);
6044     my ($new_thm) = 'theorem';
6045     # Just chop off the arguments and append to $next_def
6046     ($env,$pat) = &get_next(1); $new_thm .= $pat;
6047     ($ctr,$pat) = &get_next(0); $new_thm .= $pat;
6048     ($title,$pat) = &get_next(1); $new_thm .= $pat;
6049     ($within,$pat) = &get_next(0); $new_thm .= $pat;
6051     #check the style parameters
6052     my ($hfont,$bfont,$thm_style);
6053     my ($before_thm) = join('',@processed);
6054     my ($which,$cmds);
6055     while ($before_thm =~ /$theorem_cmd_rx/) {
6056         $which = $1;
6057         $before_thm = $';
6058         $before_thm =~ s/$next_pair_rx/$cmds = $2;''/e;
6059         $cmds =~ s/\\/\|/g;  # escape any backslash
6060         if ($which =~ /style/) { $thm_style = $cmds }
6061         elsif ($which =~ /header/) { $hfont = $cmds }
6062         elsif ($which =~ /body/)   { $bfont = $cmds }
6063     }
6064     $hfont = '['.$hfont.']';
6065     $bfont = '['.$bfont.']';
6066     $thm_style = '['.$thm_style.']';
6067     undef $before_thm;
6069     if (!($ctr)) {
6070         # define the new counter
6071         $ctr = $env;
6072         do {
6073 ###         local($_) = "\\arabic<<1>>$ctr<<1>>";
6074 ###         $_ = join('',"\\the$within", "." , $_) if ($within);
6075             $body = "\\arabic<<1>>$ctr<<1>>";
6076             $body = join('',"\\the$within", "." , $body) if ($within);
6077             &make_unique($body);
6078             $cmd = "the$ctr";
6079             $tmp = "do_cmd_$cmd";
6080             do {
6081                 $new_command{$cmd} = join(':!:',0,$body,'}') 
6082             } unless (defined &$tmp);
6083             &write_mydb("new_command", $cmd, $new_command{$cmd});
6084             eval "sub do_cmd_$cmd {\n"
6085                 . 'local($_,$ot) = @_;'."\n"
6086                 . 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'."\n"
6087                 . '&translate_commands(' . "\"$body\"" . ");\n}\n";
6088             print STDERR "\n*** sub $tmp failed:\n$@\n" if ($@);
6089             $raw_arg_cmds{$cmd} = 1;
6090             undef $body;
6091         };
6092         &do_body_newcounter($ctr);
6093     } else {
6094         do {
6095 ###         local($_) = "\\arabic<<1>>$ctr<<1>>";
6096             $body = "\\arabic<<1>>$ctr<<1>>";
6097             &make_unique($body);
6098             $cmd = "the$env";
6099             $tmp = "do_cmd_$cmd";
6100             do {
6101                 $new_command{$cmd} = join(':!:',0,$body,'}') 
6102             } unless (defined &$tmp);
6103             &write_mydb("new_command", $cmd, $new_command{$cmd});
6104             eval "sub do_cmd_$cmd {\n"
6105                 . 'local($_,$ot) = @_;'
6106                 . 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'
6107                 . '&translate_commands(' . "\"$body\"" . ");\n}\n";
6108             print STDERR "\n*** sub $tmp failed:\n$@\n" if ($@);
6109             $raw_arg_cmds{$cmd} = 1;
6110             undef $body;
6111         };
6112     }
6114     # record the counter dependency
6115     &addto_dependents($within,$ctr) if ($within);
6117     # save the text-label in the %new_theorem hash
6118     $new_theorem{$env} = $title;
6120     # define a new environment
6121     my ($id) = ++$global{'max_id'};
6122     $begin = "\\begin<<$id>>theorem_type<<$id>>"
6123         . "[$env][$ctr][$within]$thm_style$hfont$bfont\n";
6124     $id = ++$global{'max_id'};
6125     $end = "\\end<<$id>>theorem_type<<$id>>\n";
6126     $tmp = "do_env_$env";
6127     if ((defined &$tmp)&&($ALLOW_REDEFINE)) {
6128         print STDOUT "\n*** redefining theorem environment {$env} ***\n";
6129     }
6130     $new_environment{$env} = join(':!:', '', $begin, $end, '')
6131         unless ((defined &$tmp)&&(! $ALLOW_REDEFINE));
6133     if (!$PREAMBLE) {
6134         my ($new_cmd) = join(''
6135             , 'theorem{}' );
6136         &add_to_preamble('theorem', "\\new".$new_cmd );
6137         $$after_R = $_;
6138         return();
6139     }
6140     $$after_R = $_;
6141     'newed'.$new_thm;
6144 sub do_cmd_theoremstyle {
6145     local($_) = @_;
6146     local($thm_type);
6147     $thm_type = &missing_braces unless (
6148         (s/$next_pair_pr_rx/$thm_type=$2;''/e)
6149         ||(s/$next_pair_rx/$thm_type=$2;''/e));
6150 #   $THM_STYLE = $thm_type;
6151     $_;
6153 sub do_cmd_theoremheaderfont {
6154     local($_) = @_;
6155     local($thm_type);
6156     $thm_type = &missing_braces unless (
6157         (s/$next_pair_pr_rx/$thm_type=$2;''/e)
6158         ||(s/$next_pair_rx/$thm_type=$2;''/e));
6159 #   $THM_HFONT = $thm_type;
6160     $_;
6162 sub do_cmd_theorembodyfont {
6163     local($_) = @_;
6164     local($thm_type);
6165     $thm_type = &missing_braces unless (
6166         (s/$next_pair_pr_rx/$thm_type=$2;''/e)
6167         ||(s/$next_pair_rx/$thm_type=$2;''/e));
6168 #   $THM_BFONT = $thm_type;
6169     $_;
6172 sub do_env_theorem_type {
6173     local($_) = @_;
6174     local($dum,$env,$ctr,$within, $label, $name, $title, $text, $index);
6175     ($env, $dum) = &get_next_optional_argument;
6176     ($ctr, $dum) = &get_next_optional_argument;
6177     ($within, $dum) = &get_next_optional_argument;
6179     local($thm_num, $thm_style);
6180     # defaults for plain theorem-style
6181     my ($hfont,$bfont) = ('','');
6183     ($thm_style, $dum) = &get_next_optional_argument;
6184     ($hfont, $dum) = &get_next_optional_argument;
6185     $hfont =~ s/\|/\\/og;
6186     ($bfont, $dum) = &get_next_optional_argument;
6187     $bfont =~ s/\|/\\/og;
6189     # the pre-defined alternative theorem-styles
6190     if ($thm_style =~ /definition/) {
6191         $bfont = '\normalfont' unless $bfont;
6192     } elsif ($thm_style =~ /remark/) {
6193         $hfont = '\itshape' unless $hfont;
6194         $bfont = '\normalfont' unless $bfont;
6195     }
6197     # defaults for plain theorem-style
6198     $hfont = '\bfseries' unless $hfont;
6199     $bfont = '\itshape' unless $bfont;
6201     ($name, $dum) = &get_next_optional_argument;
6202     $name = &translate_environments("${O}0$C".$name."${O}0$C") if $name;
6203     $name = &translate_commands($name) if ($name =~ /\\/);
6205     $index = $section_commands{$ctr};
6206     if ($index) { 
6207         # environment actually starts a new (sub-)section
6208         $curr_sec_id[$index]++;
6209         local($this) = &translate_commands("\\the$ctr");
6210         local($hash) = &sanitize($name." $this");
6211         local($section_tag) = join('', @curr_sec_id);
6212         $encoded_section_number{$hash} = join($;, $section_tag);
6213         &reset_dependents($ctr) if ($dependent{$ctr});
6214         $thm_num = &translate_commands("\\the$ctr");
6215         $thm_num =~ s/(\w)\.(\.\w)/$1$2/g;
6217         # construct the sectioning title from the counter values
6218         $title = join( '', $new_theorem{$env}, " "
6219             , &translate_commands("\\the$ctr") );
6220         $toc_section_info{join(' ',@curr_sec_id)} = \
6221             "$current_depth$delim$CURRENT_FILE$delim$title"
6222                 if ($current_depth <= $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH);
6223         $section_info{join(' ',@curr_sec_id)} = \
6224             "$current_depth$delim$CURRENT_FILE$delim$title$delim";
6225         $title = join('',"<A NAME=\"SECTION$section_tag\"><B>"
6226                       , $title , "</B></A>" );
6227     } else {
6228         if ($ctr) {
6229             print STDOUT "\nSTP:$ctr:+1" if ($VERBOSITY > 3);
6230             $global{$ctr}++;
6231             print STDOUT "=".$global{$ctr}." " if ($VERBOSITY > 3);
6232             &reset_dependents($ctr) if ($dependent{$ctr});
6233             $thm_num = "\\the$ctr ";
6234         } else { $thm_num = ''; }
6236         # construct the full title from the counter values
6237         $title = $new_theorem{$env};
6238         if (($thm_style =~ /margin/)&&($HTML_VERSION > 2.1)) {
6239             # don't use the number yet
6240         } elsif ($thm_style =~ /change/) {
6241             $title = join(' ', $thm_num, "\\space", $title)
6242         } else {
6243             $title = join(' ', $title, "\\space", $thm_num);
6244         }
6246         if ($hfont) {
6247             $title = join('',$O,++$global{'max_id'},$C,$hfont," "
6248                       , $title, $O,++$global{'max_id'},$C);
6249             $title = &translate_environments($title);
6250             $title = &translate_commands($title);
6251         } else {
6252             $title = join('',"<B>",&translate_commands($title),"</B>");
6253         }
6254         $title =~ s/(\w)\.(\.\w)/$1$2/g;
6255     }
6256     # extract any name or label that may occur at the start
6257     s/^\s*(\\label(($O|$OP)\d+($C|$CP))([^<]*)\2)?\s*(\(([^\)]*)\))?/
6258         $label=$1; $text=$5; $name=$7 if ($7); ''/eo;
6259     if ($label) {
6260         $label = &anchor_label($text,$CURRENT_FILE,'');
6261         $label =~ s/$anchor_mark/$title/;
6262         $title = $label;
6263     }
6264     if ($name) {
6265         $name =~ s/^\s*|\s*$//g; 
6266         $name = join('', " (", $name, ") ") if $name;
6267     }
6268     local($attribs, $border);
6269     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
6270     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
6272     $_ = join('', $O,++$global{'max_id'},$C, $bfont
6273             , " ", $_ ,$O,++$global{'max_id'},$C) if ($bfont);
6275     my($cmd) = 'do_thm_'.$env;
6276     if (defined &$cmd) {
6277         $_ = &$cmd($ctr, $title, $_);
6278     } else {
6279         $_ = &translate_environments($_);
6280         $_ = &translate_commands($_);
6281     }
6283     if ($thm_style =~ /margin/) {
6284         local($valign);
6285         $valign = ($NETSCAPE_HTML ? ' VALIGN="BASELINE"':'');
6286         if ($hfont) {
6287             $thm_num = join('',$O,++$global{'max_id'},$C,$hfont," "
6288                       , $thm_num, $O,++$global{'max_id'},$C);
6289             $thm_num = &translate_environments($thm_num);
6290             $thm_num = &translate_commands($thm_num);
6291         } else {
6292             $thm_num = join('',"<B>",&translate_commands($thm_num),"</B>");
6293         }
6294         $thm_num =~ s/(\w)\.(\.\w)/$1$2/g;
6296         # code copied from  &make_table
6297         local($Tattribs);
6298         if ($attribs) {
6299             if (!($attribs =~ /=/)) {
6300                 $Tattribs = &parse_valuesonly($attribs,"TABLE");
6301             } else {
6302                 $Tattribs = &parse_keyvalues($attribs,"TABLE");
6303             }
6304             $Tattribs = ' '.$Tattribs if ($Tattribs);
6305         }
6306         $_ = join ('', "\n<P><DIV$env_id><TABLE"
6307                 , (($border) ? " BORDER=\"$border\"" : '')
6308                 , $Tattribs , ">\n<TR VALIGN=\"TOP\">"
6309                 , "<TD$valign>", &translate_commands($thm_num)
6310                 , "</TD>\n<TD>", $title, $name
6311                 , (($thm_style =~ /break/)? "\n<BR>":" \&nbsp; \n")
6312                 , $_ , "\n</TD></TR></TABLE></DIV>");
6313     } else {
6314         $_ = join('', "<P><DIV$env_id>"
6315                 , $title, $name
6316                 , (($thm_style =~ /break/)? "\n<BR>":" \&nbsp; \n")
6317                 , $_
6318                 ,"</DIV><P></P>\n");
6319         if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
6320             &make_table( $border, $attribs, '', '', '', $_ ) 
6321         } else { $_ }
6322     }
6325 # Modifies $_ in the caller and as a side-effect it modifies $next_def
6326 # which is local to substitute_meta_cmds
6327 sub get_next {
6328     local($what) = @_;
6329     local($next, $pat, $tmp);
6330     if ($what == 1) {
6331         ($next, $tmp, $pat) = &get_next_argument;
6332     }
6333     elsif ($what == 2) {
6334         ($next, $pat) = &get_next_tex_cmd;
6335     }
6336     elsif ($what == 3) {
6337         ($next, $pat) = &get_next_def_arg;
6338     }
6339     elsif ($what == 4) {
6340         ($next, $tmp, $pat) = &get_next_argument;
6341     }
6342     else {
6343         ($next, $pat) =  &get_next_optional_argument;
6344     }
6345     do {
6346         $next_def .= &revert_to_raw_tex($pat) if $pat;
6347     } unless ($renewed); # don't add \renewcommand to preamble
6348 #    $next =~ s/(^\s*)|(\s*$)//g unless ($what == 4); #don't lose white space on body
6349     $next =~ s/(^\s*)|(\s*$)//g unless ($what =~ /[14]/); #retain white space in body
6350     ($next, $pat);
6353 # The following get_next_<something> ARE ALL DESTRUCTIVE.
6354 sub get_next_argument {
6355     local($next, $br_id, $pat);
6356     if (!(s/$next_pair_rx/$br_id=$1;$next=$2;$pat=$&;''/seo)) {
6357         print " *** Could not find argument for command \\$cmd ***\n";
6358         print "$_\n";
6359     };
6360     ($next, $br_id, $pat);
6363 sub get_next_pair_or_char_pr {
6364     local($next, $br_id, $pat, $epat);
6365     if ( /^\{([^\}]*)\}/o && (! $`)) {
6366         ($next, $pat) = ($1, $&);
6367     } elsif ( (/^\s*([^\s\\<])/o && (! $`))) {
6368         ($next, $pat) = ($1, $&);
6369     } elsif ( /$next_pair_pr_rx/o && (! $`)) {
6370         ($next, $br_id, $pat) = ($2, $1, $&);
6371     };
6372     $epat = &escape_rx_chars($pat);
6373     s/$epat// if $pat;
6374     ($next, $br_id, $pat);
6377 sub get_next_optional_argument {
6378     local($next, $pat);
6379     s/$optional_arg_rx/$next=$1;$pat=$&;''/eo
6380         if (/\s*[[]/ && (! $`)); # if the first character is a [
6381     #remove trailing spaces and/or comments
6382     s/^($comment_mark(\d+\n?)?|$EOL)//gos;
6384     # if  nested inside {}s  we need to get more tokens  
6385     if ($pat) {
6386         # check for \item, indicating something has gone wrong
6387         if ($pat =~ /\\item\b/ ) {
6388             print "\n*** optional argument badly formed:\n" . $pat . "\n\n";
6389             $_ = $pat . $_;
6390             return('','');
6391         }
6392         # check for being nested inside {}s
6393         local($found) = $pat;
6394         while ($found =~ s/$O(\d+)$C[\s\S]*$O\1$C//g) {
6395             if ($found =~ /$O(\d+)$C/) {
6396                 local($br_id) = $1;
6397                 if (s/$O$br_id$C//) {
6398                     $found .= $`.$&;
6399                     $pat .= "]".$`.$&;
6400                     $next .= "]".$`.$&;
6401                     $_ = $';
6402                     s/^([^]]*)\]/$next.=$1;$pat.=$&;''/e;
6403                     $found .= $&;
6404                 } else { last } # give up if no closing brace
6405             }
6406         }
6407     } else {
6408         s/^\s*\[\]/$pat=$&;''/e; # This is not picked by $optional_arg_rx
6409     }
6410     ($next, $pat);
6413 #JCL(jcl-del) - use new form of $single_cmd_rx.
6414 sub get_next_tex_cmd {
6415     local($next, $pat);
6416     s/^\s*\=?\s*$single_cmd_rx/$4/;
6417     ($next, $pat) = ($1.$2,"\\".$1.$2);
6420 sub get_next_def_arg {
6421     local($next, $pat);
6423     # Sets is_simple_def for caller.  Start by turning it off, then
6424     # turn it on if we find one of the "simple" patterns.
6426     # This has got to be hit-or-miss to an extent, given the
6427     # thoroughly incestuous relationship between the TeX macroprocessor
6428     # ('mouth') and typesetting back-end ('stomach').  Anything which
6429     # even does catcode hacking is going to lose BAD.
6431     s/^\s*//so;                 # Remove whitespace
6433     $is_simple_def = 0;
6435     # no arguments
6437     if (/^$O/ && (! $`)) { $next=0; $pat=''; $is_simple_def=1; }
6439     # 'simple' arguments
6441     if (! $is_simple_def && /$tex_def_arg_rx/o && (! $`)) {
6442         s/$tex_def_arg_rx/$next=$1; $pat=$&; $is_simple_def=1; $2/seo; }
6444     # MESSY arguments
6446     if (! $is_simple_def) {
6447         print "Arguments to $cmd are too complex ...\n";
6448         print "It will not be processed unless used in another environment\n";
6449         print "which is passed to LaTeX whole for processing.\n";
6451         s/^[^<]*(<[^<]+)*<</$next=''; $pat=$&; $O/seo;
6452     }
6454     $pat =~ s/$O$//so;
6456     ($next, $pat);
6459 #### Key-value parsing added by RRM
6461 #   This cleans-up the key-value pairs for a given tag, 
6462 #   by removing unnecessary spaces and commas, inserting quotes
6463 #   around the value and puts a preceding space.
6464 #   The key becomes upper-case, while the value becomes lower-case.
6465 #   If specific `tags' are provided, then checking is done to verify 
6466 #   that the keys and values are valid for these tags, eliminating
6467 #   any that are not; unmatched keys or values are handled as well.
6468 #   If no tags are provided, then just a list of pairs is returned.
6470 sub parse_keyvalues {
6471     local($_,@tags) = @_;
6472     local($key,$KEY,$attribs,$atts,%attributes)=('','','','');
6474     # beware active " in german
6475     local($is_german);
6476     if (s/\&#34;/'/g) { 
6477         $is_german=1;
6478         s/(^|[\s,=])(\&\#\d\d\d;)/$1'$2/g
6479     }
6480     local($saved) = &revert_to_raw_tex(&translate_commands($_));
6481     print "\nATTRIBS: $saved\n" if ($VERBOSITY > 6);
6483     $saved =~ s/$percent_mark/%/g;
6484     $saved =~ s/((^|[\s,=])')\\\W{(\w)}/$1$3/g
6485         if $is_german;  #unwanted accents, from active "
6486     if (@tags) {
6487         foreach $tag (@tags) {
6488             $_ = $saved;
6489             local($name)= $tag."_attribs";
6490             $taglist = $$name;
6491             $name .= "_rx_list";
6492             $taglist .= $$name;
6493             $taglist =~ s/,,/,/;
6494 #           s/(^|,)\s*([a-zA-Z]+)\s*\=\s*"?([\#\%\w\d]+)"?\s*/$attributes{$2}="$3";''/eg;
6495 #           s/(^|,)\s*([a-zA-Z]+)\s*\=\s*(\"([^"]*)\"|\'([^\']*)\'|([#%\w\d]*))\s*/
6496 #           s/(^|,)\s*([a-zA-Z]+)\s*\=\s*(\"([^"]*)\"|\'([^\']*)\'|([#%&@;:+-\/\w\d]*))\s*/
6497             s/(^|,)\s*([a-zA-Z]+)\s*\=\s*(\"([^"]*)\"|\'([^\']*)\'|([^<>,=\s]*))\s*/
6498                 $attributes{$2}=($4?$4:($5?$5:$6));' '/eg;
6499             foreach $key (keys %attributes){ 
6500                 $KEY = $key;
6501                 $KEY =~ tr/a-z/A-Z/;
6502                 if ($taglist =~ /,$KEY,/i) {            
6503                     local($keyname) = $tag."__".$KEY; 
6504                     local($keyvalues) = '';
6505                     if ($$keyname) {
6506                         $keyvalues = $$keyname;
6507                         $atts = $attributes{$key};
6508                         if ($keyvalues =~ /\,$atts\,/i ) {
6509 #                           $atts =~ tr/A-Z/a-z/;
6510                             $attribs .= " $KEY=\"$atts\"";
6511                             print "\n$KEY=$atts " if ($VERBOSITY > 3);
6512                         } else { &invalid_tag($tag,$KEY,$atts); }
6513                     } else {    # test for a regular expression
6514                         $keyname = $keyname."_rx";
6515                         if ($$keyname) {
6516                             $keyvalues = $$keyname;
6517                             $atts = $attributes{$key};
6518                             if ($atts =~ /$keyvalues/) {
6519 #                               $atts =~ tr/A-Z/a-z/;
6520                                 $attribs .= " $KEY=\"$atts\"";                          
6521                                 print "\n$KEY=$atts " if ($VERBOSITY > 3);
6522                             } else { &invalid_tag($tag,$KEY,$atts) }
6523                         } else {
6524                             $atts = $attributes{$key};
6525 #                           $atts =~ tr/A-Z/a-z/;
6526                             $attribs .= " $KEY=\"$atts\"";
6527                             print "\n$KEY=$atts " if ($VERBOSITY > 3);
6528                         }
6529                     }
6530                 } else {
6531                     print "\n$key not in $taglist for $tag" if ($VERBOSITY > 3);
6532                 }
6533             }
6534         }
6535         s/(^|\s,)\'([^\s,]*)\'(\s|$)/$1$2 /g if $is_german;
6536         $attribs .= &parse_valuesonly($_,@tags);
6537     } else {
6538         # with no tags provided, just list the key-value pairs
6539         $_ = $saved;
6540         s/\s*(\w+)\s*=\s*\"?(\w+)\"?\s*,?/$attributes{$1}=$2;''/eg;
6541         foreach $key (keys %attributes){ 
6542             $KEY = $key;
6543             $KEY =~ tr/a-z/A-Z/;
6544             $atts = $attributes{$key};
6545             $atts =~ tr/A-Z/a-z/;
6546             $attribs .= " $KEY=\"$atts\"";
6547         }
6548     }
6549     $attribs;
6552 sub invalid_tag {
6553     local($tag,$key,$value) = @_;
6554     &write_warnings("$key=$value is an invalid value in the <$tag> tag\n");
6557 # RRM
6558 #   This creates key-value pairs from values only, 
6559 #   by checking whether the data matches any key to the provided tags.
6560 #   Only the first match found is retained.
6561 #   Attributes with no values are also recognised here.
6563 sub parse_valuesonly {
6564     local($values,@tags) = @_;
6565     local($i,$tag,$key,$KEY,$attribs,$atts)=(0,'','','','','');
6566     local($saved) = &revert_to_raw_tex(&translate_commands($values));
6567     $saved =~ s/$percent_mark/%/g;
6568     foreach $tag (@tags) {
6569         local($name)= $tag."_attribs";
6570         $taglist = $$name;
6571         $values = $saved;
6572         $values =~ s/\s*\"?([^,\s\"]+)\"?\s*,?/$i++;$attributes{$i}=$1;''/eg;
6573         local($j) = 0;
6574         while ($j < $i) {
6575             $j++;
6576             $key = $attributes{$j};
6577             if ($taglist =~ /,$key,/i) {
6578                 $KEY = $key;
6579                 $KEY =~ tr/a-z/A-Z/;
6580                 $attribs .= " $KEY";
6581                 print " $KEY" if ($VERBOSITY > 3);
6582             } else {
6583                 $atts = $attributes{$j};
6584                 $key = &find_attribute($key,$tag);
6585                 if ($key) {
6586                     $KEY = $key;
6587                     $KEY =~ tr/a-z/A-Z/;
6588                     $atts =~ tr/A-Z/a-z/;
6589                     $attribs .= " $KEY=\"$atts\"";
6590                     print " $KEY = $atts" if ($VERBOSITY > 3);
6591                 } else { }
6592             }
6593         }
6594     }
6595     $attribs;
6598 # RRM
6599 #   Extracts key-value pairs using a supplied (comma-separated) list.
6600 #   When no list is given, it checks for a pre-defined list for the tag.
6601 #   
6602 sub extract_attributes {
6603     local($tag,$taglist,$_) = @_;
6604     local($key,$attribs,$unused,%attributes);
6605     if (! ($taglist)) {
6606         local($name) = "$tag"."_attribs";
6607         if ($$name) { $taglist = $$name }
6608     }
6609     s/\s*(\w+)\s*=\s*\"?(\w+)\"?\s*,?/$attributes{$1}=$2;''/eg;
6610     foreach $key (keys %attributes){ 
6611         if ($taglist =~ /\,$key\,/) {
6612             $attribs .= " $key=\"$attributes{$key}\"";
6613             &write_warnings("valid attribute $key for $tag\n");
6614         } else {
6615             &write_warnings("unknown attribute $key for $tag\n");
6616             $unused .= " $key=\"$attributes{$key}\"";
6617         }
6618     }
6619     ($attribs,$unused);
6622 # RRM
6623 #   Finds the attribute of a given tag, for which a given value is valid.
6624 #   Requires variables: <tag>_<key> to be a comma-separated list of keys.
6625 #   So far it cannot recognise data-types, only names.
6627 sub find_attribute {
6628     local($key,$attrib,$tag) = ('',@_);
6629     local($name) = $tag."_attribs";
6630     local($attrib_list)=$$name;
6631     if ($attrib_list) {
6632         $attrib_list =~ s/^\,//o;
6633         $attrib_list =~ s/\,$//o;
6634         local(@keys) = split(',',$attrib_list);
6635         local($attrib_vals) = '';
6636         foreach $key (@keys) {
6637             $name = $tag."__".$key;
6638             $attrib_vals = $$name;
6639             return ($key) if ($attrib_vals =~ /\,$attrib\,/i ); 
6640         }
6641     }
6642     $name = $tag."_attribs_rx_list";
6643     $attrib_list=$$name;
6644     if (!($attrib_list)) { return(); }
6645     $attrib_list =~ s/^\,//o;
6646     $attrib_list =~ s/\,$//o;
6647     @keys = split(',',$attrib_list);
6648     foreach $key (@keys) {
6649         next if ($attribs =~ / $key=/);
6650         $name = $tag."__".$key."_rx";
6651         $attrib_vals = $$name;
6652         if ( $attrib =~ /^$attrib_vals$/ ) { 
6653             return ($key);
6654         }
6655     }
6656     0;
6659 # in case \HTML is defined differently in packages
6660 sub do_cmd_HTML { &do_cmd_HTMLcode(@_) }
6662 sub do_cmd_HTMLcode {
6663     local($_) = @_;
6664     local($tag,$attribs,$dum);
6665     local($attribs, $dum) = &get_next_optional_argument;
6666     $tag = &missing_braces unless (
6667         (s/$next_pair_pr_rx/$tag = $2;''/eo)
6668         ||(s/$next_pair_rx/$tag = $2;''/eo));
6669     $tag = &translate_commands($tag) if ($tag =~ /\\/);
6670     if (! $tag) {
6671         print "*** no tag given with \\HTML command, ignoring it";
6672         return($_);
6673     }
6674     local($afterHTML) = $_;
6675     local($value,$TAGattribs,$etag);
6676     if (defined $unclosed_tags_list{$tag}) {
6677     } elsif (defined $closed_tags_list{$tag}) {
6678         $value = &missing_braces unless (
6679             (s/$next_pair_pr_rx/$value = $2;''/eo)
6680             ||(s/$next_pair_rx/$value = $2;''/eo));
6681         $etag = "</$tag>";
6682         $afterHTML = $_;
6683     } else {
6684         print "\n*** <$tag> is not a valid tag for HTML $HTML_VERSION";
6685         print "\n rejecting: \\HTML".(($attribs)? "[$attribs]" : '')."{$tag}";
6686         return $_ ;
6687     }
6688     if ($dum) {
6689         $attribs = &translate_commands($attribs) if ($attribs=~/\\/);
6690         if ($attribs) {
6691             if (!($attribs =~ /=/)) {
6692                 $TAGattribs = &parse_valuesonly($attribs,$tag);
6693             } else {
6694                 $TAGattribs = &parse_keyvalues($attribs,$tag);
6695             }
6696         }
6697     } else { }  # default if no [...]
6698     local($needed) = join(','
6699             , $closed_tags_list{$tag},$unclosed_tags_list{$tag});
6700     $needed =~ s/,,/,/g; $needed =~ s/^,|,$//g;
6701     if ($TAGattribs) {
6702         if ($needed) {
6703             $needed =~ s/,,/,/g;
6704             local($this, @needed);
6705             (@needed) = split(',',$needed);
6706             foreach $this (@needed) {
6707                 next unless ($this);
6708                 next if ($TAGattribs =~ /\b$this\b/);
6709                 print "\n*** attribute $this required for <$tag> ***";
6710                 print "\n rejecting: \\HTML".(($attribs)? "[$attribs]" : '')."{$tag}";
6711                 return($value.$afterHTML);
6712             }
6713         }
6714         $value = &translate_environments($value);
6715         $value = &translate_commands($value) if ($value =~ /\\/);
6716         $_ = join('', "<$tag", $TAGattribs, ">", $value, $etag);
6717    } elsif ($needed) {
6718         print STDOUT "\n*** attributes $needed are required for <$tag> ***";
6719         return($value.$after);
6720     } elsif ($value) {
6721         $value = &translate_environments($value);
6722         $value = &translate_commands($value) if ($value =~ /\\/);
6723         $_ = join('', "<$tag>", $value, $etag);
6724     } else {
6725         $_ = join('', "<$tag>", $etag);
6726     }
6727     $_.$afterHTML; 
6730 sub do_cmd_HTMLget {
6731     local($_) = @_;
6732     local($which,$value,$hash,$dummy);
6733     local($hash, $dummy) = &get_next_optional_argument;
6734     $which = &missing_braces unless (
6735         (s/$next_pair_pr_rx/$which = $2;''/eo)
6736         ||(s/$next_pair_rx/$which = $2;''/eo));
6737     if ($hash) {
6738         local($tmp) = "\%$hash";
6739         if (eval "defined \%{$hash}") { $! = '';
6740             $value = ${$hash}{'$which'};
6741         } else { print "\nhash: \%$hash not defined" }
6742     } elsif ($which) {
6743         $value = ${$which};
6744     }
6745     $value.$_;
6748 sub do_cmd_HTMLset {
6749     local($_) = @_;
6750     local($which,$value,$hash,$dummy);
6751     local($hash, $dummy) = &get_next_optional_argument;
6752     $which = &missing_braces unless (
6753         (s/$next_pair_pr_rx/$which = $2;''/eo)
6754         ||(s/$next_pair_rx/$which = $2;''/eo));
6755     $value = &missing_braces unless (
6756         (s/$next_pair_pr_rx/$value = $2;''/eo)
6757         ||(s/$next_pair_rx/$value = $2;''/eo));
6758     if ($hash) {
6759         local($tmp) = "\%$hash";
6760         if (eval "defined \%{$hash}") { $! = '';
6761 #           eval "\$$hash{'$which'} = \"$value\";";
6762             ${$hash}{'$which'} = $value;
6763             print "\nHTMLset failed: $! " if ($!);
6764         } else { print "\nhash: \%$hash not defined" }
6765     } elsif ($which) { $! = '';
6766         eval "\${$which} = \"$value\";";
6767         print "\nHTMLset failed: $! " if ($!);
6768     }
6769     $_;
6772 sub do_cmd_HTMLsetenv { &do_cmd_HTMLset(@_) }
6774 ####
6777 # Appends $next_def to the preamble if it is not already there.
6778 sub add_to_preamble {
6779     local($type, $next_def) = @_;
6780     local($name);
6781     if ($type =~ /def|include|special|graphicspath/) {
6782         local($pat) = &escape_rx_chars ($next_def);
6783 #       $preamble .= $next_def . "\n" unless ($preamble =~ /$pat/);
6784         push(@preamble, $pat); 
6785     } 
6786     elsif ($type =~ /command|environment|theorem|counter/) {
6787         push(@preamble, $next_def ); 
6788     }
6789     else {
6790         ($name) = $next_def =~ /$marker\s*({[^}]+})/; # matches type{name}
6791         $name = &escape_rx_chars($name);
6792 #       $preamble .= $next_def . "\n" unless ($preamble =~ /$marker\s*$name/);
6793         push(@preamble, $name ); 
6794     }
6797 sub make_latex{
6798 # This is the environment in which to process constructs that cannot be
6799 # translated to HTML.
6800 # The environment tex2html_wrap will be wrapped around any shorthand
6801 # environments (e.g. $, \(, \[).
6802 # The tex2html_wrap environment will be treated as an unrecognised
6803 # evironment by the translator and its contents (i.e. the 'shorthand'
6804 # environment) will be passed to latex for processing as usual.
6805     local($contents) = @_;
6806     local($preamble) = $preamble;
6807     local($aux_preamble) = $aux_preamble;
6808     while ($preamble =~ s/^(\@.*\n)/$prelatex .= $1;''/e) {}
6809     print "\nPRE-LATEX: $prelatex" if (($prelatex)&&($VERBOSITY > 1));
6811     %newed_commands =
6812          ( 'newedcommand' , 'newcommand'
6813          , 'renewedcommand' , 'renewcommand'
6814          , 'providedcommand' , 'providecommand'
6815          , 'newedenvironment' , 'newenvironment'
6816          , 'newedboolean' , 'newboolean'
6817          , 'newedcounter' , 'newcounter'
6818          , 'newedtheorem' , 'newtheorem'
6819          , 'newedfont' , 'newfont' , 'newedif', 'newif'
6820          );
6821                      
6823     # Make the @ character a normal letter ...
6824     $preamble =~ s/\\par([^A-Za-z]|$)/\n$1/g;
6825     $preamble =~ s/(\\document(class|style)(\[[^\]]+\])?\{\w+\})/$1\n/;
6826     $preamble =~ s/(\\document(class|style)(\[[^\]]+\])?\{\w+\})/$1\n\\RequirePackage{ifthen}\n/
6827                          unless ($preamble =~/\{ifthen\}/);
6828 #    $preamble =~ s/(\\document(class|style)(\[[^\]]+\])?\{\w+\})/$1\n\\makeatletter/;
6829     # ... and make it special again after the preamble
6830     # remove the  \begin/\end  for  tex2html_nowrap and tex2html_deferred environments
6831     $preamble =~s/\\(begin|end)\s*\{(tex2html_(nowrap|deferred|nomath|preform)[_a-z]*|imagesonly)\}//g;
6832     $preamble =~s/\n?\s?<tex2html_(end)?file>\#[^#]*\#//mg;
6834     $preamble = "\\documentclass\{article\}%\n\\usepackage{html}\n\\usepackage[dvips]{color}\n"
6835         unless ($preamble);
6836     if (($LATEX_DUMP)&&(!($preamble =~ /\\usepackage\{ldump\}/))) {
6837         # MRO: replaced $* with /m
6838         $preamble =~ s/(\\document(class|style)[^\n]*\n)/$1\\usepackage\{ldump\}\n/m;
6839     }
6840     if ($preamble =~ /pstricks/) {
6841         if ($LOAD_LATEX_COLOR) {
6842             $LOAD_LATEX_COLOR =~ s/\{color\}/\{pstcol\}/ ;
6843         } else {
6844             $LOAD_LATEX_COLOR = "\n\\usepackage[dvips]{pstcol}\n";
6845         }
6846     } else {
6847         $LOAD_LATEX_COLOR = "\n\\usepackage[dvips]{color}";
6848     }
6849     $LATEX_COLOR = "\\pagecolor[gray]{.85}\\nobreak " unless $LATEX_COLOR;
6850     if ($preamble =~ /(^|\s*[^%])\s*\\documentstyle/) {
6851         # \usepackage is invalid in LaTeX 2.09 and LaTeX-2e compatibility mode
6852         $LATEX_COLOR = ''; $LOAD_LATEX_COLOR = '';
6853         # ... so is \providecommand 
6854         $preamble =~ s/\\documentstyle[^{]*{[^}]*}\n?/
6855                 $&."\n\\let\\providecommand\\newcommand\n"/eo;
6856     }
6858     $preamble .= $LOAD_LATEX_COLOR."\n" unless ($preamble =~ /[,\{]color[,\}]/);
6859     $preamble .= "\n\n".$LATEX_COLOR."\n" unless ($preamble =~ /\\pagecolor/);
6860     do {
6861         if ($ISOLATIN_CHARS) { $INPUTENC = $INPUTENC || 'latin1' };
6862         $preamble .= "\n\\usepackage[".$INPUTENC."]\{inputenc\}\n";
6863         } unless ($preamble =~ /\\inputenc/);
6865     $aux_preamble = '' unless (($aux_preamble)&&($contents =~ /\\(hyper)?(ref|cite)/));
6867     $preamble =~ s/\\((provide|(re)?new)ed(command|counter|if|theorem|environment|font))\b/
6868                          "%\n\\".$newed_commands{$1}/eg;
6869     $preamble =~ s/(\\(re)?newcommand)\s*(\{(\\?)(\}|[^\}]+)\})/
6870                 $1.(($4)? $3 : "{\\".$5.'}' )/eg;
6872     $preamble =~s/$verbatim_mark(imagesonly)(\d+)#/$verbatim{$2}/eg; # for images.tex only
6874 #    local($key);
6875 #    foreach $key (keys %newed_commands) {
6876 #       $preamble .= "\n\\let\\$key\\".$newed_commands{$key}
6877 #    }
6878     $preamble .= "\n";
6880     local($paperwidth) = '';
6881     if ($PAPERSIZE) { $paperwidth = &adjust_textwidth($PAPERSIZE); }
6882     else { $paperwidth = &adjust_textwidth("a5"); }
6883     local($kern) = ($EXTRA_IMAGE_SCALE ? $EXTRA_IMAGE_SCALE/2 : ".5" );
6884     $kern = $kern * $MATH_SCALE_FACTOR;
6885     $prelatex . ($DEBUG ? "\\nonstopmode" : "\\batchmode") .
6886     "\n$preamble\n\n\\makeatletter\n$aux_preamble\n" .
6887     "\\makeatletter\n\\count\@=\\the\\catcode`\\_ \\catcode`\\_=8 \n" .
6888     "\\newenvironment{tex2html_wrap}{}{}%\n" .
6889     "\\catcode`\\<=12\\catcode`\\_=\\count\@\n" .
6890     "\\newcommand{\\providedcommand}[1]{\\expandafter\\providecommand\\csname #1\\endcsname}%\n" .
6891     "\\newcommand{\\renewedcommand}[1]{\\expandafter\\providecommand\\csname #1\\endcsname{}%\n" .
6892     "  \\expandafter\\renewcommand\\csname #1\\endcsname}%\n" .
6893     "\\newcommand{\\newedenvironment}[1]{\\newenvironment{#1}{}{}\\renewenvironment{#1}}%\n" .
6894     "\\let\\newedcommand\\renewedcommand\n" .
6895     "\\let\\renewedenvironment\\newedenvironment\n" .
6896     "\\makeatother\n" .
6897     "\\let\\mathon=\$\n\\let\\mathoff=\$\n" .
6898     "\\ifx\\AtBeginDocument\\undefined \\newcommand{\\AtBeginDocument}[1]{}\\fi\n" .
6899     "\\newbox\\sizebox\n" . "$paperwidth" .
6900     "\\newwrite\\lthtmlwrite\n" . "\\makeatletter\n" .
6901     "\\let\\realnormalsize=\\normalsize\n\\global\\topskip=2sp\n\\def\\preveqno{}" .
6902     "\\let\\real\@float=\\\@float \\let\\realend\@float=\\end\@float\n" .
6903     "\\def\\\@float{\\let\\\@savefreelist\\\@freelist\\real\@float}\n" .
6904 #    "\\def\\\@float{\\\@dbflt}\n" .
6905     "\\def\\liih\@math{\\ifmmode\$\\else\\bad\@math\\fi}\n" .
6906     "\\def\\end\@float{\\realend\@float\\global\\let\\\@freelist\\\@savefreelist}\n" . 
6907     "\\let\\real\@dbflt=\\\@dbflt \\let\\end\@dblfloat=\\end\@float\n" .
6908     "\\let\\\@largefloatcheck=\\relax\n" .
6909     "\\let\\if\@boxedmulticols=\\iftrue\n" .
6910     "\\def\\\@dbflt{\\let\\\@savefreelist\\\@freelist\\real\@dbflt}\n" .
6911     "\\def\\adjustnormalsize{\\def\\normalsize{\\mathsurround=0pt \\realnormalsize\n" .
6912     " \\parindent=0pt\\abovedisplayskip=0pt\\belowdisplayskip=0pt}%\n" .
6913     " \\def\\phantompar{\\csname par\\endcsname}\\normalsize}%\n" .
6914     "\\def\\lthtmltypeout#1{{\\let\\protect\\string \\immediate\\write\\lthtmlwrite{#1}}}%\n" .
6915     "\\newcommand\\lthtmlhboxmathA{\\adjustnormalsize\\setbox\\sizebox=\\hbox\\bgroup\\kern.05em }%\n" .
6916     "\\newcommand\\lthtmlhboxmathB{\\adjustnormalsize\\setbox\\sizebox=\\hbox to\\hsize\\bgroup\\hfill }%\n" .
6917     "\\newcommand\\lthtmlvboxmathA{\\adjustnormalsize\\setbox\\sizebox=\\vbox\\bgroup %\n".
6918     " \\let\\ifinner=\\iffalse \\let\\)\\liih\@math }%\n" .
6919     "\\newcommand\\lthtmlboxmathZ{\\\@next\\next\\\@currlist{}{\\def\\next{\\voidb\@x}}%\n" .
6920 #    " \\expandafter\\box\\next\\edef\\next{\\egroup\\def\\noexpand\\thiseqn{\\theequation}}\\next}%\n" .
6921     " \\expandafter\\box\\next\\egroup}%\n" .
6922     "\\newcommand\\lthtmlmathtype[1]{\\gdef\\lthtmlmathenv{#1}}%\n" .
6923     "\\newcommand\\lthtmllogmath{\\dimen0\\ht\\sizebox \\advance\\dimen0\\dp\\sizebox\n" .
6924     "  \\ifdim\\dimen0>.95\\vsize\n" .  "   \\lthtmltypeout{%\n" .
6925     "*** image for \\lthtmlmathenv\\space is too tall at \\the\\dimen0, reducing to .95 vsize ***}%\n" .
6926     "   \\ht\\sizebox.95\\vsize \\dp\\sizebox\\z\@ \\fi\n" .  "  \\lthtmltypeout{l2hSize %\n" .
6927     ":\\lthtmlmathenv:\\the\\ht\\sizebox::\\the\\dp\\sizebox::\\the\\wd\\sizebox.\\preveqno}}%\n" .
6928     "\\newcommand\\lthtmlfigureA[1]{\\let\\\@savefreelist\\\@freelist
6929        \\lthtmlmathtype{#1}\\lthtmlvboxmathA}%\n" .
6930     "\\newcommand\\lthtmlpictureA{\\bgroup\\catcode`\\_=8 \\lthtmlpictureB}%\n" . 
6931     "\\newcommand\\lthtmlpictureB[1]{\\lthtmlmathtype{#1}\\egroup
6932        \\let\\\@savefreelist\\\@freelist \\lthtmlhboxmathB}%\n" .
6933     "\\newcommand\\lthtmlpictureZ[1]{\\hfill\\lthtmlfigureZ}%\n" .
6934     "\\newcommand\\lthtmlfigureZ{\\lthtmlboxmathZ\\lthtmllogmath\\copy\\sizebox
6935        \\global\\let\\\@freelist\\\@savefreelist}%\n" .
6936     "\\newcommand\\lthtmldisplayA{\\bgroup\\catcode`\\_=8 \\lthtmldisplayAi}%\n" .
6937     "\\newcommand\\lthtmldisplayAi[1]{\\lthtmlmathtype{#1}\\egroup\\lthtmlvboxmathA}%\n" .
6938     "\\newcommand\\lthtmldisplayB[1]{\\edef\\preveqno{(\\theequation)}%\n" .
6939     "  \\lthtmldisplayA{#1}\\let\\\@eqnnum\\relax}%\n" .
6940     "\\newcommand\\lthtmldisplayZ{\\lthtmlboxmathZ\\lthtmllogmath\\lthtmlsetmath}%\n" .
6941     "\\newcommand\\lthtmlinlinemathA{\\bgroup\\catcode`\\_=8 \\lthtmlinlinemathB}\n" .
6942     "\\newcommand\\lthtmlinlinemathB[1]{\\lthtmlmathtype{#1}\\egroup\\lthtmlhboxmathA\n" .
6943     "  \\vrule height1.5ex width0pt }%\n" .
6944     "\\newcommand\\lthtmlinlineA{\\bgroup\\catcode`\\_=8 \\lthtmlinlineB}%\n" .
6945     "\\newcommand\\lthtmlinlineB[1]{\\lthtmlmathtype{#1}\\egroup\\lthtmlhboxmathA}%\n" .
6946     "\\newcommand\\lthtmlinlineZ{\\egroup\\expandafter\\ifdim\\dp\\sizebox>0pt %\n" .
6947     "  \\expandafter\\centerinlinemath\\fi\\lthtmllogmath\\lthtmlsetinline}\n" .
6948     "\\newcommand\\lthtmlinlinemathZ{\\egroup\\expandafter\\ifdim\\dp\\sizebox>0pt %\n" .
6949     "  \\expandafter\\centerinlinemath\\fi\\lthtmllogmath\\lthtmlsetmath}\n" .
6950     "\\newcommand\\lthtmlindisplaymathZ{\\egroup %\n" .
6951     "  \\centerinlinemath\\lthtmllogmath\\lthtmlsetmath}\n" .
6952     "\\def\\lthtmlsetinline{\\hbox{\\vrule width.1em \\vtop{\\vbox{%\n" .
6953     "  \\kern.1em\\copy\\sizebox}\\ifdim\\dp\\sizebox>0pt\\kern.1em\\else\\kern.3pt\\fi\n" .
6954     "  \\ifdim\\hsize>\\wd\\sizebox \\hrule depth1pt\\fi}}}\n" .
6955     "\\def\\lthtmlsetmath{\\hbox{\\vrule width.1em\\kern-.05em\\vtop{\\vbox{%\n" .
6956     "  \\kern.1em\\kern$kern pt\\hbox{\\hglue.17em\\copy\\sizebox\\hglue$kern pt}}\\kern.3pt%\n" .
6957     "  \\ifdim\\dp\\sizebox>0pt\\kern.1em\\fi \\kern$kern pt%\n" .
6958     "  \\ifdim\\hsize>\\wd\\sizebox \\hrule depth1pt\\fi}}}\n" .
6959     "\\def\\centerinlinemath{%\n" . 
6960     "  \\dimen1=\\ifdim\\ht\\sizebox<\\dp\\sizebox \\dp\\sizebox\\else\\ht\\sizebox\\fi\n" .
6961     "  \\advance\\dimen1by.5pt \\vrule width0pt height\\dimen1 depth\\dimen1 \n".
6962     " \\dp\\sizebox=\\dimen1\\ht\\sizebox=\\dimen1\\relax}\n\n" .
6963     "\\def\\lthtmlcheckvsize{\\ifdim\\ht\\sizebox<\\vsize \n" .
6964     "  \\ifdim\\wd\\sizebox<\\hsize\\expandafter\\hfill\\fi \\expandafter\\vfill\n" .
6965     "  \\else\\expandafter\\vss\\fi}%\n" .
6966     "\\providecommand{\\selectlanguage}[1]{}%\n" .
6967 #    "\\def\\\@enddocumenthook{\\ifnum\\count0>1 \\ifvoid\\\@cclv\\penalty-\\\@MM\\fi\\fi}\n" .
6968     "\\makeatletter \\tracingstats = 1 \n"
6969     . ($itrans_loaded ? $itrans_tex_mod : '')
6970     . $LaTeXmacros . "\n"  # macros defined in extension files
6971 #    "\\usepackage{lthimages}\n" .
6972     . (($LATEX_DUMP)? "\\latexdump\n" : '')
6973     . "\n\\begin{document}\n" .
6974     "\\pagestyle{empty}\\thispagestyle{empty}\\lthtmltypeout{}%\n" .
6975     "\\lthtmltypeout{latex2htmlLength hsize=\\the\\hsize}\\lthtmltypeout{}%\n" .
6976     "\\lthtmltypeout{latex2htmlLength vsize=\\the\\vsize}\\lthtmltypeout{}%\n" .
6977     "\\lthtmltypeout{latex2htmlLength hoffset=\\the\\hoffset}\\lthtmltypeout{}%\n" .
6978     "\\lthtmltypeout{latex2htmlLength voffset=\\the\\voffset}\\lthtmltypeout{}%\n" .
6979     "\\lthtmltypeout{latex2htmlLength topmargin=\\the\\topmargin}\\lthtmltypeout{}%\n" .
6980     "\\lthtmltypeout{latex2htmlLength topskip=\\the\\topskip}\\lthtmltypeout{}%\n" .
6981     "\\lthtmltypeout{latex2htmlLength headheight=\\the\\headheight}\\lthtmltypeout{}%\n" .
6982     "\\lthtmltypeout{latex2htmlLength headsep=\\the\\headsep}\\lthtmltypeout{}%\n" .
6983     "\\lthtmltypeout{latex2htmlLength parskip=\\the\\parskip}\\lthtmltypeout{}%\n" .
6984     "\\lthtmltypeout{latex2htmlLength oddsidemargin=\\the\\oddsidemargin}\\lthtmltypeout{}%\n" .
6985     "\\makeatletter\n" .
6986     "\\if\@twoside\\lthtmltypeout{latex2htmlLength evensidemargin=\\the\\evensidemargin}%\n" .
6987     "\\else\\lthtmltypeout{latex2htmlLength evensidemargin=\\the\\oddsidemargin}\\fi%\n" .
6988     "\\lthtmltypeout{}%\n" .
6989     "\\makeatother\n\\setcounter{page}{1}\n\\onecolumn\n\n% !!! IMAGES START HERE !!!\n\n"
6990     . "$contents\n"
6991 #    "\\clearpage\n" .
6992     . "\\end{document}";
6995 sub adjust_textwidth {
6996     local($_) = @_;
6997     local($width,$length) = ('','');
6998     if (/a4/) {$width = 595; $length= 842; }
6999     elsif (/letter/) {$width = 612; $length= 792; }
7000     elsif (/legal/) {$width = 612; $length= 1008; }
7001     elsif (/note/) {$width = 540; $length= 720; }
7002     elsif (/b5/) {$width = 501; $length= 709; }
7003     elsif (/a5/) {$width = 421; $length= 595; }
7004     elsif (/a6/) {$width = 297; $length= 421; }
7005     elsif (/a7/) {$width = 210; $length= 297; }
7006     elsif (/a8/) {$width = 148; $length= 210; }
7007     elsif (/a9/) {$width = 105; $length= 148; }
7008     elsif (/a10/) {$width = 74; $length= 105; }
7009     elsif (/b4/) {$width = 709; $length= 1002; }
7010     elsif (/a3/) {$width = 842; $length= 1190; }
7011     elsif (/b3/) {$width = 1002; $length= 1418; }
7012     elsif (/a2/) {$width = 1190; $length= 1684; }
7013     elsif (/b2/) {$width = 1418; $length= 2004; }
7014     elsif (/a1/) {$width = 1684; $length= 2380; }
7015     elsif (/b1/) {$width = 2004; $length= 2836; }
7016     elsif (/a0/) {$width = 2380; $length= 3368; }
7017     elsif (/b0/) {$width = 2836; $length= 4013; }
7018     else {
7019         &write_warnings("\nPAPERSIZE: $_ unknown, using LaTeX's size.");
7020         return();
7021      }
7022     if ($width > 500) { $width = $width - 144; $length = $length - 288; }
7023     elsif ($width > 250) { $width = $width - 72; $length = $length - 144; }
7024     elsif ($width > 125) { $width = $width - 36; $length = $length - 72; }
7025 #    "\\setlength{\\oddsidemargin}{0pt}\n" .
7026 #    "\\setlength{\\evensidemargin}{0pt}\n" .
7027 #    "\\setlength{\\parskip}{0pt}\\setlength{\\topskip}{0pt}\n" .
7028     "\\setlength{\\hoffset}{0pt}\\setlength{\\voffset}{0pt}\n" .
7029     "\\addtolength{\\textheight}{\\footskip}\\setlength{\\footskip}{0pt}\n" .
7030     "\\addtolength{\\textheight}{\\topmargin}\\setlength{\\topmargin}{0pt}\n" .
7031     "\\addtolength{\\textheight}{\\headheight}\\setlength{\\headheight}{0pt}\n" .
7032     "\\addtolength{\\textheight}{\\headsep}\\setlength{\\headsep}{0pt}\n" .
7033     "\\setlength{\\textwidth}{${width}pt}\n"
7034     . (($length > 500) ? "\\setlength{\\textheight}{${length}pt}\n" : '')
7037 # Given the depth of the current sectioning declaration and the current
7038 # section numbers it returns the new section numbers.
7039 # It increments the $depth-ieth element of the @curr_sec_id list and
7040 # 0's the elements after the $depth-ieth element.
7041 sub new_level {
7042     local($depth, @curr_sec_id) = @_;
7043     $depth = $section_commands{$outermost_level} unless $depth;
7044     local($i) = 0;
7045     grep( do { if ($i == $depth) {$_++ ;}
7046                elsif ($i > $depth) {$_ = 0 ;};
7047                $i++;
7048                0;
7049            },
7050          @curr_sec_id);
7051     @curr_sec_id;
7054 sub make_head_and_body {
7055     local($title,$body,$before_body) = @_;
7056     local($DTDcomment) = '';
7057     local($version,$isolanguage) = ($HTML_VERSION, 'EN');
7058     local(%isolanguages) = (  'english',  'EN'   , 'USenglish', 'EN-US'
7059                             , 'original', 'EN'   , 'german'   , 'DE'
7060                             , 'austrian', 'DE-AT', 'french'   , 'FR'
7061                             , 'spanish',  'ES'
7062                             , %isolanguages );
7063 #    $isolanguage = $isolanguages{$default_language};  # DTD is in EN
7064     $isolanguage = 'EN' unless $isolanguage;
7065 #JCL(jcl-tcl)
7066 # clean title as necessary
7067 # the first words ... is a kludge, but reasonable (or not?) 
7068 #RRM: why bother? --- as long as it is pure text.
7069     $title = &purify($title,1);
7070     eval("\$title = ". $default_title ) unless ($title);
7071 #    $title = &get_first_words($title, $WORDS_IN_NAVIGATION_PANEL_TITLES);
7073     # allow user-modification of the <TITLE> tag; thanks Dan Young
7074     if (defined &custom_TITLE_hook) {
7075         $title = &custom_TITLE_hook($title, $toc_sec_title);
7076     }
7078     if ($DOCTYPE =~ /\/\/[\w\.]+\s*$/) { # language spec included
7079         $DTDcomment = '<!DOCTYPE HTML PUBLIC "'. $DOCTYPE .'"';
7080     } else {
7081         $DTDcomment = '<!DOCTYPE HTML PUBLIC "'. $DOCTYPE .'//'
7082             . ($ISO_LANGUAGE ? $ISO_LANGUAGE : $isolanguage) . '"'
7083     }
7084     $DTDcomment .= ($PUBLIC_REF ? "\n  \"".$PUBLIC_REF.'"' : '' ) . '>'."\n";
7086     $STYLESHEET = $FILE.".css" unless defined($STYLESHEET);
7088     my ($this_charset) = $charset;
7089     if ($USE_UTF) { $charset = $utf8_str; $NO_UTF = ''; }
7090     if (!$charset && $CHARSET) {
7091         $this_charset = $CHARSET;
7092         $this_charset =~ s/_/\-/go;
7093     }
7094     if ($NO_UTF && $charset =~/utf/) {
7095         $this_charset = $PREV_CHARSET||$CHARSET; 
7096         $this_charset =~ s/_/\-/go;
7097     }
7099     join("\n", (($DOCTYPE)? $DTDcomment : '' )
7100         ,"<!--Converted with LaTeX2HTML $TEX2HTMLVERSION"
7101         , "original version by:  Nikos Drakos, CBLU, University of Leeds"
7102         , "* revised and updated by:  Marcus Hennecke, Ross Moore, Herb Swan"
7103         , "* with significant contributions from:"
7104         , "  Jens Lippmann, Marek Rouchal, Martin Wilck and others"
7105             . " -->\n<HTML>\n<HEAD>\n<TITLE>".$title."</TITLE>"
7106         , &meta_information($title)
7107         ,  ($CHARSET && $HTML_VERSION ge "2.1" ? 
7108               "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=$this_charset\">" 
7109               : "" )
7110         , $LATEX2HTML_META
7111         , ($BASE ? "<BASE HREF=\"$BASE\">" : "" )
7112         , $STYLESHEET_CASCADE
7113         , ($STYLESHEET ? "<LINK REL=\"STYLESHEET\" HREF=\"$STYLESHEET\">" : '' )
7114         , $more_links_mark
7115         , "</HEAD>" , ($before_body? $before_body : '')
7116         , "<BODY $body>", '');
7120 sub style_sheet {
7121     local($env,$id,$style);
7122     #AXR:  don't overwrite existing .css
7123     #MRO: This is supposed to be $FILE.css, no?
7124     #RRM: only by default, others can be specified as well, via $EXTERNAL_STYLESHEET
7125     #return if (-f $EXTERNAL_STYLESHEET);
7126     return if (-r "$FILE.css" && -s _ && !$REFRESH_STYLES );
7128     unless(open(STYLESHEET, ">$FILE.css")) {
7129         print "\nError: Cannot write '$FILE.css': $!\n";
7130         return;
7131     }
7132     if ( -f $EXTERNAL_STYLESHEET ) {
7133         if(open(EXT_STYLES, "<$EXTERNAL_STYLESHEET")) {
7134             while (<EXT_STYLES>) { print STYLESHEET $_; }
7135             close(EXT_STYLES);
7136         } else {
7137             print "\nError: Cannot read '$EXTERNAL_STYLESHEET': $!\n";
7138         }
7139     } else {
7140         print STYLESHEET <<"EOF"
7141 /* Century Schoolbook font is very similar to Computer Modern Math: cmmi */
7142 .MATH    { font-family: \"Century Schoolbook\", serif; }
7143 .MATH I  { font-family: \"Century Schoolbook\", serif; font-style: italic }
7144 .BOLDMATH { font-family: \"Century Schoolbook\", serif; font-weight: bold }
7146 /* implement both fixed-size and relative sizes */
7147 SMALL.XTINY             { font-size : xx-small }
7148 SMALL.TINY              { font-size : x-small  }
7149 SMALL.SCRIPTSIZE        { font-size : smaller  }
7150 SMALL.FOOTNOTESIZE      { font-size : small    }
7151 SMALL.SMALL             {  }
7152 BIG.LARGE               {  }
7153 BIG.XLARGE              { font-size : large    }
7154 BIG.XXLARGE             { font-size : x-large  }
7155 BIG.HUGE                { font-size : larger   }
7156 BIG.XHUGE               { font-size : xx-large }
7158 /* heading styles */
7159 H1              {  }
7160 H2              {  }
7161 H3              {  }
7162 H4              {  }
7163 H5              {  }
7165 /* mathematics styles */
7166 DIV.displaymath         { }     /* math displays */
7167 TD.eqno                 { }     /* equation-number cells */
7170 /* document-specific styles come next */
7171 EOF
7172     }
7173     print "\n *** Adding document-specific styles *** ";
7174     while (($env,$style) = each %env_style) {
7175         if ($env =~ /\./) {
7176             $env =~ s/\.$//;
7177             print STYLESHEET "$env\t\t{ $style }\n";
7178         } elsif ($env =~ /inline|^(text|math)?((tt|rm|sf)(family)?|(up|it|sl|sc)(shape)?|(bf|md)(series)?|normal(font)?)$/) {
7179             print STYLESHEET "SPAN.$env\t\t{ $style }\n";
7180         } elsif ($env =~ /\./) {
7181             print STYLESHEET "$env\t\t{ $style }\n";
7182         } elsif ($env =~ /^(preform|\w*[Vv]erbatim(star)?)$/) {
7183             print STYLESHEET "PRE.$env\t\t{ $style }\n";
7184         } elsif ($env =~ /figure|table|tabular|equation|$array_env_rx/) {
7185             print STYLESHEET "TABLE.$env\t\t{ $style }\n";
7186         } else {
7187             print STYLESHEET "DIV.$env\t\t{ $style }\n";
7188         }
7189     }
7190     while (($env,$style) = each %txt_style) {
7191         print STYLESHEET "SPAN.$env\t\t{ $style }\n";
7192     }
7193     while (($env,$style) = each %img_style) {
7194         print STYLESHEET "IMG.$env\t\t{ $style }\n";
7195     }
7197     my ($style);
7198     foreach $id (sort(keys  %styleID)) {
7199         $style =  $styleID{$id};
7200         $style =~ s/font-(color)/$1/;
7201         print STYLESHEET "\#$id\t\t{ $style }\n"
7202             if ($styleID{$id} ne '');
7203     }
7204     close(STYLESHEET);
7207 sub clear_styleID {
7208     return unless ($USING_STYLES);
7209     local($env_id,$id) = ("grp", @_); 
7210     undef $styleID{$env_id} if ($id =~ /^\d+$/);
7213 sub make_address { 
7214     local($addr) = &make_real_address(@_);
7215     $addr .= "\n</BODY>\n</HTML>\n";
7216     &lowercase_tags($addr) if $LOWER_CASE_TAGS;
7217     $addr;
7220 sub make_real_address {
7221     local($addr) = $ADDRESS;
7222     if ((defined &custom_address)&&($addr)) {
7223         &custom_address($addr)
7224     } elsif ($addr) {
7225         "<ADDRESS>\n$addr\n</ADDRESS>";
7226     } else { '' }
7229 sub purify_caption {
7230     local($_) = @_;
7231     local($text) = &recover_image_code($_);
7232     $text =~ s/\\protect|ALT\=|%EQNO:\d+//g;
7233     $text =~ s/[\\\#\'\"\`]//g;
7234     $text;
7237 sub recover_image_code {
7238     local($key) = @_;
7239     local($text) = $img_params{$key};
7240     if (!$text) {
7241         if ($text = $id_map{$key}) {
7242             if ($orig_name_map{$text}) {
7243                 $text = $img_params{$orig_name_map{$text}}
7244             }
7245         } elsif ($cached_env_img{$key}) {
7246             $text = $img_params{$cached_env_img{$key}};
7247         }
7248         if ($text =~ /\#*ALT="([^"]+)"(>|#)/s) { $text = $1 }
7249     }
7250     $text =~ s/\\protect|%EQNO:\d+//g;
7251     $text =~ s/&(gt|lt|amp|quot);/&special_html_inv($1)/eg;
7252     $text;
7255 sub encode_title {
7256     local($_) = @_;
7257     $_ = &encode($_);
7258     while (/(<[^<>]*>)/o) {s/$1//g}; # Remove HTML tags
7259     s/#[^#]*#//g;               # Remove #-delimited markers
7260     $_;
7263 # Encodes the contents of enviroments that are passed to latex. The code
7264 # is then used as key to a hash table pointing to the URL of the resulting
7265 # picture.
7266 sub encode {
7267     local($_) = @_;
7268     # Remove invocation-specific stuff
7269     1 while(s/\\(begin|end)\s*(($O|$OP)\d+($C|$CP))?|{?tex2html_(wrap|nowrap|deferred|)(_\w+)?}?(\2)?//go);
7270     $_ = &revert_to_raw_tex($_);
7271     s/\\protect//g;             # remove redundant \protect macros
7272     #$_ = pack("u*", $_);       # uuencode
7273     s/\\\$/dollar/g;            # replace funnies, may cause problems in a hash key
7274     s/\//slash/g;               # replace funnies, may cause problems in a hash key
7275     s/\$|\/|\\//g;              # remove funnies, may cause problems in a hash key
7276     s/\s*|\n//g;                # Remove spaces  and newlines
7277     s/^(.{80}).*(.{80})$/$1$2/;         # truncate to avoid DBM problems
7278     $_;
7282 ##################### Hypertext Section Links ########################
7283 sub post_process {
7284     # Put hyperlinks between sections, add HTML headers and addresses,
7285     # do cross references and citations.
7286     # Uses the %section_info array created in sub translate.
7287     # Binds the global variables
7288     # $PREVIOUS, $PREVIOUS_TITLE
7289     # $NEXT, $NEXT_TITLE
7290     # $UP, $UP_TITLE
7291     # $CONTENTS, $CONTENTS_TITLE 
7292     # $INDEX, $INDEX_TITLE
7293     # $NEXT_GROUP, $NEXT_GROUP_TITLE
7294     # $PREVIOUS_GROUP, $PREVIOUS_GROUP_TITLE
7295     # Converting to and from lists and strings is very inefficient.
7296     # Maybe proper lists of lists should be used (or wait for Perl5?)
7297     # JKR:  Now using top_navigation and bot_navigation instead of navigation
7298     local($_, $key, $depth, $file, $title, $header, @link, @old_link,
7299           $top_navigation, $bot_navigation, @keys,
7300           @tmp_keys, $flag, $child_links, $body, $more_links);
7302     @tmp_keys = @keys = sort numerically keys %section_info;
7303     print "\nDoing section links ...";
7304     while (@tmp_keys) {
7305         $key = shift @tmp_keys;
7306         next if ($MULTIPLE_FILES &&!($key =~ /^$THIS_FILE/));
7307         print ".";
7308         $more_links = "";
7309         ($depth, $file, $title, $body) = split($delim,$section_info{$key});
7310         print STDOUT "\n$key $file $title $body" if ($VERBOSITY > 3);
7311         next if ($body =~ /external/);
7312         $PREVIOUS = $PREVIOUS_TITLE = $NEXT = $NEXT_TITLE = $UP = $UP_TITLE
7313             = $CONTENTS = $CONTENTS_TITLE = $INDEX = $INDEX_TITLE
7314             = $NEXT_GROUP = $NEXT_GROUP_TITLE
7315             = $PREVIOUS_GROUP = $PREVIOUS_GROUP_TITLE
7316             = $_ = $top_navigation = $bot_navigation = undef;
7317         &add_link_tag('previous',$file);
7318         @link =  split(' ',$key);
7319         ($PREVIOUS, $PREVIOUS_TITLE) =
7320             &add_link($previous_page_visible_mark,$file,@old_link);
7321         @old_link = @link;
7322         unless ($done{$file}) {
7323             ++$link[$depth];
7324 #           if ($MULTIPLE_FILES && !$depth && $multiple_toc ) {
7325 #               local($save_depth) = $link[$depth];
7326 #               $link[$depth] = 1;
7327 #               ($NEXT_GROUP, $NEXT_GROUP_TITLE) =
7328 #                   &add_link($next_visible_mark, $file, @link);
7329 #               &add_link_tag('next', $file, @link);
7330 #               $link[$depth] = $save_depth;
7331 #           } else {
7332                 ($NEXT_GROUP, $NEXT_GROUP_TITLE) =
7333                     &add_link($next_visible_mark, $file, @link);
7334                 &add_link_tag('next', $file, @link);
7335 #           }
7337             $link[$depth]--;$link[$depth]--;
7338             if ($MULTIPLE_FILES && !$depth ) {
7339             } else {
7340                 ($PREVIOUS_GROUP, $PREVIOUS_GROUP_TITLE) =
7341                     &add_link($previous_visible_mark, $file,@link);
7342                 &add_link_tag('previous', $file,@link);
7343             }
7345             $link[$depth] = 0;
7346             ($UP, $UP_TITLE) =
7347                 &add_link($up_visible_mark, $file, @link);
7348             &add_link_tag('up', $file, @link);
7350             if ($CONTENTS_IN_NAVIGATION) {
7351                 ($CONTENTS, $CONTENTS_LINK) = 
7352                     &add_special_link($contents_visible_mark, $tocfile, $file);
7353                 &add_link_tag('contents', $file, $delim.$tocfile);
7354             }
7356             if ($INDEX_IN_NAVIGATION) {
7357                 ($INDEX, $INDEX_LINK) = 
7358                     &add_special_link($index_visible_mark, $idxfile, $file);
7359                 &add_link_tag('index', $file, $delim.$idxfile,);
7360             }
7362             @link = split(' ',$tmp_keys[0]);
7363             # the required `next' link may be several sub-sections along
7364             local($nextdepth,$nextfile,$nextkey,$nexttitle,$nextbody)=
7365                 ($depth,$file,$key,'','');
7366             $nextkey = shift @tmp_keys;
7367             ($nextdepth, $nextfile,$nexttitle,$nextbody) = split($delim,$section_info{$nextkey});
7368             if (($nextdepth<$MAX_SPLIT_DEPTH)&&(!($nextbody=~/external/))) {
7369                 ($NEXT, $NEXT_TITLE) =
7370                     &add_link($next_page_visible_mark, $file, @link);
7371                 &add_link_tag('next', $file, @link);
7372             } else {
7373                 ($NEXT, $NEXT_TITLE) = ('','');
7374                 $nextfile = $file;
7375             }
7376             if ((!$NEXT || $NEXT =~ /next_page_inactive_visible_mark/)&&(@tmp_keys)) {
7377                 # the required `next' link may be several sub-sections along
7378                 while ((@tmp_keys)&&(($MAX_SPLIT_DEPTH < $nextdepth+1)||($nextfile eq $file))) {
7379                     $nextkey = shift @tmp_keys;
7380                     ($nextdepth, $nextfile,$nexttitle,$nextbody) = split($delim,$section_info{$nextkey});
7381                     if ($nextbody =~ /external/) {
7382                         $nextfile = $file;
7383                         next;
7384                     };
7385                     print ",";
7386                     print STDOUT "\n $nextkey" if ($VERBOSITY > 3);
7387                 }
7388                 @link = split(' ',$nextkey);
7389                 if (($nextkey)&&($nextdepth<$MAX_SPLIT_DEPTH)) {
7390                     ($NEXT, $NEXT_TITLE) =
7391                         &add_link($next_page_visible_mark, $file, @link);
7392                     &add_link_tag('next', $file, @link);
7393                 } else {
7394                     ($NEXT, $NEXT_TITLE) = ($NEXT_GROUP, $NEXT_GROUP_TITLE);
7395                     $NEXT =~ s/next_page_(inactive_)?visible_mark/next_page_$1visible_mark/;
7396                     ($PREVIOUS, $PREVIOUS_TITLE) = ($PREVIOUS_GROUP, $PREVIOUS_GROUP_TITLE);
7397                     $PREVIOUS =~ s/previous_(inactive_)?visible_mark/previous_page_$1visible_mark/;
7398                 }
7399             }
7400             unshift (@tmp_keys,$nextkey) if ($nextkey);
7402             $top_navigation = (defined(&top_navigation_panel) ?
7403                                &top_navigation_panel : &navigation_panel)
7404                 unless $NO_NAVIGATION;
7405             $bot_navigation = (defined(&bot_navigation_panel) ?
7406                                &bot_navigation_panel : &navigation_panel)
7407                 unless $NO_NAVIGATION;
7408             local($end_navigation) = "\n<!--End of Navigation Panel-->\n";
7409             if ($USING_STYLES) {
7410                 $top_navigation = "\n".'<DIV CLASS="navigation">' . $top_navigation
7411                         if $top_navigation;
7412                 $bot_navigation = "\n".'<DIV CLASS="navigation">' . $bot_navigation
7413                         if $bot_navigation;
7414                 $end_navigation = '</DIV>' . $end_navigation;
7415                 $env_style{'navigation'} = " ";
7416             }
7418             $header = &make_head_and_body($title, $body);
7419             $header = join('', $header, $top_navigation, $end_navigation) if ($top_navigation);
7421             local($this_file) = $file;
7422             if ($MULTIPLE_FILES && $ROOTED) {
7423                 if ($this_file =~ /\Q$dd\E([^$dd$dd]+)$/) { $this_file = $1 }
7424             }
7425             &slurp_input($this_file);
7426             open(OUTFILE, ">$this_file")
7427                 || die "\nError: Cannot write file '$this_file': $!\n";
7429             if (($INDEX) && ($SHORT_INDEX) && ($SEGMENT eq 1)) {
7430                 &make_index_segment($title,$file); }
7432             local($child_star,$child_links);
7433             local($CURRENT_FILE) = $this_file; # ensure $CURRENT_FILE is set correctly
7434             if (/$childlinks_on_mark\#(\d)\#/) { $child_star = $1 }
7435             $child_links = &add_child_links('',$file, $depth, $child_star,$key, @keys)
7436                 unless (/$childlinks_null_mark\#(\d)\#/);
7437             if (($child_links)&&(!/$childlinks_mark/)&&($MAX_SPLIT_DEPTH > 1)) {
7438                 if ($depth < $MAX_SPLIT_DEPTH -1) {
7439                     $_ = join('', $header, $_, &child_line(), $childlinks_mark, "\#0\#" );
7440                 } else {
7441                     $_ = join('', $header, "\n$childlinks_mark\#0\#", &upper_child_line(), $_ );
7442                 }
7443             } else {
7444                 $_ = join('', $header, $_ );
7445             }
7446             $flag = (($BOTTOM_NAVIGATION || &auto_navigation) && $bot_navigation);
7447             $_ .= $bot_navigation . $end_navigation if ($flag &&($bot_navigation));
7448             $_ .= &child_line() unless $flag;
7449             print STDOUT "\n *** replace markers *** " if ($VERBOSITY > 1);
7450             &replace_markers;
7451             print STDOUT "\n *** post-post-process *** " if ($VERBOSITY > 1);
7452             &post_post_process if (defined &post_post_process);
7453             &adjust_encoding;
7454             print OUTFILE $_;
7455             print OUTFILE &make_address;
7456             close OUTFILE;
7457             $done{$file}++;
7458         }
7459     }
7460     &post_process_footnotes if ($footfile);
7463 sub adjust_encoding {
7464     &convert_to_utf8($_) if ($USE_UTF);
7465     &lowercase_tags($_) if $LOWER_CASE_TAGS;
7468 sub post_replace_markers {
7469     # MRO: replaced $* with /m
7470     # clean up starts and ends of  P, BR and DIV tags
7471     s/(<\/?(P|BR|DIV)>)\s*(\w)/$1\n$3/gom unless ($file eq $citefile);
7472     s/([^\s])(<(BR|DIV))/$1\n$2/gom unless ($file eq $citefile);
7473     local($keep,$after);
7475     # anchor images when otherwise there is an invisible-anchor
7476 #    s/(<A[^>]*>)\&\#160;<\/A>\s?(<(P|DIV)[^>]*>)\s*(<IMG[^>]*>)\s*(<\/(P|DIV)>)/
7477     s/(<A[^>]*>)($anchor_mark|$anchor_invisible_mark)<\/A>\s?(<(P|DIV)[^>]*>)\s*(<IMG[^>]*>)\s*(<\/(P|DIV)>)/
7478         do{ $keep="$3$1$5<\/A>";
7479             $after = $6;
7480             join('',$keep, &after_punct_break($after), $after);
7481         } /egom;
7483     # absorb named anchor (e.g. from index-entry) into preceding or following anchor
7484 #    s/(<A NAME=\"[^\"]+\")>\&#160;<\/A>\s*\b?<A( HREF=\"[^\"]+\">)/$1$2/gom;
7485 #    s/(<A HREF=\"[^\"]+\")(>\s*\b?([^<]+|<([^>\/]+|\/[^>A]+)>\s*)*<\/A>)\s*\b?<A( NAME=\"[^\"]+\")>\&#160;<\/A>/$1$5$2/gom;
7487     # clean up empty table cells
7488     s/(<TD[^>]*>)\s*(<\/TD>)/<TD>$2/gom;
7490     # clean up list items (only desirable in the bibliography ?)
7491     # s/\n<P>(<DT[^>]*>)/\n<P><\/P>\n$1/gom;
7493     # remove blank lines and comment-markers
7494 #    s/\n\n/\n/g;  # no, cause this kills intended ones in verbatims
7495     s/$comment_mark(\d+\n?)?//gm;
7496     s/\&quot;/"/gm;  # replace  &quot;  entities
7498     # italic \LaTeX looks bad
7499     s:<(I|EM)>(($Laname|$AmSname)?$TeXname)</\1>:$2:gm;
7502 sub lowercase_tags {
7503     # MRO: modified to use $_[0]
7504     # local(*stream) = @_;
7505     my ($tags,$attribs);
7506     $_[0] =~ s!<(/?\w+)( [^>]*)?>!
7507         $tags = $1; $attribs = $2;
7508         $attribs =~ s/ ([\w\d-]+)(=| |$)/' '.lc($1).$2/eg;
7509         join('', '<', lc($tags) , $attribs , '>')!eg;
7512 sub after_punct_break {
7513     # MRO: modified to use $_[0]
7514     # local(*stream) = @_;
7515 #    $stream =~ s/^([ \t]*)([,;\.\)\!\"\'\?])[ \t]*(\n)?/(($2)? "$2" : "$1")."\n"/em;
7516 #    $stream;
7517     $_[0] =~ s/^([ \t]*)([,;\.\)\!\"\'\?\>]|\&gt;)[ \t]*(\n)?//em;
7518     ($2 ? $2 : $1)."\n";
7521 sub make_index_segment {
7522     local($title,$file)= @_ ;
7523 #JCL(jcl-tcl)
7524 #    s/<[^>]*>//g;
7526     $index_segment{$PREFIX} = "$title";
7527     if (!($ref_files{"segment"."$PREFIX"} eq "$file")) {
7528         $ref_files{"segment"."$PREFIX"} = "$file";
7529         $changed = 1
7530     }
7531     $SEGMENT = 2;
7535 sub add_link {
7536     # Returns a pair (iconic link, textual link)
7537     local($icon, $current_file, @link) = @_;
7538     local($dummy, $file, $title, $lbody) = split($delim,$section_info{join(' ',@link)});
7539     if ($lbody =~ /external/) { return ('','') };
7541 #    local($dummy, $file, $title) = split($delim,$toc_section_info{join(' ',@link)});
7543     if ($MULTIPLE_FILES && $ROOTED && $file) {
7544         if (!($DESTDIR =~ /\Q$FIXEDDIR\E[$dd$dd]?$/)) { $file = "..$dd$file" }
7545     }
7546 #    if ($title && ($file ne $current_file || $icon ne $up_visible_mark)) {
7547     if ($title && ($file ne $current_file)) {
7548         #RRM: allow user-customisation of the link-text; thanks Dan Young
7549         if (defined &custom_link_hook ) {
7550             $title = &custom_link_hook($title,$toc_section_info{join(' ',@link)});
7551         } else {
7552             $title = &purify($title);
7553             $title = &get_first_words($title, $WORDS_IN_NAVIGATION_PANEL_TITLES);
7554         }
7555         return ("\n".&make_href($file, $icon), &make_href($file, "$title"))
7556     }
7557 #    elsif ($icon eq $up_visible_mark && $file eq $current_file && $EXTERNAL_UP_LINK) {
7558     elsif ($icon eq $up_visible_mark && $EXTERNAL_UP_LINK) {
7559         return ("\n".&make_href($EXTERNAL_UP_LINK, $icon),
7560                 &make_href($EXTERNAL_UP_LINK, "$EXTERNAL_UP_TITLE"))
7561     }
7562     elsif (($icon eq $previous_visible_mark || $icon eq $previous_page_visible_mark)
7563         && $EXTERNAL_PREV_LINK && $EXTERNAL_PREV_TITLE) {
7564         return ("\n".&make_href($EXTERNAL_PREV_LINK, $icon),
7565                 &make_href($EXTERNAL_PREV_LINK, "$EXTERNAL_PREV_TITLE"))
7566     }
7567     elsif (($icon eq $next_visible_mark ||  $icon eq $next_page_visible_mark)
7568         && $EXTERNAL_DOWN_LINK && $EXTERNAL_DOWN_TITLE) {
7569         return ("\n".&make_href($EXTERNAL_DOWN_LINK, $icon),
7570                 &make_href($EXTERNAL_DOWN_LINK, "$EXTERNAL_DOWN_TITLE"))
7571     }
7572     (&inactive_img($icon), "");
7575 sub add_special_link { &add_real_special_link(@_) }
7576 sub add_real_special_link {
7577     local($icon, $file, $current_file) = @_;
7578     local($text);
7579     if ($icon eq $contents_visible_mark) { $text = $toc_title }
7580     elsif ($icon eq $index_visible_mark) { $text = $idx_title }
7581     elsif ($icon eq $biblio_visible_mark) { $text = $bib_title }
7582     (($file && ($file ne $current_file)) ? 
7583         ("\n" . &make_href($file, $icon), 
7584             ($text ? " ". &make_href($file, $text) : undef))
7585         : ( undef, undef ))
7588 #RRM: add <LINK ...> tag to the HTML head.
7589 #     suggested by Marcus Hennecke
7591 sub add_link_tag {
7592     local($rel, $currentfile, @link ) = @_;
7593 #    local($dummy, $file, $title) = split($delim,$toc_section_info{join(' ',@link)});
7594     local($dummy, $file, $title) = split($delim,$section_info{join(' ',@link)});
7595     ($dummy, $file, $title) = split($delim,$toc_section_info{join(' ',@link)})
7596         unless ($title);
7598     if ($MULTIPLE_FILES && $ROOTED && $file) {
7599         if (!($DESTDIR =~ /\Q$FIXEDDIR\E[$dd$dd]?$/)) { $file = "..$dd$file" }
7600     }
7601     if ($file && !($file eq $currentfile) && (!$NO_NAVIGATION)) {
7602         #RRM: allow user-customisation of the REL attribute
7603         if (defined &custom_REL_hook ) {
7604             $rel = &custom_REL_hook($rel,$toc_section_info{join(' ',@link)});
7605         }
7606         $more_links .= "\n<LINK REL=\"$rel\" HREF=\"$file\">";
7607     }
7610 sub remove_markers {
7611 # modifies $_
7612     s/$lof_mark//go;
7613     s/$lot_mark//go;
7614     &remove_bbl_marks;
7615     s/$toc_mark//go;
7616     s/$idx_mark//go;
7617     &remove_cross_ref_marks;
7618     &remove_external_ref_marks;
7619     &remove_cite_marks;
7620     &remove_file_marks;
7621 # sensitive markers
7622     &remove_image_marks;
7623     &remove_icon_marks;
7624     &remove_verbatim_marks;
7625     &remove_verb_marks;
7626     &remove_child_marks;
7627 # uncaught markers
7628     s/$percent_mark/%/go;
7629     s/$ampersand_mark/\&amp;/go;
7630     s/$comment_mark\s*(\d+\n?)?//sgo;
7631     s/$caption_mark//go;
7632     s/<tex2html[^>]*>//g;
7633     s/$OP\d+\$CP//g;
7634     $_;
7637 sub replace_markers {
7638     &find_quote_ligatures;
7639     &replace_general_markers;
7640     &text_cleanup;
7641     # Must NOT clean the ~'s out of the navigation icons (in panel or text),
7642     # and must not interfere with verbatim-like environments
7643     &replace_sensitive_markers;
7644     &replace_init_file_mark if (/$init_file_mark/);
7645     &replace_file_marks;
7646     &post_replace_markers;
7649 sub replace_general_markers {
7650     if (defined &replace_infopage_hook) {&replace_infopage_hook if (/$info_page_mark/);}
7651     else { &replace_infopage if (/$info_page_mark/); }
7652     if (defined &add_idx_hook) {&add_idx_hook if (/$idx_mark/);}
7653     else {&add_idx if (/$idx_mark/);}
7655     if ($segment_figure_captions) {
7656 #       s/$lof_mark/<UL>$segment_figure_captions<\/UL>/o
7657 #   } else { s/$lof_mark/<UL>$figure_captions<\/UL>/o }
7658         s/$lof_mark/$segment_figure_captions/o
7659     } else { s/$lof_mark/$figure_captions/o }
7660     if ($segment_table_captions) {
7661 #       s/$lot_mark/<UL>$segment_table_captions<\/UL>/o
7662 #   } else { s/$lot_mark/<UL>$table_captions<\/UL>/o }
7663         s/$lot_mark/$segment_table_captions/o
7664     } else { s/$lot_mark/$table_captions/o }
7665     &replace_morelinks();
7666     if (defined &replace_citations_hook) {&replace_citations_hook if /$bbl_mark/;}
7667     else {&replace_bbl_marks if /$bbl_mark/;}
7668     if (defined &add_toc_hook) {&add_toc_hook if (/$toc_mark/);}
7669     else {&add_toc if (/$toc_mark/);}
7670     if (defined &add_childs_hook) {&add_childs_hook if (/$childlinks_on_mark/);}
7671     else {&add_childlinks if (/$childlinks_on_mark/);}
7672     &remove_child_marks;
7674     if (defined &replace_cross_references_hook) {&replace_cross_references_hook;}
7675     else {&replace_cross_ref_marks if /$cross_ref_mark||$cross_ref_visible_mark/;}
7676     if (defined &replace_external_references_hook) {&replace_external_references_hook;}
7677     else {&replace_external_ref_marks if /$external_ref_mark/;}
7678     if (defined &replace_cite_references_hook) {&replace_cite_references_hook;}
7679     else { &replace_cite_marks if /$cite_mark/; }
7680     if (defined &replace_user_references) {
7681         &replace_user_references if /$user_ref_mark/; }
7684 sub replace_sensitive_markers {
7685     if (defined &replace_images_hook) {&replace_images_hook;}
7686     else {&replace_image_marks if /$image_mark/;}
7687     if (defined &replace_icons_hook) {&replace_icons_hook;}
7688     else {&replace_icon_marks if /$icon_mark_rx/;}
7689     if (defined &replace_verbatim_hook) {&replace_verbatim_hook;}
7690     else {&replace_verbatim_marks if /$verbatim_mark/;}
7691     if (defined &replace_verb_hook) {&replace_verb_hook;}
7692     else {&replace_verb_marks if /$verb_mark|$verbstar_mark/;}
7693     s/;SPMdollar;/\$/g; s/;SPMtilde;/\~/g; s/;SPMpct;/\%/g;
7694     s/;SPM/\&/go;
7695     s/$percent_mark/%/go;
7696     s/$ampersand_mark/\&amp;/go;
7697     #JKR: Turn encoded ~ back to normal
7698     s/&#126;/~/go;
7701 sub find_quote_ligatures {
7702     my $ent;
7704 # guillemets, governed by $NO_FRENCH_QUOTES
7705     do {
7706         $ent = &iso_map('laquo', "", 1);
7707         if ($NO_UTF && !$USE_UTF && $ent=~/\&\#(\d+);/) {
7708             $ent='' if ($1 > 255);
7709         }
7710         s/((\&|;SPM)lt;){2}/$ent/ogs if $ent;
7711         $ent = &iso_map('raquo', "", 1) if ($ent);
7712         s/((\&|;SPM)gt;){2}/$ent/ogs if $ent;
7713         # single guillemot chars cannot be easily implemented this way
7714         # finding an approp regexp is work for the future
7715     } unless ($NO_FRENCH_QUOTES);
7717     $ent = &iso_map("gg", "", 1);
7718     s/;SPMgg;/($ent ? $ent : '&gt;&gt;')/eg unless ($USE_NAMED_ENTITIES);
7719     $ent = &iso_map("ll", "", 1);
7720     s/;SPMll;/($ent ? $ent : '&lt;&lt;')/eg unless ($USE_NAMED_ENTITIES);
7722     my $ldquo, $rdquo;
7723 # "curly" quotes, governed by  $USE_CURLY_QUOTES.
7724     do {
7725         $ldquo = &iso_map("ldquo", "", 1);
7726         if ($NO_UTF && !$USE_UTF && $ldquo =~ /\&\#(\d+);/) {
7727             $ldquo = '' if ($1 > 255);
7728         }
7729         s/``/$ldquo/ogs if ($ldquo);
7730         $rdquo = &iso_map("rdquo", "", 1) if ($ldquo);
7731         s/''/$rdquo/ogs if ($rdquo);
7732         
7733         # single curly quotes cannot be easily implemented this way
7734         # finding an approp regexp is work for the future
7735     } if ($USE_CURLY_QUOTES);
7737 # "german" quotes, governed by  $NO_GERMAN_QUOTES.
7738     do {
7739         $ent = &iso_map('bdquo', "", 1);
7740         if ($NO_UTF && !$USE_UTF && $ent =~ /\&\#(\d+);/) {
7741             $ent = '' if ($1 > 255);
7742         }
7743         s/,,/$ent/eg if $ent;
7745         # closing upper quotes are not properly displayed in browsers
7746         s/($ent[\w\s\&\#;']+)$ldquo/$1``/og
7747                 if ($USE_CURLY_QUOTES && $ldquo && $ent);
7748     } unless ($NO_GERMAN_QUOTES);
7751 sub add_childlinks {
7752     local($before, $after, $star);
7753     while (/$childlinks_on_mark\#(\d)\#/) {
7754         $star = $1;
7755         $before = $`;
7756         $after = $';
7757         $before =~ s/\n\s*$//;
7758         $_ = join('', $before, "\n", $child_links, $after);
7759     }
7762 sub replace_infopage {
7763     local($INFO)=1 if !(defined $INFO);
7764     if ($INFO == 1) {
7765         local($title);
7766         if ((defined &do_cmd_infopagename)||$new_command{'infopagename'}) {
7767             local($br_id)=++$global{'max_id'};
7768             $title = &translate_environments("$O$br_id$C\\infopagename$O$br_id$C");
7769         } else { $title = $info_title }
7770             if ($MAX_SPLIT_DEPTH <= $section_commands{$outermost_level}) {
7771                 $_ =~ s/(<HR[^>]*>\s*)?$info_title_mark/
7772                     ($1? $1 : "\n<HR>")."\n<H2>$title<\/H2>"/eog;
7773             } else {
7774                 $_ =~ s/$info_title_mark/"\n<H2>$title<\/H2>"/eog;
7775             }
7776     }
7777     while (/$info_page_mark/o) {
7778         $_ = join('', $`, &do_cmd_textohtmlinfopage, $');
7779     }
7782 sub replace_init_file_mark {
7783     local($init_file, $init_contents, $info_line)=($INIT_FILE,'','');
7784     if (-f $init_file) {
7785     } elsif (-f "$orig_cwd$dd$init_file") {
7786         $init_file = $orig_cwd.$dd.$init_file;
7787     } else {
7788         s/$init_file_mark//g;
7789         return();
7790     }
7791     if(open(INIT, "<$init_file")) {
7792         foreach $info_line (<INIT>) {
7793             $info_line =~ s/[<>"&]/'&'.$html_special_entities{$&}.';'/eg;
7794             $init_contents .= $info_line;
7795         }
7796         close INIT;
7797     } else {
7798         print "\nError: Cannot read '$init_file': $!\n";
7799     }
7800     s/$init_file_mark/\n<BLOCKQUOTE><PRE>\n$init_contents\n<\/PRE><\/BLOCKQUOTE>\n/g;
7803 sub replace_morelinks {
7804     $_ =~ s/$more_links_mark/$more_links/e;
7807 # This code is extremely inefficient. At least the subtrees should be
7808 # filtered according to $MAX_LINK_DEPTH before going into the
7809 # inner loops.
7810 # RRM: revamped parts, for $TOC_STARS, fixing some errors.
7812 sub add_child_links { &add_real_child_links(@_) }
7813 sub add_real_child_links {
7814     local($exclude, $base_file, $depth, $star, $current_key, @keys) = @_;
7815     local $min_depth = $section_commands{$outermost_level} - 1;
7816     return ('') if ((!$exclude)&&(!$LEAF_LINKS)&&($depth >= $MAX_SPLIT_DEPTH));
7817     if ((!$depth)&&($outermost_level)) { $depth = $min_depth }
7819     local($_, $child_rx, @subtree, $next, %open, @roottree);
7820     local($first, $what, $pre, $change_key, $list_class);
7821     $childlinks_start = "<!--Table of Child-Links-->";
7822     $childlinks_end = "<!--End of Table of Child-Links-->\n";
7823     $child_rx = $current_key;
7824     $child_rx =~ s/( 0)*$//;    # Remove trailing 0's
7825     if ((!$exclude)&&($depth < $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH -1 )
7826 #           &&($depth >= $MAX_SPLIT_DEPTH-1)) {
7827             &&($depth > $min_depth)) {
7828         if ((defined &do_cmd_childlinksname)||$new_command{'childlinksname'}) {
7829             local($br_id)=++$global{'max_id'};
7830             $what = &translate_environments("$O$br_id$C\\childlinksname$O$br_id$C");
7831         } else {
7832             $what = "<strong>$child_name</strong>";
7833         }
7834         $list_class = ' CLASS="ChildLinks"' if ($USING_STYLES);
7835         $first = "$childlinks_start\n<A NAME=\"CHILD_LINKS\">$what<\/A>\n";
7836     } elsif ($exclude) {
7837         # remove any surrounding braces
7838         $exclude =~ s/^($O|$OP)\d+($C|$CP)|($O|$OP)\d+($C|$CP)$//g;
7839         # Table-of-Contents
7840         $list_class = ' CLASS="TofC"' if ($USING_STYLES);
7841         $childlinks_start = "\n<!--Table of Contents-->\n";
7842         $childlinks_end = "<!--End of Table of Contents-->";
7843         $first = "$childlinks_start";
7844     } else {
7845         $list_class = ' CLASS="ChildLinks"' if ($USING_STYLES);
7846         $first = "$childlinks_start\n"
7847             . ($star ? '':"<A NAME=\"CHILD_LINKS\">$anchor_mark<\/A>\n");
7848     }
7849     my $startlist, $endlist;
7850     $startlist = "<UL$list_class>" unless $CHILD_NOLIST;
7851     $endlist = '</UL>' unless $CHILD_NOLIST;
7852     my $alt_item = '<BR>&nbsp;<BR>'."\n";
7853     my $outer_item = ($CHILD_NOLIST ? $alt_item : '<LI>');
7854     my $inner_item = '<LI>';
7855     my $inner_end = '</UL><BR>';
7857     # collect the relevant keys...
7858     foreach $next (@keys) {
7859         if ($MULTIPLE_FILES && $exclude) {
7860             # ...all but with this document as the root
7861             if ($next =~ /^$THIS_FILE /) {
7862 #               # make current document the root
7863 #               $change_key = '0 '.$';
7864                 push(@roottree,$next);
7865                 print "\n$next : m-root" if ($VERBOSITY > 3);
7866             } else {
7867                 push(@subtree,$next);
7868                 print "\n$next : m-sub" if ($VERBOSITY > 3);
7869             }
7870         } elsif (($next =~ /^$child_rx /)&&($next ne $current_key)) {
7871         # ...which start as $current_key
7872             push(@subtree,$next);
7873             print "\n$next : sub $child_rx" if ($VERBOSITY > 3);
7874         } else {
7875             print "\n$next : out $current_key" if ($VERBOSITY > 3);
7876         }
7877     }
7878     if (@subtree) { @subtree = sort numerically @subtree; }
7879     if (@roottree) {
7880         @roottree = sort numerically @roottree;
7881         @subtree = ( @roottree, @subtree );
7882     }
7883     # @subtree now contains the subtree rooted at the current node
7885     local($countUL); #counter to ensure correct tag matching
7886     my $root_file, $href;
7887     if (@subtree) {
7888         local($next_depth, $file, $title, $sec_title, $star, $ldepth,$this_file, $prev_file);
7889         $ldepth = $depth;
7890         $prev_file = $base_file;
7891 #       @subtree = sort numerically @subtree;
7892         foreach $next (@subtree) {
7893             $title = '';
7894             if ($exclude) {
7895                 # making TOC
7896                 ($next_depth, $file, $sec_title) =
7897                         split($delim,$section_info{$next});
7898                 ($next_depth, $file, $title, $star) =
7899                         split($delim,$toc_section_info{$next});
7900                 # use the %section_info  title, in case there are images
7901                 $title = $sec_title if ($sec_title =~ /image_mark>\#/);
7902             } else {
7903                 # making mini-TOC i.e. the child-links tables
7904                 $star = '';
7905                 ($next_depth, $file, $title) =
7906                         split($delim,$section_info{$next});
7907             }
7908             $root_file = $file unless $root_file;
7909             if ($root_file && $root_file =~ /_mn\./) { $root_file=$` };
7910             # remove any surrounding braces
7911             $title =~ s/^($O|$OP)\d+($C|$CP)|($O|$OP)\d+($C|$CP)$//g;
7912             next if ($exclude && $title =~ /^$exclude$/);
7913             if (!$title) {
7914                 ($next_depth, $file, $title, $star) =
7915                         split($delim,$toc_section_info{$next});
7916             }
7917             $this_file = $file;
7918             $title = "\n".$title if !($title =~/^\n/);
7919             next if ( $exclude &&(                              # doing Table-of-Contents
7920                 ( $TOC_DEPTH &&($next_depth > $TOC_DEPTH))      # and  too deep
7921                 ||($star && !$TOC_STARS ) ));                   # or no starred sections 
7922             $file = "" if (!$MAX_SPLIT_DEPTH); # Martin Wilck
7923             next if ($exclude && !$MULTIPLE_FILES &&($title =~ /^\s*$exclude\s*$/));
7924             next if (!$exclude && $next_depth > $MAX_LINK_DEPTH + $depth);
7925             print "\n$next :" if ($VERBOSITY > 3);
7926             if ($this_file =~ /^(\Q$prev_file\E|\Q$base_file\E)$/) {
7927                 $file .= join('', "#SECTION", split(' ', $next));
7928             } else { $prev_file = $file }
7930             if (!$next_depth && $MULTIPLE_FILES) { ++$next_depth }
7931             local($num_open) = (split('/',%open))[0];
7932             if ((($next_depth > $ldepth)||$first)
7933                 && ((split('/',%open))[0] < $MAX_LINK_DEPTH + $depth )
7934                 ) {
7935                 # start a new <UL> list
7936                 if ($first) {
7937                     $_ = "$first\n$startlist\n"; $countUL++;
7938                     local $i = 1;
7939                     while ($i <= $ldepth) {
7940                         $open{$i}=0; $i++
7941                     }
7942                     $first = '';        # include NAME tag first time only
7943                     while ($i < $next_depth) {
7944                         $open{$i}=1; $i++; 
7945                         $_ .= ($countUL >1 ? $inner_item : $outer_item)."<UL>\n";
7946                         $countUL++;
7947                     }
7948                 } else {
7949                     $_ .= "<UL>\n"; $countUL++;
7950                 }
7951                 $ldepth = $next_depth;
7952                 $open{$ldepth}++; 
7953                 # append item to this list
7954                 print " yes " if ($VERBOSITY > 3);
7955                 if (defined &add_frame_child_links) {
7956                     $href = &make_href($file,$title);
7957                     if ($href =~ s/($root_file)_mn/$1_ct/) {
7958                         $href =~ s/(target=")main(")/$1contents$2/i;
7959                     };
7960                     $_ .= ($countUL >1 ? $inner_item : $outer_item)
7961                         . $href . "\n";
7962                 } else {
7963                     $_ .= ($countUL >1 ? $inner_item : $outer_item)
7964                         . &make_href($file,$title) . "\n";
7965                 }
7966             }
7967             elsif (($next_depth)&&($next_depth <= $ldepth)
7968                 &&((split('/',%open))[0] <= $MAX_LINK_DEPTH + $depth )
7969                 ) {
7970                 # append item to existing <UL> list
7971                 while (($next_depth < $ldepth) && %open ) {
7972                 # ...closing-off any nested <UL> lists
7973                     if ($open{$ldepth}) {
7974                         if (!(defined $open{$next_depth}))  {
7975                             $open{$next_depth}++;
7976                         } else {
7977                             $_ .= ($countUL==2 ? $inner_end : '</UL>')."\n";
7978                             $countUL--;
7979                         }
7980                         delete $open{$ldepth};
7981                     };
7982                     $ldepth--;
7983                 }
7984                 $ldepth = $next_depth;
7985                 print " yes" if ($VERBOSITY > 3);
7986                 if (defined &add_frame_child_links) {
7987                     $href = &make_href($file,$title);
7988                     if ($href =~ s/($root_file)_mn/$1_ct/) {
7989                         $href =~ s/(target=")main(")/$1contents$2/i;
7990                     };
7991                     $_ .= ($countUL >1 ? $inner_item : $outer_item)
7992                         . $href . "\n";
7993                 } else {
7994                     $_ .= ($countUL >1 ? $inner_item : $outer_item)
7995                         . &make_href($file,$title) . "\n";
7996                 }
7997             } else {
7998                 # ignore items that are deeper than $MAX_LINK_DEPTH
7999                 print " no" if ($VERBOSITY > 3);
8000             }
8001         }
8003         if (%open) {
8004         # close-off any remaining <UL> lists
8005             $countUL-- if $CHILD_NOLIST;
8006             local $cnt = (split('/',%open))[0];
8007             local $i = $cnt;
8008                 while ($i > $depth) { 
8009                     if ($open{$i}) {
8010                         $_ .= '</UL>' if $countUL;
8011                         $countUL--;
8012                         delete $open{$i};
8013                     }
8014                 $i--;
8015             }
8016         }
8017     }
8018     # just in case the count is wrong
8019     $countUL-- if ($CHILD_NOLIST && $countUL > 0);
8020     $countUL = '' if ($countUL < 0);
8021     while ($countUL) { $_ .= '</UL>'; $countUL-- }
8022     ($_ ? join('', $_, "\n$childlinks_end") : '');
8025 sub child_line {($CHILDLINE) ? "$CHILDLINE" : "<BR>\n<HR>";}
8026 sub upper_child_line { "<HR>\n"; }
8028 sub adjust_root_keys {
8029     return() unless ($MULTIPLE_FILES && $ROOTED);
8030     local($next,$change_key,$current_rx);
8031     local(@keys) = (keys %toc_section_info);
8032     
8033     local($current_key) = join(' ',@curr_sec_id);
8034     $current_key =~ /^(\d+ )/;
8035     $current_rx = $1;
8036     return() unless $current_rx;
8038     # alter the keys which start as $current_key
8039     foreach $next (@keys) {
8040         if ($next =~ /^$current_rx/) {
8041             # make current document the root
8042             $change_key = '0 '.$';
8043             $toc_section_info{$change_key} = $toc_section_info{$next};
8044             $section_info{$change_key} = $section_info{$next};
8045 #           if (!($next eq $current_key)) {
8046 #               $toc_section_info{$next} = $section_info{$next} = '';
8047 #           }
8048         }
8049     }
8052 sub top_page {
8053     local($file, @navigation_panel) = @_;
8054     # It is the top page if there is a link to itself
8055     join('', @navigation_panel) =~ /$file/;
8058 # Sets global variable $AUX_FILE
8059 sub process_aux_file {
8060     local(@exts) = ('aux');
8061     push(@exts, 'lof') if (/\\listoffigures/s);
8062     push(@exts, 'lot') if (/\\listoftables/s);
8063     local($_, $status);         # To protect caller from &process_ext_file
8064     $AUX_FILE = 1;
8065     foreach $auxfile (@exts) {
8066         $status = &process_ext_file($auxfile);
8067         if ($auxfile eq "aux" && ! $status) {
8068             print "\nCannot open $FILE.aux $!\n";
8069             &write_warnings("\nThe $FILE.aux file was not found," .
8070                             " so sections will not be numbered \nand cross-references "
8071                             . "will be shown as icons.\n");
8072         }
8073     }
8074     $AUX_FILE = 0;
8077 sub do_cmd_htmlurl {
8078     local($_) = @_;
8079     local($url);
8080     $url = &missing_braces unless (
8081         (s/$next_pair_pr_rx/$br_id=$1;$url=$2;''/e)
8082         ||(s/$next_pair_rx/$br_id=$1;$url=$2;''/e));
8083     $url =~ s/\\(html)?url\s*($O|$OP)([^<]*)\2/$3/;
8084     $url =~ s/\\?~/;SPMtilde;/og;
8085     join('','<TT>', &make_href($url,$url), '</TT>', $_);
8087 sub do_cmd_url { &do_cmd_htmlurl(@_) }
8089 sub make_href { &make_real_href(@_) }
8090 sub make_real_href {
8091     local($link, $text) = @_;
8092     $href_name++;
8093     my $htarget = '';
8094     $htarget = ' target="'.$target.'"'
8095         if (($target)&&($HTML_VERSION > 3.2));
8096     #HWS: Nested anchors not allowed.
8097     $text =~ s/<A .*><\/A>//go;
8098     #JKR: ~ is handled different - &#126; is turned to ~ later.
8099     #$link =~ s/&#126;/$percent_mark . "7E"/geo;
8100     if ($text eq $link) { $text =~ s/~/&#126;/g; }
8101     $link =~ s/~/&#126;/g;
8102     # catch \url or \htmlurl
8103     $link =~ s/\\(html)?url\s*(($O|$OP)\d+($C|$CP))([^<]*)\2/$5/;
8104     $link =~ s:(<TT>)?<A [^>]*>([^<]*)</A>(</TT>)?(([^<]*)|$):$2$4:;
8105     # this should not be here; else TOC, List of Figs, etc. fail:
8106     # $link =~ s/^\Q$CURRENT_FILE\E(\#)/$1/ unless ($SEGMENT||$SEGMENTED);
8107     $text = &simplify($text);
8108     "<A NAME=\"tex2html$href_name\"$htarget\n  HREF=\"$link\">$text</A>";
8111 sub make_href_noexpand { # clean
8112     my ($link, $name, $text) = @_;
8113     do {$name = "tex2html". $href_name++} unless $name;
8114     #HWS: Nested anchors not allowed.
8115     $text =~ s/<A .*><\/A>//go;
8116     #JKR: ~ is handled different - &#126; is turned to ~ later.
8117     #$link =~ s/&#126;/$percent_mark . "7E"/geo;
8118     if ($text eq $link) { $text =~ s/~/&#126;/g; }
8119     $link =~ s/~/&#126;/g;
8120     # catch \url or \htmlurl
8121     $link =~ s/\\(html)?url\s*(($O|$OP)\d+($C|$CP))([^<]*)\2/$5/;
8122     $link =~ s:(<TT>)?<A [^>]*>([^<]*)</A>(</TT>)?(([^<]*)|$):$2$4:;
8123     "<A NAME=\"$name\"\n HREF=\"$link\">$text</A>";
8126 sub make_named_href {
8127     local($name, $link, $text) = @_;
8128     $text =~ s/<A .*><\/A>//go;
8129     $text = &simplify($text);
8130     if ($text eq $link) { $text =~ s/~/&#126;/g; }
8131     $link =~ s/~/&#126;/g;
8132     # catch \url or \htmlurl
8133     $link =~ s/\\(html)?url\s*(($O|$OP)\d+($C|$CP))([^<]*)\2/$5/;
8134     $link =~ s:(<TT>)?<A [^>]*>([^<]*)</A>(</TT>)?(([^<]*)|$):$2$4:;
8135     if (!($name)) {"<A\n HREF=\"$link\">$text</A>";}
8136     elsif ($text =~ /^\w/) {"<A NAME=\"$name\"\n HREF=\"$link\">$text</A>";}
8137     else {"<A NAME=\"$name\"\n HREF=\"$link\">$text</A>";}
8140 sub make_section_heading {
8141     local($text, $level, $anchors) = @_;
8142     local($elevel) = $level; $elevel =~ s/^(\w+)\s.*$/$1/;
8143     local($section_tag) = join('', @curr_sec_id);
8144     local($align,$pre_anchors);
8146     # separate any invisible anchors or alignment, if this has not already been done
8147     if (!($anchors)){ ($anchors,$text) = &extract_anchors($text) }
8148     else { 
8149         $anchors =~ s/(ALIGN=\"\w*\")/$align = " $1";''/e;
8150         $align = '' if ($HTML_VERSION < 2.2);
8151         $anchors = &translate_commands($anchors) if ($anchors =~ /\\/);
8152     }
8154     # strip off remains of bracketings
8155     $text =~ s/$OP\d+$CP//g;
8156     if (!($text)) {
8157         # anchor to a single `.' only
8158         $text = "<A NAME=\"SECTION$section_tag\">.</A>$anchors\n";
8159     } elsif ($anchors) {
8160 #       # put anchors immediately after, except if title is too long
8161 #       if ((length($text)<60 )&&(!($align)||($align =~/left/))) {
8162 #           $text = "<A NAME=\"SECTION$section_tag\">$text</A>\n" . $anchors;
8163         # ...put anchors preceding the title, on a separate when left-aligned
8164 #       } else {
8165             $text = "<A NAME=\"SECTION$section_tag\">$anchor_invisible_mark</A>$anchors"
8166                 . (!($align)||($align =~ /left/i ) ? "<BR>" : "") . "\n". $text;
8167 #       }
8168     } elsif (!($text =~ /<A[^\w]/io)) {
8169         # no embedded anchors, so anchor it all
8170         $text = "<A NAME=\"SECTION$section_tag\">\n" . $text . "</A>";
8171     } else {
8172         # there are embedded anchors; these cannot be nested
8173         local ($tmp) = $text;
8174         $tmp =~ s/<//o ;        # find 1st <
8175         if ($`) {               # anchor text before the first < 
8176 #           $text = "<A NAME=\"SECTION$section_tag\">\n" . $` . "</A>\n<" . $';
8177             $text = "<A NAME=\"SECTION$section_tag\">\n" . $` . "</A>";
8178             $pre_anchors = "<" . $';
8179             if ($pre_anchors =~ /^(<A NAME=\"[^\"]+>${anchor_invisible_mark}<\/A>\s*)+$/) {
8180                 $pre_anchors .= "\n"
8181             } else { $text .= $pre_anchors; $pre_anchors = '' }
8182         } else {
8183             # $text starts with a tag
8184             local($after,$tmp) = ($','');
8185             if ( $after =~ /^A[^\w]/i ) {       
8186                 # it is an anchor already, so need a separate line
8187                 $text = "<A NAME=\"SECTION$section_tag\">$anchor_invisible_mark</A><BR>\n$text";
8188             } else {
8189                 # Is it a tag enclosing the anchor ?
8190                 $after =~ s/^(\w)*[\s|>]/$tmp = $1;''/eo;
8191                 if ($after =~ /<A.*<\/$tmp>/) {
8192                     # it encloses an anchor, so use anchor_mark + break
8193                     $text = "<A NAME=\"SECTION$section_tag\">$anchor_invisible_mark</A><BR>\n$text";
8194                 } else {
8195                     # take up to the anchor
8196                     $text =~ s/^(.*)<A([^\w])/"<A NAME=\"SECTION$section_tag\">$1<A$2"/oe;
8197                 }
8198             }
8199         }
8200     }
8201     "$pre_anchors\n<$level$align>$text\n<\/$elevel>";
8204 sub do_cmd_captionstar { &process_cmd_caption(1, @_) }
8205 sub do_cmd_caption { &process_cmd_caption('', @_) }
8206 sub process_cmd_caption {
8207     local($noLOTentry, $_) = @_;
8208     local($text,$opt,$br_id, $contents);
8209     local($opt) = &get_next_optional_argument;
8210     $text = &missing_braces unless (
8211         (s/$next_pair_pr_rx/$br_id=$1;$text=$2;''/e)
8212         ||(s/$next_pair_rx/$br_id=$1;$text=$2;''/e));
8214     # put it in $contents, so &extract_captions can find it
8215     local($contents) = join('','\caption', ($opt ? "[$opt]" : '')
8216            , "$O$br_id$C" , $text , "$O$br_id$C");
8218     # $cap_env is set by the surrounding figure/table
8219     &extract_captions($cap_env);
8220     $contents.$_;
8223 sub extract_captions {
8224     # Uses and modifies $contents and $cap_anchors, defined in translate_environments
8225     # and modifies $figure_captions, $table_captions, $before and $after
8226     # MRO: no effect! local($env,*cap_width) = @_;
8227     local($env) = @_;
8228     local(%captions, %optional_captions, $key, $caption, $optional_caption,
8229           $item, $type, $list, $extra_list, $number, @tmp, $br_id, $_);
8230     # associate the br_id of the caption with the argument of the caption
8231     $contents =~ s/$caption_rx(\n)?/do {
8232         $key = $9; $caption = $10; $optional_caption = $3;
8233         $key = &filter_caption_key($key) if (defined &filter_caption_key);
8234         $optional_captions{$key} = $optional_caption||$caption;
8235         $captions{$key} = $10; ''}/ego;
8236 #       $captions{$9} = $10; $caption_mark }/ego;
8237     $key = $caption = $optional_caption = '';
8239     #catch any  \captionwidth  settings that may remain
8240     $contents =~ s/$caption_width_rx(\n)?/&translate_commands($&);''/eo;
8241     
8242 #    $after = join("","<P>",$after) if ($&);
8243 #    $before .= "</P>" if ($&);
8244     #JKR: Replaced "Figure" and "Table" with variables (see latex2html.config too).
8245     if ($env eq 'figure') {
8246         if ((defined &do_cmd_figurename)||$new_command{'figurename'}){
8247             $br_id = ++$global{'max_id'};
8248             $type = &translate_environments("$O$br_id$C\\figurename$O$br_id$C")
8249                 unless ($noLOFentry);
8250         } else { $type = $fig_name }
8251         $list = "\$figure_captions";
8252 #       $extra_list = "\$segment_figure_captions" if ($figure_table_captions);
8253         $extra_list = "\$segment_figure_captions" if ($segment_figure_captions);
8254     }
8255     elsif ($env =~ /table/) {
8256         if ((defined &do_cmd_tablename)||$new_command{'tablename'}) {
8257             $br_id = ++$global{'max_id'};
8258             $type = &translate_environments("$O$br_id$C\\tablename$O$br_id$C")
8259                 unless ($noLOTentry);
8260         } else { $type = $tab_name }
8261         $list = "\$table_captions";
8262         $extra_list = "\$segment_table_captions" if ($segment_table_captions);
8263     }
8265 #    $captions = "";
8266     $cap_anchors = "";
8267     local($this);
8268     foreach $key (sort {$a <=> $b;} keys %captions){ # Sort numerically
8269         $this = $captions{$key};
8270         $this =~ s/\\label\s*($O\d+$C)[^<]+\1//g; # remove \label commands
8271         local($br_id) = ++$global{'max_id'};
8272         local($open_tags_R) = []; # locally, initially no style
8273         $caption = &translate_commands(
8274              &translate_environments("$O$br_id$C$this$O$br_id$C"));
8276         # same again for the optional caption
8277         $this = $optional_captions{$key};
8278         $this =~ s/\\label\s*($O\d+$C)[^<]+\1//g; # remove \label commands
8279         local($open_tags_R) = []; local($br_id) = ++$global{'max_id'};
8280         $this = &translate_environments("$O$br_id$C$this$O$br_id$C");
8281         $optional_caption = &translate_commands($this);
8283         $cap_anchors .= "<A NAME=\"$key\">$anchor_mark</A>";
8284         $_ = $optional_caption || $caption;
8287         # split at embedded anchor or citation marker
8288         local($pre_anchor,$post_anchor) = ('','');
8289         if (/\s*(<A\W|\#[^#]*\#<tex2html_cite_[^>]*>)/){
8290             $pre_anchor = "$`";
8291             $post_anchor = "$&$'";
8292             $pre_anchor = $anchor_invisible_mark
8293                 unless (($pre_anchor)||($SHOW_SECTION_NUMBERS));
8294         } else {
8295             $pre_anchor = "$_";
8296         }
8298 #JCL(jcl-tcl)
8299 ##      &text_cleanup;
8300 ##      $_ = &encode_title($_);
8301 ##      s/&nbsp;//g;            # HWS - LaTeX changes ~ in its .aux files
8302 #       $_ = &sanitize($_);
8303 ##
8304 #       $_ = &revert_to_raw_tex($_);
8306         #replace image-markers by the image params
8307         s/$image_mark\#([^\#]+)\#/&purify_caption($1)/e;
8309         local($checking_caption, $cap_key) = (1, $_);
8310         $cap_key = &simplify($cap_key);
8311         $cap_key = &sanitize($cap_key);
8312         @tmp = split(/$;/, eval ("\$encoded_$env" . "_number{\$cap_key}"));
8313         $number = shift(@tmp);
8314         $number = "" if ($number eq "-1");
8316         if (!$number) {
8317             $cap_key = &revert_to_raw_tex($cap_key);
8318             @tmp = split(/$;/
8319                , eval ("\$encoded_$env" . "_number{\$cap_key}"));
8320             $number = shift(@tmp);
8321             $number = "" if ($number eq "-1");
8322         }
8324         #resolve any embedded cross-references first
8325         $checking_caption = '';
8326         $_ = &simplify($_);
8327         $_ = &sanitize($_);
8330 #       @tmp = split(/$;/, eval ("\$encoded_$env" . "_number{\$_}"));
8331 #       $number = shift(@tmp);
8332 #       $number = "" if ($number eq "-1");
8334         &write_warnings(qq|\nNo number for "$_"|) if (! $number);
8335         eval("\$encoded_$env" . "_number{\$_} = join(\$;, \@tmp)");
8337         $item = join( '', ($SHOW_SECTION_NUMBERS ? $number."\. " : '')
8338             , &make_href("$CURRENT_FILE#$key", $pre_anchor)
8339             , $post_anchor);
8340         undef $_;
8341         undef @tmp;
8343         $captions = join("", ($captions ? $captions."\n<BR>\n" : '')
8344                 , "<STRONG>$type" , ($number ? " $number:" : ":")
8345                 , "</STRONG>\n$caption" , (($captions) ? "\n" : "" ));
8347         do {
8348             eval "$extra_list .= \"\n<LI>\" .\$item" if ($extra_list);
8349             eval "$list .= \"\n<LI>\" .\$item" }
8350                  unless ( $noLOTentry || $noLOFentry);
8351 #       eval("print \"\nCAPTIONS:\".$extra_list.\n\"");
8352     }
8356 # This processes \label commands found in environments that will
8357 # be handed over to Latex. Sets the table %symbolic_labels
8358 sub do_labels {
8359     local($context,$new_context) = @_;
8360     local($label);
8361     # MRO: replaced $* by /m
8362     $context =~ s/\s*$labels_rx/do {
8363         $label = &do_labels_helper($2);
8364         $new_context = &anchor_label($label,$CURRENT_FILE,$new_context);""}/geom;
8365     $new_context;
8368 sub extract_labels {
8369     local($_) = @_;
8370     local($label,$anchors);
8371     # MRO: replaced $* by /m
8372     while (s/[ \t]*$labels_rx//om) {
8373         $label = &do_labels_helper($2);
8374         $anchors .= &anchor_label($label,$CURRENT_FILE,'');
8375     }
8376     ($_, $anchors);
8379 # This should be done inside the substitution but it doesn't work ...
8380 sub do_labels_helper {
8381     local($_) = @_;
8382     s/$label_rx/_/g;  # replace non-alphanumeric characters
8383     $symbolic_labels{$_} = $latex_labels{$_}; # May be empty;
8384     $_;
8387 sub convert_to_description_list {
8388     # MRO: modified to use $_[1]
8389     # local($which, *list) = @_;
8390     my $which = $_[0];
8391     $_[1] =~ s!(</A>\s*)<[OU]L([^>]*)>!$1<DD><DL$2>!ig;
8392     $_[1] =~ s!<(/?)[OU]L([^>]*)>!$1? "<$1DL$2>":"<DL$2>"!eig;
8393     $_[1] =~ s!(</?)LI>!$1D$which>!ig;
8394 #    $_[1] =~ s/^\s*<DD>//;
8397 sub add_toc { &add_real_toc(@_) }
8398 sub add_real_toc {
8399     local($temp1, $temp2);
8400     print "\nDoing table of contents ...";
8401     local(@keys) = keys %toc_section_info;
8402     @keys = sort numerically @keys;
8403     $temp1 = $MAX_LINK_DEPTH; $temp2 = $MAX_SPLIT_DEPTH;
8404     $MAX_SPLIT_DEPTH = $MAX_LINK_DEPTH = 1000;
8405     #JKR: Here was a "Contents" - replaced it with $toc_title
8406     local($base_key) = $keys[0];
8407     if ($MULTIPLE_FILES) {
8408         $base_key = $THIS_FILE;
8409     }
8410     local($title);
8411     if ((defined &do_cmd_contentsname)||$new_command{'contentsname'}) {
8412         local($br_id)=++$global{'max_id'};
8413         $title = &translate_environments("$O$br_id$C\\contentsname$O$br_id$C");
8414     } else { $title = $toc_title }
8415     local($toc,$on_first_page) = ('','');
8416     $on_first_page = $CURRENT_FILE
8417         unless ($MAX_SPLIT_DEPTH && $MAX_SPLIT_DEPTH <1000);
8418     $toc = &add_child_links($title,$on_first_page,'',1,$keys[0],@keys);
8419     &convert_to_description_list('T',$toc) if ($use_description_list);
8420     s/$toc_mark/$toc/;
8421     $MAX_LINK_DEPTH = $temp1; $MAX_SPLIT_DEPTH = $temp2;
8424 # Assign ref value, but postpone naming the label
8425 sub make_half_href {
8426     local($link) = $_[0];
8427     $href_name++;
8428     "<A NAME=\"tex2html$href_name\"\n HREF=\"$link\">";
8432 # Redefined in makeidx.perl
8433 sub add_idx {
8434     local($sidx_style, $eidx_style) =('<STRONG>','</STRONG>');
8435     if ($INDEX_STYLES) {
8436         if ($INDEX_STYLES =~/,/) {
8437         local(@styles) = split(/\s*,\s*/,$INDEX_STYLES);
8438             $sidx_style = join('','<', join('><',@styles) ,'>');
8439             $eidx_style = join('','</', join('></',reverse(@styles)) ,'>');
8440         } else {
8441             $sidx_style = join('','<', $INDEX_STYLES,'>');
8442             $eidx_style = join('','</', $INDEX_STYLES,'>');
8443         }
8444     }
8445     &add_real_idx(@_)
8447 sub add_real_idx {
8448     print "\nDoing the index ...";
8449     local($key, $str, @keys, $index, $level, $count,
8450           @previous, @current);
8451     @keys = keys %index;
8452     @keys = sort keysort  @keys;
8453     $level = 0;
8454     foreach $key (@keys) {
8455         @current = split(/!/, $key);
8456         $count = 0;
8457         while ($current[$count] eq $previous[$count]) {
8458             $count++;
8459         }
8460         while ($count > $level) {
8461             $index .= "\n<DL COMPACT>";
8462             $level++;
8463         }
8464         while ($count < $level) {
8465             $index .= "\n</DL>";
8466             $level--;
8467         }
8468         foreach $term (@current[$count .. $#current-1]) {
8469             # need to "step in" a little
8470 #           $index .= "<DT>" . $term . "\n<DL COMPACT>";
8471             $index .= "\n<DT>$sidx_style" . $term . "$eidx_style\n<DD><DL COMPACT>";
8472             $level++;
8473         }
8474         $str = $current[$#current];
8475         $str =~ s/\#\#\#\d+$//o; # Remove the unique id's
8476         $index .= $index{$key} .
8477             # If it's the same string don't start a new line
8478             (&index_key_eq(join('',@current), join('',@previous)) ?
8479              ", $sidx_style" . $cross_ref_visible_mark . "$eidx_style</A>\n" :
8480              "<DT>$sidx_style" . $str . "$eidx_style</A>\n");
8481         @previous = @current;
8482     }
8483     while ($count < $level) {
8484         $index .= "\n</DL>";
8485         $level--;
8486     }
8487     $index = '<DD>'.$index unless ($index =~ /^\s*<D(T|D)>/);
8489     $index =~ s/(<A [^>]*>)(<D(T|D)>)/$2$1/g;
8490     
8491 #    s/$idx_mark/<DL COMPACT>$index<\/DL>/o;
8492     s/$idx_mark/$preindex\n<DL COMPACT>\n$index<\/DL>\n/o;
8495 sub keysort {
8496     local($x, $y) = ($a,$b);
8497     $x = &clean_key($x);
8498     $y = &clean_key($y);
8499 #    "\L$x" cmp "\L$y";  # changed sort-rules, by M Ernst.
8500     # Put alphabetic characters after symbols; already downcased
8501     $x =~ s/^([a-z])/~~~$1/;
8502     $y =~ s/^([a-z])/~~~$1/;
8503     $x cmp $y;
8506 sub index_key_eq {
8507     local($a,$b) = @_;
8508     $a = &clean_key($a);
8509     $b = &clean_key($b);
8510     $a eq $b;
8513 sub clean_key {
8514     local ($_) = @_;
8515     tr/A-Z/a-z/;
8516     s/\s+/ /g;          # squeeze white space and newlines into space
8517     s/ (\W)/$1/g;       # make foo( ), foo () and foo(), or <TT>foo</TT>
8518     ;                   # and <TT>foo </TT> to be equal
8519     s/$O\d+$C//go;      # Get rid of bracket id's
8520     s/$OP\d+$CP//go;    # Get rid of processed bracket id's
8521     s/\#\#\#\d+$//o;    # Remove the unique id
8522     $_;
8526 sub make_footnotes {
8527     # Uses $footnotes defined in translate and set in do_cmd_footnote
8528     # Also uses $footfile
8529     local($_) = "\n<DL>$footnotes\n<\/DL>";
8530     $footnotes = ""; # else they get used
8531     local($title);
8532     if ((defined &do_cmd_footnotename)||$new_command{'footnotename'}) {
8533         local($br_id)=++$global{'max_id'};
8534         $title = &translate_environments("$O$br_id$C\\footnotename$O$br_id$C");
8535     } else {
8536         $foot_title = "Footnotes" unless $foot_title;
8537         $title = $foot_title;
8538     }
8539     print "\nDoing footnotes ...";
8540 #JCL(jcl-tcl)
8541 # If the footnotes go into a separate file: see &make_file.
8542     if ($footfile) {
8543         $toc_sec_title = $title;
8544         &make_file($footfile, $title, $FOOT_COLOR); # Modifies $_;
8545         $_ = "";
8546     } else {
8547         $footnotes = ""; # else they get re-used
8548         $_ = join ('', '<BR><HR><H4>', $title, '</H4>', $_ );
8549     }
8550     $_;
8553 sub post_process_footnotes {
8554     &slurp_input($footfile);
8555     open(OUT, ">$footfile") || die "Cannot write file '$footfile': $!\n";
8556     &replace_markers;
8557     &post_post_process if (defined &post_post_process);
8558     &adjust_encoding;
8559     print OUT $_;
8560     close OUT;
8563 sub make_file {
8564     # Uses and modifies $_ defined in the caller
8565     local($filename, $title, $layout) = @_;
8566     $layout = $BODYTEXT unless $layout;
8567     $_ = join('',&make_head_and_body($title,$layout), $_
8568         , (($filename =~ /^\Q$footfile\E$/) ? '' : &make_address )
8569         , (($filename =~ /^\Q$footfile\E$/) ? "\n</BODY>\n</HTML>\n" : '')
8570         );
8571     &replace_markers unless ($filename eq $footfile); 
8573     unless(open(FILE,">$filename")) {
8574         print "\nError: Cannot write '$filename': $!\n";
8575         return;
8576     }
8577     print FILE $_;
8578     close(FILE);
8581 sub add_to_body {
8582     local($attrib, $value) = @_;
8583     local($body) = $BODYTEXT;
8584     if ($body =~ s/\Q$attrib\E\s*=\s*"[^"]*"/$attrib="$value"/) {
8585     } else {
8586         $body .= " $attrib=\"$value\""; $body =~ s/\s{2,}/ /g;
8587     }
8588     $BODYTEXT = $body if $body;
8591 sub replace_verbatim_marks {
8592     # Modifies $_
8593     my($tmp);
8594     s/$math_verbatim_rx/&make_comment('MATH', $verbatim{$1})/eg;
8595     s/$mathend_verbatim_rx/&make_comment('MATHEND', '')/eg;
8596 #    s/$verbatim_mark(verbatim\*?)(\d+)#/<PRE>\n$verbatim{$2}\n<\/PRE>/go;
8597 ##    s/$verbatim_mark(\w*[vV]erbatim\*?)(\d+)#/\n$verbatim{$2}\n/go;
8598     s!$verbatim_mark(\w*[vV]erbatim\*?|tex2html_code)(\d+)#\n?!$tmp=$verbatim{$2};
8599         $tmp.(($tmp =~/\n\s*$/s)? '':"\n")!eg;
8600 #       "\n".$tmp.(($tmp =~/\n\s*$/s)? '':"\n")!eg;
8601 #    s/$verbatim_mark(rawhtml)(\d+)#/$verbatim{$2}/eg; # Raw HTML
8602     s/$verbatim_mark(imagesonly)(\d+)#//eg; # imagesonly is *not* replaced
8603     # Raw HTML, but replacements may have protected characters
8604     s/$verbatim_mark(rawhtml)(\d+)#/&unprotect_raw_html($verbatim{$2})/eg;
8605     s/$verbatim_mark$keepcomments_rx(\d+)#/$verbatim{$2}/ego; # Raw TeX
8606     s/$unfinished_mark$keepcomments_rx(\d+)#/$verbatim{$2}/ego; # Raw TeX
8609 # TeX's special characters may have been escaped with a '\'; remove it.
8610 sub unprotect_raw_html {
8611     local($raw) = @_;
8612     $raw =~ s/\\($latex_specials_rx|~|\^|@)/$1/g;
8613     $raw;
8616 # remove file-markers; special packages may redefine &replace_file_marks
8617 sub remove_file_marks {
8618     s/<(DD|LI)>\n?($file_mark|$endfile_mark)\#.*\#\n<\/\1>(\n|(<))/$4/gm;
8619     s/($file_mark|$endfile_mark)\#.*\#(\n|(<))/$3/gm;
8621 sub replace_file_marks { &remove_file_marks }
8623 sub remove_verbatim_marks {
8624     # Modifies $_
8625     s/($math_verbatim_rx|$mathend_verbatim_rx)//go;
8626 #    s/$verbatim_mark(verbatim\*?)(\d+)#//go;
8627     s/$verbatim_mark(\w*[Vv]erbatim\w*\*?)(\d+)#//go;
8628     s/$verbatim_mark(rawhtml|imagesonly)(\d+)#//go;
8629     s/$verbatim_mark$keepcomments_rx(\d+)#//go;
8630     s/$unfinished_mark$keepcomments_rx(\d+)#//go;
8633 sub replace_verb_marks {
8634     # Modifies $_
8635     s/(?:$verb_mark|$verbstar_mark)(\d+)$verb_mark/
8636         $code = $verb{$1};
8637         $code = &replace_comments($code) if ($code =~ m:$comment_mark:);
8638         "<code>$code<\/code>"/ego;
8641 sub replace_comments{
8642     local($_) = @_;
8643     $_ =~ s/$comment_mark(\d+)\n?/$verbatim{$1}/go;
8644     $_ =~ s/$comment_mark\d*\n/%\n/go;
8645     $_;
8648 sub remove_verb_marks {
8649     # Modifies $_
8650     s/($verb_mark|$verbstar_mark)(\d+)$verb_mark//go;
8653 # This is used by revert_to_raw_tex
8654 sub revert_verbatim_marks {
8655     # Modifies $_
8656 #    s/$verbatim_mark(verbatim)(\d+)#/\\begin{verbatim}$verbatim{$2}\\end{verbatim}\n/go;
8657     s/$verbatim_mark(\w*[Vv]erbatim)(\d+)#/\\begin{$1}\n$verbatim{$2}\\end{$1}\n/go;
8658     s/$verbatim_mark(rawhtml)(\d+)#/\\begin{rawhtml}\n$verbatim{$2}\\end{rawhtml}\n/go;
8659     s/$verbatim_mark(imagesonly|tex2html_code)(\d+)#\n?/$verbatim{$2}/go;
8660     s/$verbatim_mark$image_env_rx(\d+)#/\\begin{$1}\n$verbatim{$2}\\end{$1}\n/go;
8661     s/($math_verbatim_rx|$mathend_verbatim_rx)//go;
8664 sub revert_verb_marks {
8665     # Modifies $_
8666     s/$verbstar_mark(\d+)$verb_mark/\\verb*$verb_delim{$1}$verb{$1}$verb_delim{$1}/go;
8667     s/$verb_mark(\d+)$verb_mark/\\verb$verb_delim{$1}$verb{$1}$verb_delim{$1}/go;
8670 sub replace_cross_ref_marks {
8671     # Modifies $_
8672     local($label,$id,$ref_label,$ref_mark,$after,$name);
8673     local($invis) = "<tex2html_anchor_invisible_mark></A>";
8674 #    s/$cross_ref_mark#([^#]+)#([^>]+)>$cross_ref_mark/
8675     s/$cross_ref_mark#([^#]+)#([^>]+)>$cross_ref_mark<\/A>(\s*<A( NAME=\"\d+)\">$invis)?/
8676         do {($label,$id) = ($1,$2); $name = $4;
8677             $ref_label = $external_labels{$label} unless
8678                 ($ref_label = $ref_files{$label});
8679             print "\nXLINK<: $label : $id :$name " if ($VERBOSITY > 3);
8680             $ref_label = '' if ($ref_label eq $CURRENT_FILE);
8681             $ref_mark = &get_ref_mark($label,$id);
8682             &extend_ref if ($name); $name = '';
8683             print "\nXLINK: $label : $ref_label : $ref_mark " if ($VERBOSITY > 3);
8684             '"' . "$ref_label#$label" . "\">" . $ref_mark . "<\/A>"
8685         }/geo;
8687     # This is for pagerefs which cannot have symbolic labels ??? 
8688 #    s/$cross_ref_mark#(\w+)#\w+>/
8689     s/$cross_ref_mark#([^#]+)#[^>]+>/
8690         do {$label = $1;
8691             $ref_label = $external_labels{$label} unless
8692                 ($ref_label = $ref_files{$label});
8693             $ref_label = '' if ($ref_label eq $CURRENT_FILE);
8694             print "\nXLINKP: $label : $ref_label" if ($VERBOSITY > 3);
8695             '"' . "$ref_files{$label}#$label" . "\">"
8696         }/geo;
8699 #RRM: this simply absorbs the name from the invisible anchor following, 
8700 #     when the anchor itself is not already named.
8701 sub extend_ref {
8702     if ($ref_label !=~ /NAME=/) { $label .= "\"\n".$name  }
8705 sub remove_cross_ref_marks {
8706     # Modifies $_
8707 #    s/$cross_ref_mark#(\w+)#(\w+)>$cross_ref_mark/
8708     s/$cross_ref_mark#([^#]+)#([^>]+)>$cross_ref_mark/
8709         print "\nLOST XREF: $1 : $2" if ($VERBOSITY > 3);''/ego;
8710 #    s/$cross_ref_mark#(\w+)#\w+>//go;
8711     s/$cross_ref_mark#([^#]+)#[^#>]+>//go;
8714 sub replace_external_ref_marks {
8715     # Modifies $_
8716     local($label, $link);
8717 #    s/$external_ref_mark#(\w+)#(\w+)>$external_ref_mark/
8718     s/$external_ref_mark#([^#]+)#([^>]+)>$external_ref_mark/
8719         do {($label,$id) = ($1,$2); 
8720             $link = $external_labels{$label};
8721             print "\nLINK: $label : $link" if ($VERBOSITY > 3);
8722             '"'. "$link#$label" . "\">\n"
8723                . &get_ref_mark("userdefined$label",$id)
8724         }
8725     /geo;
8728 sub remove_external_ref_marks {
8729     # Modifies $_
8730 #    s/$external_ref_mark#(\w+)#(\w+)>$external_ref_mark/
8731     s/$external_ref_mark#([^#]+)#([^>]+)>$external_ref_mark/
8732         print "\nLOST LINK: $1 : $2" if ($VERBOSITY > 3);''/ego;
8735 sub get_ref_mark {
8736     local($label,$id) = @_;
8737     ( ( $SHOW_SECTION_NUMBERS && $symbolic_labels{"$label$id"}) ||
8738      $latex_labels{"userdefined$label$id"} ||
8739      $symbolic_labels{"$label$id"} ||
8740      $latex_labels{$label} ||
8741      $external_latex_labels{$label} ||
8742      $cross_ref_visible_mark );
8745 sub replace_bbl_marks {
8746     # Modifies $_
8747     s/$bbl_mark#([^#]+)#/$citations{$1}/go;
8750 sub remove_bbl_marks {
8751     # Modifies $_
8752     s/$bbl_mark#([^#]+)#//go;
8755 sub replace_image_marks {
8756     # Modifies $_
8757     s/$image_mark#([^#]+)#([\.,;:\)\]])?(\001)?([ \t]*\n?)(\001)?/
8758         "$id_map{$1}$2$4"/ego;
8759 #       "$id_map{$1}$2".(($4)?"\n":'')/ego;
8762 sub remove_image_marks {
8763     # Modifies $_
8764     s/$image_mark#([^#]+)#//go;
8767 sub replace_icon_marks {
8768     # Modifies $_
8769     if ($HTML_VERSION < 2.2 ) {
8770         local($icon);
8771         s/$icon_mark_rx/$icon = &img_tag($1);
8772             $icon =~ s| BORDER="?\d+"?||;$icon/ego;
8773     } else {
8774         s/$icon_mark_rx/&img_tag($1)/ego;
8775     }
8778 sub remove_icon_marks {
8779     # Modifies $_
8780     s/$icon_mark_rx//go;
8783 sub replace_cite_marks {
8784     local($key,$label,$text,$file);
8785     # Modifies $_
8786     # Uses $citefile set by the thebibliography environment
8787     local($citefile) = $citefile;
8788     $citefile =~ s/\#.*$//;
8789     
8790     s/#([^#]+)#$cite_mark#([^#]+)#((($OP\d+$CP)|[^#])*)#$cite_mark#/
8791         $text = $3; $label= $1; $file='';
8792         $text = $cite_info{$1} unless $text;
8793         if ($checking_caption){
8794             "$label"
8795         } elsif ($citefiles{$2}){
8796             $file = $citefiles{$2}; $file =~ s:\#.*$::;
8797             &make_named_href('', "$file#$label","$text");
8798         } elsif ($PREAMBLE) {
8799             $text || "\#!$1!\#" ;
8800         } elsif ($simplifying) {
8801             $text
8802         } else {
8803              &write_warnings("\nno reference for citation: $1");
8804              "\#!$1!\#"
8805         }/sge ;
8806     #
8807     #RRM: Associate the cite_key with  $citefile , for use by other segments.
8808     if ($citefile) {
8809         local($cite_key, $cite_ref);
8810         while (($cite_key, $cite_ref) = each %cite_info) {
8811             if ($ref_files{'cite_'."$cite_key"} ne $citefile) {
8812                 $ref_files{'cite_'."$cite_key"} = $citefile;
8813                 $changed = 1; }
8814         }
8815     }
8818 sub remove_cite_marks {
8819     # Modifies $_
8820     s/#([^#]+)#$cite_mark#([^#]+)#([^#]*)#$cite_mark#//go;
8823 sub remove_anchors {
8824 # modifies $_
8825     s/<A[^>]*>//g;
8826     s/<\/A>//g;
8830 # We need two matching keys to determine section/figure/etc. numbers.
8831 # The "keys" are the name of the section/figure/etc. and its
8832 # equivalent in the .aux file (also carrying the number we desire).
8833 # But both keys might have been translated slightly different,
8834 # depending on the usage of math, labels, special characters such
8835 # as umlauts, or simply spacing!
8837 # This routine tries to squeeze the HTML translated keys such
8838 # that they match (hopefully very often). -- JCL
8840 sub sanitize {
8841     local($_,$mode) = @_;
8842     &remove_markers;
8843     &remove_anchors;
8844     &text_cleanup;
8845     s/(\&|;SPM)nbsp;//g;            # HWS - LaTeX changes ~ in its .aux files
8846     #strip unwanted HTML constructs
8847     s/<\/?(P|BR|H)[^>]*>//g;
8848     s/\s+//g; #collapse white space
8849     $_;
8852 # This one removes any HTML markup, so that pure
8853 # plain text remains. (perhaps with <SUP>/<SUB> tags)
8854 # As the result will be part of the HTML file, it will be
8855 # &text_cleanup'd later together with its context.
8857 sub purify {
8858     local($_,$strict) = @_;
8859     &remove_markers;
8860     #strip unwanted HTML constructs
8861 #    s/<[^>]*>/ /g;
8862     s/<(\/?SU[BP])>/>$1>/g unless ($strict);  # keep sup/subscripts ...
8863     s/<[^>]*>//g;                             # remove all other tags
8864     s/>(\/?SU[BP])>/<$1>/g unless ($strict);  # ...reinsert them
8865     s/^\s+|\001//g; s/\s\s+/ /g;              #collapse white space
8866     $_;
8869 # This one is not as strict as &sanitize.
8870 # It is chosen to strip section names etc. a bit from
8871 # constructs so that it better fits a table of contents,
8872 # label files, etc.
8873 # As the result will be part of the HTML file, it will be
8874 # &text_cleanup'd later together with its context.
8876 sub simplify {
8877     local($_) = @_;
8878     local($simplifying) = 1;
8879     s/$tex2html_envs_rx//g;
8880     if (/\\/) {
8881         local($USING_STYLES) = 0;
8882         $_ = &translate_commands($_);
8883         undef $USING_STYLES;
8884     }
8885     &replace_external_ref_marks if /$external_ref_mark/;
8886     &replace_cross_ref_marks if /$cross_ref_mark||$cross_ref_visible_mark/;
8887     &replace_cite_marks if /$cite_mark/;
8888     # strip unwanted HTML constructs
8889 #    s/<\/?H[^>]*>/ /g;
8890     s/<\/?(H)[^>]*>//g;
8891     s/<\#\d+\#>//g;
8892     s/^\s+//;
8893     $_;
8896 #RRM: This extracts $anchor_mark portions from a given chunk of text,
8897 #     so they can be positioned separately by the calling subroutine.
8898 # added for v97.2: 
8899 #  search within the immediately following text also; so that 
8900 #  \index and \label after section-headings work as expected.
8902 sub extract_anchors {
8903     local($search_text, $start_only) = @_; 
8904     local($anchors) = '';
8905     local($untranslated_anchors) = '';
8907     do {
8908         while ($search_text =~ s/<A[^>]*>($anchor_mark|$anchor_invisible_mark)<\/A>//) {
8909             $anchors .= $&;
8910         }
8911     } unless ($start_only);
8912     
8913     $search_text =~ s/\s*(\\protect)?\\(label|index|markright|markboth\s*(($O|$OP)\d+($C|$CP))[^<]*\3)\s*(($O|$OP)\d+($C|$CP))[^<]*\6/
8914         $anchors .= $&;''/eg unless ($start_only);
8916     while ( s/^\s*<A[^>]*>($anchor_mark|$anchor_invisible_mark)<\/A>//m) {
8917         $untranslated_anchors .= $&;
8918     }
8919     while ( s/^\s*(\\protect)?\\(label|index|markright|markboth\s*(($O|$OP)\d+($C|$CP))[^<]*\3)\s*(($O|$OP)\d+($C|$CP))[^<]*\6//) {
8920         $untranslated_anchors .= $&;
8921     }
8922     if ($TITLE||$start_only) {
8923         $anchors .= &translate_commands($untranslated_anchors);
8924         $untranslated_anchors = '';
8925     }
8926     ($anchors.$untranslated_anchors,$search_text); 
8929 # This routine must be called once on the text only,
8930 # else it will "eat up" sensitive constructs.
8931 sub text_cleanup {
8932     # MRO: replaced $* with /m
8933     s/(\s*\n){3,}/\n\n/gom;     # Replace consecutive blank lines with one
8934     s/<(\/?)P>\s*(\w)/<$1P>\n$2/gom;      # clean up paragraph starts and ends
8935     s/$O\d+$C//go;              # Get rid of bracket id's
8936     s/$OP\d+$CP//go;            # Get rid of processed bracket id's
8937     s/(<!)?--?(>)?/(length($1) || length($2)) ? "$1--$2" : "-"/ge;
8938     # Spacing commands
8939     s/\\( |$)/ /go;
8940     #JKR: There should be no more comments in the source now.
8941     #s/([^\\]?)%/$1/go;        # Remove the comment character
8942     # Cannot treat \, as a command because , is a delimiter ...
8943     s/\\,/ /go;
8944     # Replace tilde's with non-breaking spaces
8945     s/ *~/&nbsp;/g;
8947     ### DANGEROUS ?? ###
8948     # remove redundant (not <P></P>) empty tags, incl. with attributes
8949     s/\n?<([^PD >][^>]*)>\s*<\/\1>//g;
8950     s/\n?<([^PD >][^>]*)>\s*<\/\1>//g;
8951     # remove redundant empty tags (not </P><P> or <TD> or <TH>)
8952     s/<\/(TT|[^PTH][A-Z]+)><\1>//g;
8953     s/<([^PD ]+)(\s[^>]*)?>\n*<\/\1>//g;
8955     
8956 #JCL(jcl-hex)
8957 # Replace ^^ special chars (according to p.47 of the TeX book)
8958 # Useful when coming from the .aux file (german umlauts, etc.)
8959     s/\^\^([^0-9a-f])/chr((64+ord($1))&127)/ge;
8960     s/\^\^([0-9a-f][0-9a-f])/chr(hex($1))/ge;
8963 # This is useful for getting words from a title which are not cluttered
8964 # with tex2html markers or HTML constructs
8965 sub extract_pure_text {
8966     local($mode) = @_;
8967     &text_cleanup;              # Remove marking brackets
8969 # HWS <hswan@perc.Arco.com>:  Conditionally doing the following
8970 #     permits equations in section headings.
8972     if ($mode eq "strict") {
8973         s/$image_mark#[^#]*#//g;        # Remove image marker
8974         s/$bbl_mark#[^#]*#//g;          # Remove citations marker
8975         s/<tex2html_percent_mark>/%/g;  # BMcM: Retain % signs...
8976         s/<tex2html_ampersand_mark>/\&amp;/g;
8977         s/tex2html[\w\d]*//g;   # Remove other markers
8978         }
8981 # HWS <hswan@perc.Arco.com>:  Replace next statement with the following two
8982 #    to permit symbolic links and images to appear in section headings.
8984 #   s/<[^>]*>//go;                      # Remove HTML constructs
8985     s/$OP[^#]*$CP//go;                  # Remove <# * #> constructs
8986     s/<\s*>//go;                        # Remove embedded whitespace
8989 ############################ Misc ####################################
8991 # MRO: Print standardized header
8992 sub banner {
8993     print <<"EOF";
8994 This is LaTeX2HTML Version $TEX2HTMLVERSION
8995 by Nikos Drakos, Computer Based Learning Unit, University of Leeds.
8997 EOF
9000 # MRO: Extract usage information from POD
9001 sub usage {
9002     my $start  = 0;
9003     my $usage  = 'Usage: ';
9004     my $indent = '';
9006     print (@_, "\n") if @_;
9008     my $perldoc = "/usr/bin${dd}perldoc";
9009     my $script = $SCRIPT || $0;
9010     open(PIPE, "$perldoc -t $script |")
9011         || die "Fatal: can't open pipe: $!";
9012     while (<PIPE>) {
9013         if (/^\s*$/) {
9014             next;
9015         } elsif (/^SYNOPSIS/) {
9016             $start = 1;
9017         } elsif (/^\w/) {
9018             $start = 0;
9019         } elsif ($start == 1) {
9020             ($indent) = /^(\s*)/;
9021             s/^$indent/$usage/;
9022             $usage =~ s/./ /g;
9023             $start = 2;
9024             print $_;
9025         } elsif ($start == 2) {
9026             s/^$indent/$usage/;
9027             print $_;
9028         }
9029     }
9030     close PIPE;
9031     1;
9034 # The bibliographic references, the appendices, the lists of figures and tables
9035 # etc. must appear in the contents table at the same level as the outermost
9036 # sectioning command. This subroutine finds what is the outermost level and
9037 # sets the above to the same level;
9038 sub set_depth_levels {
9039     # Sets $outermost_level
9040     local($level);
9041     # scan the document body, not the preamble, for use of sectioning commands
9042     my ($contents) = $_;
9043     if ($contents =~ /\\begin\s*((?:$O|$OP)\d+(?:$C|$CP))document\1|\\startdocument/s) {
9044         $contents = $';
9045     }
9046     #RRM:  do not alter user-set value for  $MAX_SPLIT_DEPTH
9047     foreach $level ("part", "chapter", "section", "subsection",
9048                     "subsubsection", "paragraph") {
9049         last if (($outermost_level) = $contents =~ /\\($level)$delimiter_rx/);
9050         last if (($outermost_level) = $contents =~ /\\endsegment\s*\[\s*($level)\s*\]/s);
9051         if ($contents =~ /\\segment\s*($O\d+$C)[^<]+\1\s*($O\d+$C)\s*($level)\s*\2/s)
9052                 { $outermost_level = $3; last };
9053     }
9054     $level = ($outermost_level ? $section_commands{$outermost_level} :
9055               do {$outermost_level = 'section'; 3;});
9057     #RRM:  but calculate value for $MAX_SPLIT_DEPTH when a $REL_DEPTH was given
9058     if ($REL_DEPTH && $MAX_SPLIT_DEPTH) { 
9059         $MAX_SPLIT_DEPTH = $level + $MAX_SPLIT_DEPTH;
9060     } elsif (!($MAX_SPLIT_DEPTH)) { $MAX_SPLIT_DEPTH = 1 };
9062     %unnumbered_section_commands = (
9063           'tableofcontents', $level
9064         , 'listoffigures', $level
9065         , 'listoftables', $level
9066         , 'bibliography', $level
9067         , 'textohtmlindex', $level
9068         , %unnumbered_section_commands
9069         );
9071     %section_commands = ( 
9072           %unnumbered_section_commands
9073         , %section_commands
9074         );
9077 # Now ignores accents which cannot be translated to ISO-LATIN-1 characters
9078 # Also replaces ?' and !' ....
9079 sub replace_strange_accents { 
9080     &real_replace_strange_accents(@_); # if ($CHARSET =~ /8859[_\-]1$/);
9082 sub real_replace_strange_accents {
9083     # Modifies $_;
9084     s/\?`/&iso_map("iquest", "")/geo;
9085     s/!`/&iso_map("iexcl", "")/geo;
9086     s/\\\^\\i /&iso_map("icirc", "")/geo;
9087     my ($charset) = "${CHARSET}_character_map_inv";
9088     $charset =~ s/-/_/g;
9089     # convert upper 8-bit characters
9090     if (defined %$charset &&($CHARSET =~ /8859[_\-]1$/)) {
9091         s/([\200-\377])/
9092             $tmp = $$charset{'&#'.ord($1).';'};
9093             &mark_string($tmp) if ($tmp =~ m!\{!);
9094             &translate_commands($tmp)
9095         /egos
9096     }
9097 };
9099 # Creates a new directory or reuses old, perhaps after deleting its contents
9100 sub new_dir {
9101     local($this_dir,$mode) = @_;
9102     local(@files)=();
9103     $this_dir = '.' unless $this_dir;
9104     $this_dir =~ s/[$dd$dd]+$//o;
9105     local($print_dir) = $this_dir.$dd;
9106     (!$mode && mkdir($this_dir, 0755)) ||
9107         do {
9108             print "\nCannot create directory $print_dir: $!" unless ($mode);
9109             if ($REUSE) {
9110                 print ", reusing it.\n" unless ($mode);
9111                 &reuse($this_dir,$print_dir);
9112             } else {
9113                 print "\n" unless ($mode);
9114                 while (! ($answer =~ /^[dqr]$/)) {
9115                     if ($mode) {
9116                         $answer = $mode;
9117                     } else { 
9118                         print "(r) Reuse the images in the old directory OR\n"
9119                             . (($this_dir eq '.') ?
9120                 "(d) *** DELETE *** the images in $print_dir  OR\n"
9121                 : "(d) *** DELETE *** THE CONTENTS OF $print_dir  OR\n" )
9122                             . "(q) Quit ?\n:";
9123                         $answer = scalar(<STDIN>);
9124                     };
9125                     if ($answer =~ /^d$/) {
9126                         @files = ();
9127                         if(opendir(DIR,$this_dir)) {
9128                             @files = readdir DIR;
9129                             closedir DIR;
9130                         } else {
9131                             print "\nError: Cannot read dir '$this_dir': $!\n";
9132                         }
9133                         foreach (@files) {
9134                             next if /^\.+$/;
9135                             if (-d "$this_dir$dd$_") {
9136                                 &new_dir("$this_dir$dd$_",'d');
9137                             } elsif ($this_dir eq '.') {
9138                                 L2hos->Unlink($_) if (/\.(pl|gif|png)$/) 
9139                             } else {
9140                                 L2hos->Unlink("$this_dir$dd$_"); 
9141                             };
9142                         }
9143                         return(1) if ($this_dir eq '.');
9144                         if($mode) {
9145                           rmdir($this_dir);
9146                           rmdir($print_dir);
9147                         }
9148                         if (!$mode) { &new_dir($this_dir,'r')};
9149                         return(1);
9150                     } elsif ($answer =~ /^q$/) {
9151                         die "Bye!\n";
9152                     } elsif ($answer =~ /^r$/) {
9153                         &reuse($this_dir,$print_dir);
9154                         return(1);
9155                     } else {print "Please answer r d or q!\n";};
9156                 }
9157             };
9158         };
9159     1;
9162 sub reuse {
9163     local($this_dir,$print_dir) = @_;
9164     $print_dir = $this_dir.$dd unless ($print_dir);
9165     if (-f "$this_dir$dd${PREFIX}images.pl") {
9166         print STDOUT "Reusing directory $print_dir:\n";
9167         local($key);
9168         require("$this_dir$dd${PREFIX}images.pl");
9169     }
9173 # JCL(jcl-del) - use $CD rather than a space as delimiter.
9174 # The commands might take white space, or not, depending on
9175 # their definition. Eg. \relax takes white space, because it's a
9176 # letter command, but \/ won't.
9177 # TeX seems to have an internal separator: If \x is " x",
9178 # and \y is "y", then \expandafter\y \x expands to "y x", TeX
9179 # hasn't gobbled the space, meaning that spaces are gobbled once
9180 # when the \y token is consumed, but then never again after \y.
9182 # The actions below ensure to insert exactly one space after
9183 # the command name.     # what happens to  `\ '  ?
9184 # The substition is done twice to handle \one\delimits\another
9185 # cases.
9186 # The internal shortcut $CD is then turned into the single
9187 # space we desire.
9189 sub tokenize {
9190     # Modifies $_;
9191     local($rx) = @_;
9192     # $rx must be specially constructed, see &make_new_cmd_rx.
9193     if (length($rx)) {
9194         # $1: non-letter cmd, or $2: letter cmd
9195         s/$rx/\\$1$2$CD$4/g;
9196         s/$rx/\\$1$2$CD$4/g;
9197         s/$CD+/ /g;     # puts space after each command name
9198     }
9201 # When part of the input text contains special perl characters and the text
9202 # is to be used as a pattern then these specials must be escaped.
9203 sub escape_rx_chars {
9204     my($rx) = @_; # must use a copy of the string
9205     $rx =~ s:([\\(){}[\]\^\$*+?.|]):\\$1:g; $rx; }
9207 # Does not do much but may need it later ...
9208 # The document environment has to be removed because it spans
9209 # more than one sections (the translator can only deal with
9210 # environments wholly contained with sections).
9212 # (Does a little more now ... the end of the preamble is now marked
9213 # with an internally-generated command which causes all output
9214 # erroneously generated from unrecognized commands in the preamble
9215 # to vanish --- rst).
9217 sub remove_document_env {
9218 #    s/\\begin$match_br_rx[d]ocument$match_br_rx/\\latextohtmlditchpreceding /o;
9219     if (/\\begin\s*${match_br_rx}document$match_br_rx/) { 
9220         s/\\begin\s*$match_br_rx[d]ocument$match_br_rx/\\latextohtmlditchpreceding /
9221     }
9222 #   s/\\end$match_br_rx[d]ocument$match_br_rx(.|\n)*//o;
9223     if (/\\end\s*${match_br_rx}document$match_br_rx/) { $_ = $` }
9226 # And here's the code to handle the marker ...
9228 sub do_cmd_latextohtmlditchpreceding {
9229     local($_) = @_;
9230     $ref_before = '';
9231     $_;
9234 print "\n"; # flushes a cache? This helps, for some unknown reason!!
9236 sub do_AtBeginDocument{
9237     local($_) = @_;
9238     eval $AtBeginDocument_hook;
9239     $_;
9242 sub cleanup {
9243     local($explicit) = @_;
9244     return unless $explicit || !$DEBUG;
9246     if (opendir(DIR, '.')) {
9247         while (defined($_ = readdir(DIR))) {
9248             L2hos->Unlink($_)
9249                 if /\.ppm$/ || /^${PREFIX}images\.dvi$/ || /^(TMP[-._]|$$\_(image)?)/;
9250         }
9251         closedir (DIR);
9252     }
9254     L2hos->Unlink("WARNINGS") if ($explicit &&(-f "WARNINGS"));
9256     if ($TMPDIR && opendir(DIR, $TMPDIR)) {
9257         local(@files) = grep(!/^\.\.?$/,readdir(DIR));
9258         local($busy);
9259         foreach (@files) {
9260             $busy .= $_." " unless (L2hos->Unlink("$TMPDIR$dd$_"));
9261         }
9262         closedir (DIR);
9263         if ($busy) {
9264             print "\n\nFiles: $busy  are still in use.\n\n" if ($DEBUG);
9265         } else {
9266             &write_warnings("\n\n Couldn't remove $TMPDIR : $!")
9267                 unless (rmdir $TMPDIR);
9268         }
9269     }
9270     if (opendir(DIR, $TMP_)) {
9271         local(@files) = grep(!/^\.\.?$/,readdir(DIR));
9272         $busy = '';
9273         foreach (@files) {
9274             $busy .= "$_ " unless (L2hos->Unlink("$TMP_$dd$_"));
9275         }
9276         closedir (DIR);
9277         local($full_dir) = L2hos->Make_directory_absolute($TMP_);
9278         if ($busy) {
9279             print "\n\nFiles: $busy in $full_dir are still in use.\n\n"
9280                 if ($DEBUG);
9281         } else {
9282             &write_warnings("\n\nCouldn't remove directory '$full_dir': $!")
9283                 unless (rmdir $full_dir);
9284         }
9285     }
9288 sub handler {
9289     print "\nLaTeX2HTML shutting down.\n";
9290     kill ('INT', $child_pid) if ($child_pid);
9291     &close_dbm_database;
9292     &cleanup();
9293     exit(-1);
9296 # Given a filename or a directory it returns the file and the full pathname
9297 # relative to the current directory.
9298 sub get_full_path {
9299     local($file) = @_;
9300     local($path,$dir);
9301     if (-d $file) {     # $file is a directory
9302         $path = L2hos->Make_directory_absolute($file);
9303         $file = '';
9305 # JCL(jcl-dir)
9306     } elsif ($file =~ s|\Q$dd\E([^$dd$dd]*)$||o ) {
9307         $path = $file;
9308         $file = $1;
9309         $path = L2hos->Make_directory_absolute($path);
9311 #RRM: check within $TEXINPUTS directories
9312     } elsif (!($TEXINPUTS =~ /^\.$envkey$/)) {
9313         #check along directories in the $TEXINPUTS variable
9314         foreach $dir (split(/$envkey/,$TEXINPUTS)) {
9315             $dir =~ s/[$dd$dd]$//o;
9316             if (-f $dir.$dd.$file) {
9317                 $path = L2hos->Make_directory_absolute($dir);
9318                 last;
9319             }
9320         }
9321     } else {
9322         $path = L2hos->Cwd();
9323     }
9324     ($path, $file);
9328 # Given a directory name in either relative or absolute form, returns
9329 # the absolute form.
9330 # Note: The argument *must* be a directory name.
9331 # The whole function has been moved to override.pm
9335 # Given a relative filename from the directory in which the original
9336 # latex document lives, it tries to expand it to the full pathname.
9337 sub fulltexpath {
9338     # Uses $texfilepath defined in sub driver
9339     local($file) = @_;
9340     $file =~ s/\s//g;
9341     $file = "$texfilepath$dd$file"
9342       unless (L2hos->is_absolute_path($file));
9343     $file;
9346 #RRM  Extended to allow customised filenames, set $CUSTOM_TITLES
9347 #     or long title from the section-name, set $LONG_TITLES
9349 sub make_name {
9350     local($sec_name, $packed_curr_sec_id) = @_;
9351     local($title,$making_name,$saved) = ('',1,'');
9352     if ($LONG_TITLES) {
9353         $saved = $_;
9354         &process_command($sections_rx, $_) if /^$sections_rx/;
9355         $title = &make_long_title($TITLE)
9356             unless ((! $TITLE) || ($TITLE eq $default_title));
9357         $_ = $saved;
9358     } elsif ($CUSTOM_TITLES) {
9359         $saved = $_;
9360         &process_command($sections_rx, $_) if /^$sections_rx/;
9361         $title = &custom_title_hook($TITLE)
9362             unless ((! $TITLE) || ($TITLE eq $default_title));
9363         $_ = $saved;
9364     }
9365     if ($title) {
9366         #ensure no more than 32 characters, including .html extension
9367         $title =~ s/^(.{1,27}).*$/$1/;
9368         ++$OUT_NODE;
9369         join("", ${PREFIX}, $title, $EXTN);
9370     } else {
9371     # Remove 0's from the end of $packed_curr_sec_id
9372         $packed_curr_sec_id =~ s/(_0)*$//;
9373         $packed_curr_sec_id =~ s/^\d+$//o; # Top level file
9374         join("",($packed_curr_sec_id ? 
9375             "${PREFIX}$NODE_NAME". ++$OUT_NODE : $sec_name), $EXTN);
9376     }
9379 #RRM: redefine this subroutine, to create customised file-names
9380 #     based upon the actual section title.
9381 #     The default is empty, so reverts to:  node1, node2, ...
9383 sub custom_title_hook {
9384     local($_)= @_;
9385     "";
9389 sub make_long_title {
9390     local($_)= @_;
9391     local($num_words) = $LONG_TITLES;
9392     #RRM:  scan twice for short words, due to the $4 overlap
9393     #      Cannot use \b , else words break at accented letters
9394     $_ =~ s/(^|\s)\s*($GENERIC_WORDS)(\'|(\s))/$4/ig;
9395     $_ =~ s/(^|\s)\s*($GENERIC_WORDS)(\'|(\s))/$4/ig;
9396     #remove leading numbering, unless that's all there is.
9397     local($sec_num);
9398     if (!(/^\d+(\.\d*)*\s*$/)&&(s/^\s*(\d+(\.\d*)*)\s*/$sec_num=$1;''/e))
9399         { $num_words-- };
9400     &remove_markers; s/<[^>]*>//g; #remove tags
9401     #revert entities, etc. to TeX-form...
9402     s/([\200-\377])/"\&#".ord($1).";"/eg;
9403     $_ = &revert_to_raw_tex($_);
9405     # get $LONG_TITLES number of words from what remains
9406     $_ = &get_first_words($_, $num_words) if ($num_words);
9407     # ...and cleanup accents, spaces and punctuation
9408     $_ = join('', ($SHOW_SECTION_NUMBERS ? $sec_num : ''), $_);
9409     s/\\\W\{?|\}//g; s/\s/_/g; s/\W/_/g; s/__+/_/g; s/_+$//;
9410     $_;
9414 sub make_first_key {
9415     local($_);
9416     $_ = ('0 ' x keys %section_commands);
9417     s/^0/$THIS_FILE/ if ($MULTIPLE_FILES);  
9418     chop;
9419     $_;
9422 # This copies the preamble into the variable $preamble.
9423 # It also sets the LaTeX font size, if $FONT_SIZE is set.
9424 sub add_preamble_head {
9425     $preamble = join("\n", $preamble, @preamble);
9426     $preamble = &revert_to_raw_tex($preamble);
9427     $preamble = join ("\n", &revert_to_raw_tex(/$preamble_rx/o),
9428                                 $preamble);
9429     local($savedRS) = $/; undef $/;
9430     # MRO: replaced $* with /m
9431     $preamble =~ /(\\document(style|class))\s*(\[[^]]*\])?\s*\{/sm;
9432     local($before,$after) = ($`.$1, '{'.$');
9433     $/ = $savedRS;
9434     local ($options) = $3;
9435     if ($FONT_SIZE) {
9436         $options =~ s/(1\dpt)\b//;
9437         $options =~ s/(\[|\])//g;
9438         $options = "[$FONT_SIZE".($options ? ",$options" : '').']';
9439         $preamble = join('', $before, $options, $after );
9440         &write_mydb_simple("preamble", $preamble);
9441         @preamble = split(/\n/, $preamble);
9442         $LATEX_FONT_SIZE = $FONT_SIZE;
9443     }
9444     if (($options =~ /(1\dpt)\b/)&&(!$LATEX_FONT_SIZE)) {
9445         $LATEX_FONT_SIZE = $1;
9446     }
9447     #RRM: need to know the font-size before the .aux file is read
9448     $LATEX_FONT_SIZE = '10pt' unless ($LATEX_FONT_SIZE);
9451 # It is necessary to filter some parts of the document back to raw
9452 # tex before passing them to latex for processing.
9453 sub revert_to_raw_tex {
9454     local($_) = @_;
9455     local($character_map) = "";
9456     if ( $CHARSET && $HTML_VERSION ge "2.1" ) {
9457         $character_map = $CHARSET;
9458         $character_map =~ tr/-/_/; }
9459     while (s/$O\s*\d+\s*$C/\{/o) { s/$&/\}/;}
9460     while (s/$O\s*\d+\s*$C/\{/o) { s/$&/\}/;} #repeat this.
9461     # The same for processed markers ...
9462     while ( s/$OP\s*\d+\s*$CP/\{/o ) { s/$&/\}/; }
9463     while ( s/$OP\s*\d+\s*$CP/\{/o ) { s/$&/\}/;} #repeat this.
9465     s/<BR>/\\\\/g; # restores the \\ from \parbox's
9467     # revert any math-entities
9468     s/\&\w+#(\w+);/\\$1/g;
9469     s/\&limits;/\\limits/g;
9470     s/\\underscore/\\_/g;
9471     s/\\circflex/\\^/g;
9472     s/\\space/\\ /g;
9473     s/;SPMthinsp;/\\,/g;
9474     s/;SPMnegsp;/\\!/g;
9475     s/;SPMsp;/\\:/g;
9476     s/;SPMthicksp;/\\;/g;
9477     s/;SPMgg;/\\gg /g;
9478     s/;SPMll;/\\ll /g;
9479     s/;SPMquot;/"/g;
9481     # revert any super/sub-scripts
9482     s/<SUP>/\^\{/g;
9483     s/<SUB>/\_\{/g;
9484     s/<\/SU(B|P)>/\}/g;
9487 #    #revert common character entities  ??
9488 #    s/&#92;/\\/g;
9490 #    # revert special marks
9491 #    s/$percent_mark/\\%/go;
9492 ##    s/$comment_mark(\d+)\n/%$comments{$1}\n/go;
9493     local($tmp,$tmp2);
9494 #    s/$comment_mark(\d+)\n/$tmp=$verbatim{$1};chomp($tmp);$tmp."\n"/ego;
9495     s/$comment_mark(\d+)(\n|$|(\$))/$tmp=$verbatim{$1};$tmp2 = $3;
9496         ($tmp=~m!^\%!s ? '':'%').$tmp.(($tmp=~ m!\n\s*$!s)?'':"\n").$tmp2/sego;
9497     s/${verbatim_mark}tex2html_code(\d+)\#/$verbatim{$1}/go;
9498     s/^($file_mark|$endfile_mark).*\#\n//gmo;
9499     s/$comment_mark(\d*)\s*\n/%\n/go;
9500     s/$dol_mark/\$/go;
9501     s/$caption_mark//go;
9503     # From &pre_process.
9504     # MRO: replaced $* with /m
9505     s/\\\\[ \t]*(\n)?/\\\\$1/gm;
9507     # revert any array-cell delimiters
9508     s/$array_col_mark/\&/g;
9509     s/$array_row_mark/\\\\/g;
9510     s/$array_text_mark/\\text/g;
9511     s/$array_mbox_mark/\\mbox/g;
9513     # Replace any verbatim and image markers ...
9514     &revert_verbatim_marks;
9515     &revert_verb_marks;
9518 #    &replace_image_marks;
9519     s/$image_mark\#([^\#]+)\#/&recover_image_code($1)/eg;
9521     # remove artificial environments and commands
9523     s/(\n*)\\(begin|end)(($O|$OP)\d+($C|$CP))tex2html_b(egin)?group\3\n?/
9524         ($1? "\n":'')."\\".($6? $2:(($2 =~ m|end|)? 'e':'b'))."group\n"
9525     /gem;
9526     s/\\(begin|end)(\{|(($O|$OP)\d+($C|$CP|\})))(tex2html|verbatim)_code(\}|\3)\n?//gm;
9528     #take care not to concatenate \<cmd> with following letters
9529     local($tmp);
9530     s/(\\\w+)?$tex2html_wrap_rx([^\\\n])?/$tmp=$2;
9531         ((($tmp eq 'end')&&($1)&&!($5)&&($6))? "$1 $6":"$1$5$6")/egs;
9532     undef $tmp;
9533     s/\s*\\newedcommand\s*{/"%\n\\providecommand{\\"/gem;
9534     s/\\newedcommand\s*{/\\providecommand{\\/gom;
9535 #    s/(\n*)\\renewedcommand{/($1? "\n":'')."\\renewcommand{\\"/geo;
9536     s/\s*\\providedcommand\s*{/"%\n\\providecommand{\\"/gem;
9537 #    s/\\providedcommand{/\\providecommand{\\/go;
9538     s/\\renewedenvironment\s*/\\renewenvironment/gom;
9539     s/\\newedboolean\s*{/\\newboolean{/gom;
9540     s/\\newedcounter\s*{/\\newcounter{/gom;
9541     s/\\newedtheorem\s*{/\\newtheorem{/gom;
9542     s/\\xystar/\\xy\*/gom; # the * has a special meaning in Xy-pic
9544     #fix-up the star'd environment names
9545     s/(\\(begin|end)(($O|$OP)\d+($C|$CP))[^<]*)star\3/$1\*$3/gm;
9546     s/(\\(begin|end)\{[^\}]*)star\}/$1\*\}/gm;
9547     s/\\(begin|end)\{[^\}]*begin(group)\}/\\$1$2/gm;
9548     s/\\(b|e)(egin|end)\{[^\}]*b(group)\}/\\$1$3/gm;
9550     s/(\\(\w+)TeX)/($language_translations{$2}? "\\selectlanguage{$2}": $1)/egom;
9552     if ($PREPROCESS_IMAGES) {
9553       while (/$pre_processor_env_rx/m) {
9554         $done .= $`; $pre_env = $5; $which =$1; $_ = $';
9555         if (($which =~ /begin/)&&($pre_env =~ /indica/)) {
9556             ($indic, $dum) = &get_next_optional_argument;
9557             $done .= "\#$indic";
9558         } elsif (($which =~ /begin/)&&($pre_env =~ /itrans/)) {
9559             ($indic, $dum) = &get_next_optional_argument;
9560             $done .= "\#$indic";
9561         } elsif (($which =~ /end/)&&($pre_env =~ /indica/)) {
9562             $done .= '\#NIL';
9563         } elsif (($which =~ /end/)&&($pre_env =~ /itrans/)) {
9564             $done .= "\#end$indic";
9565         } elsif ($which =~ /begin/) {
9566             $done .= (($which =~ /end/)? $end_preprocessor{$pre_env}
9567                           : $begin_preprocessor{$pre_env} )
9568         }
9569         $_ = $done . $_;
9570       }
9571     }
9572     s/\\ITRANSinfo\{(\w+)\}\{([^}]*)\}/\#$1=$2/gm if $itrans_loaded;
9574     s/\n{3,}/\n\n/gm; # remove multiple (3+) new-lines 
9575     s/^\n+$//gs; # ...especially if that is all there is!
9576     if ($PREAMBLE) {
9577         s/$comment_mark(\d+\n?)?//g;
9578 #       $preamble =~ s/\\par\n?/\n/g;
9579         s/\\par\b/\n/g;
9580         s/^\s*$//g; #remove blank lines in the preamble
9581     };
9583     s/($html_specials_inv_rx)/$html_specials_inv{$1}/geo;
9584     # revert entities to TeX code, except if in {rawhtml} environments
9585     if (!($env =~ /rawhtml/)) {
9586         s/$character_entity_rx/( $character_map ?
9587           eval "\$${character_map}_character_map_inv\{\"$1\"\}" :
9588             $iso_8859_1_character_map_inv{$1} ||
9589               $iso_10646_character_map_inv{$1})/geo;
9590         s/$named_entity_rx/( $character_map ? 
9591           eval "\$${character_map}_character_map_inv\{\$${character_map}_character_map{'$1'}}" :
9592             $iso_8859_1_character_map_inv{$iso_8859_1_character_map{$1}} ||
9593               $iso_10646_character_map_inv{$iso_10646_character_map{$1}})/geo;
9595     } else {
9596         #RRM: check for invalid named entities in {rawhtml} environments
9597         s/($named_entity_rx)/&write_warnings(
9598             "An unknown named entity ($1) appears in the source text.") unless (
9599                  $character_map && eval 
9600           "\$${character_map}_character_map_inv\{\$${character_map}_character_map{'$2'}}");
9601                      ";SPM$2;"/ego;
9602     }
9604     #RRM: check for numbered character entity out-of-range
9605     if ($HTML_VERSION < 4.0) {
9606         s/$character_entity_rx/&write_warnings(
9607             "An invalid character entity ($1) appears in the source text.")
9608              if ($2 > 255);
9609         $1/ego; }
9611     #RRM: check for invalid named entities outside {rawhtml} environments
9612     # --- these should have been caught already, but check again
9613     s/$named_entity_rx/&write_warnings(
9614             "An unknown named entity ($1) appears in the source text.") unless (
9615         $character_map && eval 
9616           "\$${character_map}_character_map_inv\{\$${character_map}_character_map{'$1'}}");
9617                      $1/ego;
9619     &revert_to_raw_tex_hook if (defined &revert_to_raw_tex_hook);
9620     $_;
9623 sub next_wrapper {
9624     local($dollar) = @_;
9625     local($_,$id);
9626     $wrap_toggle = (($wrap_toggle eq 'end') ? 'begin' : 'end');
9627     $id = ++$global{'max_id'};
9628     $_ = "\\$wrap_toggle$O$id$C"."tex2html_wrap$O$id$C";
9629     $_ = (($wrap_toggle eq 'end') ? $dollar.$_ : $_.$dollar);
9630     $_;
9633 sub make_wrapper {
9634     &make_any_wrapper($_[0], '', "tex2html_wrap");
9637 sub make_nowrapper {
9638     &make_any_wrapper($_[0], 1, "tex2html_nowrap");
9641 sub make_inline_wrapper {
9642     &make_any_wrapper($_[0], '', "tex2html_wrap_inline");
9645 sub make_deferred_wrapper {
9646     &make_any_wrapper($_[0], 1, "tex2html_deferred");
9649 sub make_nomath_wrapper {
9650     &make_any_wrapper($_[0], '', "tex2html_nomath_inline");
9653 sub make_any_wrapper {
9654     local($toggle,$break,$kind) = @_;
9655     local($max_id) = ++$global{'max_id'};
9656     '\\'. (($toggle) ? 'begin' : 'end')
9657         . "$O$max_id$C"."$kind$O$max_id$C"
9658         . (($toggle || !$break) ? '' : '');
9661 sub get_last_word {
9662     # Returns the last word in multi-line strings
9663     local($_) = @_;
9664     local ($word,$lastbit,$which);
9665 #JCL(jcl-tcl)
9666 # also remove anchors and other awkward HTML markup
9667 #    &extract_pure_text("strict");
9668 ##    $_ = &purify($_);  ## No. what if it is a verbatim string or image?
9670 #    while (/\s(\S+)\s*$/g) { $word = $lastbit = $1;}
9672     if (!$_ && (defined $keep)) {
9673         # inside mathematics !
9674         $_ = $keep . $pre ;
9675     }
9676     if (!$_ && $ref_before) { $_ = $ref_before; }
9677     elsif (!$_) {
9678         # get it from last thing before the current environment
9679         $which = $#processedE;
9680         $_ = $processedE[$which];
9681     }
9683     while (/((($O|$OP)\d+($C|$CP))[.\n]*\2|\s(\S+))\s*$/g)
9684         { $word = $lastbit = $1 }
9685     if (($lastbit =~ s/\$\s*$//)||(defined $keep)) {
9686         local($br_idA) = ++$global{'max_id'};
9687         local($br_idB) = ++$global{'max_id'};
9688         $lastbit = join('', "\\begin $O$br_idA${C}tex2html_wrap_inline$O$br_idA$C\$"
9689                 , $lastbit, "\$\\end $O$br_idB${C}tex2html_wrap_inline$O$br_idB$C");
9690         $lastbit = &translate_environments($lastbit);
9691         $lastbit = &translate_commands($lastbit);
9692         return ($lastbit);
9693     }
9694     if ($lastbit =~ s/($O|$OP)\d+($C|$CP)//g) { return ($lastbit); }
9695     elsif ($lastbit eq '') { return ($_) }
9697     local($pre_bit);
9698     if ($lastbit =~/>([^>]*)$/) { 
9699         $word = $1; $pre_bit = $`.'>';
9700         if ($pre_bit =~ /($verb_mark|$verbstar_mark)$/) {
9701             $word = $lastbit;
9702         } elsif ($pre_bit =~ /<\w+_mark>$/) {
9703             $word = $& . $word;
9704         } elsif (!($word)) {
9705             if ($lastbit =~ s/<([^\/][^>]*)>$//o)
9706                 { $word=$1; $pre_bit = $`; }
9707             elsif ($lastbit =~ s/>([^<]*)<\/[^>]*>//o)
9708                 { $word=$1; $pre_bit = $`.'>' }
9709             else { $word = ";SPMnbsp;"; }
9710         }
9711 #       if ($pre_bit =~ /<\w+_mark>$/) { $word = $& . $word }
9712      } else { $word = $lastbit };
9713     $word;
9716 #JCL(jcl-tcl)
9717 # changed completely
9719 # We take the first real words specified by $min from the string.
9720 # Allow for simple HTML constructs like <I>...</I> (but not <H*>
9721 # or <P*> and the like), math, or images to remain in the result,
9722 # not counting as words.
9723 # Take care that eg. <I>...</I> grouping tags are not broken.
9724 # This is achieved by lifting the markup, removing superfluous
9725 # words, re-inserting the markup, and throw empty markup away.
9726 # In later versions images could be modified such that they become
9727 # thumbnail sized.
9729 # rawhtml or verbatim environments might introduce lots of awkward
9730 # stuff, but yet we leave the according tex2html markers in.
9732 sub get_first_words {
9733     local($_, $min) = @_;
9734     local($words,$i);
9735     local($id,%markup);
9736     #no limit if $min is negative
9737     $min = 1000 if ($min < 0);
9739     &remove_anchors;
9740     #strip unwanted HTML constructs
9741     s/<\/?(P|BR|H)[^>]*>/ /g;
9742     #remove leading white space and \001 characters
9743     s/^\s+|\001//g;
9744     #lift html markup, numbered for recovery
9745     s/(<[^>]*>(#[^#]*#)?)/$markup{++$id}=$1; "\000$id\000"/ge;
9747     foreach (split /\s+|\-{3,}/) {
9748         # count words (incl. HTML markup as part of the word)
9749         ++$i; 
9750 #       $words .= $_ . " " if (/\000/ || ($i <= $min));
9751         $words .= $_ . " " if ($i <= $min);
9752     }
9753     $_ = $words;
9754     chop;
9756     #re-insert markup
9757     s/\000(\d+)\000/$markup{$1}/g;
9758     # remove empty markup
9759     # it's normalized, because generated by LaTeX2HTML only
9760     s/<([A-Z]+)[^>]*>\s*<\/\1>\s*//g;
9761     $_;
9764 sub replace_word {
9765     # Replaces the LAST occurrence of $old with $new in $str;
9766     local($str, $old, $new) = @_;
9767     substr($str,rindex($str,$old),length($old)) = $new;
9768     $str;
9771 # Returns the recognised sectioning commands as a string of alternatives
9772 # for use in regular expressions;
9773 sub get_current_sections {
9774     local($_, $key);
9775     foreach $key (keys %section_commands) {
9776         if ($key =~ /star/) {
9777             $_ = $key . "|" . $_}
9778         else {
9779             $_ .= "$key" . '[*]?|';
9780         }
9781     }
9782     chop;                       # Remove the last "|".
9783     $_;
9786 sub numerically {
9787     local(@x) = split(' ',$a);
9788     local(@y) = split(' ',$b);
9789     local($i, $result);
9790     for($i=0;$i<$#x;$i++) {
9791        last if ($result = ($x[$i] <=> $y[$i]));
9792     }
9793     $result
9796 # Assumes that the files to be sorted are of the form
9797 # <NAME><NUMBER>
9798 sub file_sort {
9799     local($i,$j) = ($a,$b);
9800     $i =~ s/^[^\d]*(\d+)$/$1/;
9801     $j =~ s/^[^\d]*(\d+)$/$1/;
9802     $i <=> $j
9805 # If a normalized command name exists, return it.
9806 sub normalize {
9807     # MRO: modified to use $_[1]
9808     # local($cmd,*after) = @_;
9809     my $cmd =$_[0];
9810     my $ncmd;
9811     # Escaped special LaTeX characters
9812     if ($cmd =~ /^($latex_specials_rx)/) {
9813 #       $cmd =~ s/&(.*)$/&amp;$1/o;
9814         $cmd =~ s/&(.*)$/$ampersand_mark$1/o;
9815         $cmd =~ s/%/$percent_mark/o;
9816         $_[1] = join('', $cmd, $_[1]);
9817         $cmd = ""}
9818     elsif ($ncmd = $normalize{$cmd}) {
9819         $ncmd;
9820     }
9821     else {
9822         $cmd =~ s/[*]$/star/;
9823         $cmd =~ s/\@/_at_/g;
9824         $cmd;
9825     }
9828 sub normalize_sections {
9829     my $dummy = '';
9830     # MRO: s/$sections_rx/'\\' . &normalize($1.$2,*after) . $4/ge;
9831     s/$sections_rx/'\\' . &normalize($1.$2,$dummy) . $4/ge;
9834 sub embed_image {
9835     my ($url,$name,$external,$altst,$thumbnail,$map,$align,
9836         $usemap,$exscale,$exstr) = @_;
9837     my $imgID = '';
9838     my $urlimg = $url;
9839     my $ismap = $map ? " ISMAP" : '';
9840     print "\nembedding $url for $name, with $altst\n" if ($VERBOSITY > 1);
9842     if (! ($NO_IMAGES || $PS_IMAGES)) {
9843         # for over-scaled GIFs with pre-determined sizes        # RRM 11-9-96
9844         my $size;
9845         if (($width{$name})&&(($exscale)||($EXTRA_IMAGE_SCALE))) {
9846             $exscale = $EXTRA_IMAGE_SCALE unless ($exscale);
9847             if ($name =~ /inline|indisplay|entity|equation|math|eqn|makeimage/){
9848                 ($size, $imgID) = &get_image_size($url, $exscale);
9849             } else {
9850                 ($size, $imgID) = &get_image_size($url,'');
9851             }
9852         } else {
9853             ($size,$imgID) = &get_image_size($url,'');
9854         }
9855         $image_size{$url} = $size 
9856             unless ((! $size) || ($size eq "WIDTH=\"0\" HEIGHT=\"0\""));
9857         $url = &find_unique($url);
9858     }
9860     $urlimg = $url;
9861     $urlimg =~ s/\.$IMAGE_TYPE$/.html/ if ($map);
9862     if ($exstr =~ s/align\s*=\s*(\"?)(\w+)\1($|\s|,)//io) { $align = $2; }
9863     my $usersize = '';
9864     if ($exstr =~ s/width\s*=\s*(\"?)([^\s,]+)\1($|\s|,)//io) {
9865         my ($pxs,$len) = &convert_length($2);
9866         $usersize = " WIDTH=\"$pxs\"";
9867     }
9868     if ($exstr =~ s/height\s*=\s*(\"?)([^\s,]+)\1($|\s|,)//io) { 
9869         my ($pxs,$len) = &convert_length($2);
9870         $usersize .= " HEIGHT=\"$pxs\"";
9871     }
9873     my $border = '';
9874     $border = "\" BORDER=\"0"
9875         unless (($HTML_VERSION < 2.2 )||($exstr =~ /BORDER/i));
9877     my $aalign;
9878     if (($name =~ /figure|table|displaymath\d+|eqnarraystar/)&&(!$align)) {
9879     } elsif ($name =~ /displaymath_/) {
9880         $aalign = "MIDDLE".$border;
9881     } elsif (($name =~ /(equation|eqnarray)($|\d)/)&&(!$align)) {
9882         if ($HTML_VERSION >= 3.2) {
9883             $aalign =  ($EQN_TAGS eq "L") ? "RIGHT" : "LEFT";
9884         }
9885     } elsif ($name =~ /inline|display|entity|xy|diagram/ && $depth{$name} != 0) {
9886         $aalign = "MIDDLE".$border;
9887     } elsif ($name =~ /inpar/m) {
9888         $aalign = "TOP".$border;
9889     } else {  $aalign = "BOTTOM".$border }
9891     $aalign = "\U$align" if $align;
9892     my $ausemp = $usemap ? "\UUSEMAP=$usemap" : '';
9894     #append any extra valid options 
9895     $ismap .= &parse_keyvalues ($exstr, ("IMG")) if ($exstr);
9897     $altst = '' if ($ismap =~ /(^|\s+)ALT\s*=/);
9898     if ($altst) {
9899         if ($altst =~ /\s*ALT="?([^\"]+)"?\s*/io) { $altst=$1 }
9900         $altst =~ s/[<>"&]/'&'.$html_special_entities{$&}.';'/eg;
9901         $altst = "\n ALT=\"$altst\"";
9902     }
9904     my ($extern_image_mark,$imagesize);
9905     if ($thumbnail) {
9906         print "\nmaking thumbnail" if ($VERBOSITY > 1);
9907         if (($image_size{$thumbnail}) = &get_image_size($thumbnail,'')) {
9908             $thumbnail = &find_unique($thumbnail);
9909             $imagesize = " ".$image_size{$thumbnail};
9910             if ($HTML_VERSION < 2.2 ) {
9911                 # put the WIDTH/HEIGHT information into the ALT string
9912                 # first removing the quotes
9913                 my ($noquotes) = $imagesize;
9914                 $noquotes =~ s/\"//g;
9915                 $altst =~ s/"$/\% $noquotes "/m;
9916                 $imagesize = '';
9917             }
9918             $extern_image_mark = join('',"<IMG"
9919                 , "\n$imagesize" 
9920                 , (($aalign) ? " ALIGN=\"$aalign\"" : '')
9921                 , ("$aalign$imagesize" ? "\n" : '' )
9922                 , " SRC=\"$thumbnail\"$altst>");
9923         }
9924         $extern_image_mark =~ s/\s?BORDER="?\d+"?//
9925             unless ($exstr =~ /BORDER/i);
9926     } else { 
9927         # MRO: dubious (&extern_image_mark takes only one arg)
9928         $extern_image_mark = &extern_image_mark($IMAGE_TYPE,$altst);
9929     }
9931     my ($anch1,$anch2) = ('','');
9932     my $result;
9933     if ($external || $thumbnail || $EXTERNAL_IMAGES) {
9934         if ( $extern_image_mark ) {
9935             $result = &make_href_noexpand($urlimg, $name , $extern_image_mark);
9936             &save_image_map($url, $urlimg, $map, $name, $altst, $ausemp) if $map;
9937         }
9938     } else {
9939         if ($map) {
9940             $anch1 = "<A HREF=\"$map\">";
9941             $anch2 = "</A>";
9942         }
9943 #       if ($aalign eq "CENTER") {
9944 #           if ($HTML_VERSION eq "2.0") {
9945 #               $anch1 .= "\n<P ALIGN=\"CENTER\">";
9946 #               $anch2 .= "</P>";
9947 #           } else {
9948 #               $anch1 .= "\n<DIV ALIGN=\"CENTER\">";
9949 #               $anch2 .= "</DIV>";
9950 #           }
9951 #       }
9953         $imagesize = $image_size{$url};
9954         $imagesize = $usersize if (($usersize)&&($HTML_VERSION > 2.1 ));
9955         if ($HTML_VERSION < 2.2 ) {
9956             # put the WIDTH/HEIGHT information into the ALT string
9957             # first removing the quotes
9958             my ($noquotes) = $imagesize;
9959             $noquotes =~ s/\"//g;
9960             $altst =~ s/"$/\% $noquotes "/m;
9961         }
9963         # include a stylesheet entry for each included image
9964         if ($USING_STYLES && $SCALABLE_IMAGES &&(!$imgID)) {
9965             if ($url =~ /($dd|^)([^$dd$dd]+)\.$IMAGE_TYPE$/) {
9966                 my $img_name = $2;
9967                 $imgID = $img_name . ($img_name =~ /img/ ? '' : $IMAGE_TYPE);
9968                 $img_style{"$imgID"} = ' ' unless $img_style{"$imgID"};
9969                 $imgID = join('', ' CLASS="', $imgID, '"') if $imgID;
9970             }
9971         }
9973         ### MEH Add width and height to IMG
9974         ### Patched by <hswan@perc.Arco.com>:  Fixed \htmladdimg 
9975         if ( $imagesize || $name eq "external image" || $NO_IMAGES || $PS_IMAGES) {
9976             $imagesize = '' if ($HTML_VERSION < 2.2 );
9977             if ($border =~ s/^"//) { $border .= '"' };
9978             $result = join(''
9979                    , "<IMG$imgID"
9980                    , "\n", ($imagesize ? " $imagesize" : '')
9981                    , (($aalign)? " ALIGN=\"$aalign\"" : $border)
9982                    , $ismap );
9983             if ($ausemp) { $result .= " $ausemp" }
9984             $result .= "\n" unless (($result =~ /\n *$/m)|| !$imagesize);
9985             $result .= " SRC=\"$url\"";
9986             if ($altst) { $result .= $altst }
9987             $result .= ">";
9988         }
9989     }
9990     join('',$anch1, $result, $anch2);
9993 # MRO: added PNG support
9994 sub get_image_size { # clean
9995     my ($imagefile, $scale) = @_;
9997     $scale = '' if ($scale == 1);
9998     my ($imgID,$size) = ('','');
9999     if (open(IMAGE, "<$imagefile")) {
10000         my ($buffer,$magic,$dummy,$width,$height) = ('','','',0,0);
10001         binmode(IMAGE); # not harmful un UNIX
10002         if ($IMAGE_TYPE =~ /gif/) {
10003             read(IMAGE,$buffer,10);
10004             ($magic,$width,$height) = unpack('a6vv',$buffer);
10005             # is this image sane?
10006             unless($magic =~ /^GIF8[79]a$/ && ($width * $height) > 0) {
10007                 $width = $height = 0;
10008             }
10009         }
10010         elsif ($IMAGE_TYPE =~ /png/) {
10011             read(IMAGE,$buffer,24);
10012             ($magic,$dummy,$width,$height) = unpack('a4a12NN',$buffer);
10013             unless($magic eq "\x89PNG" && ($width * $height) > 0) {
10014                 $width = $height = 0;
10015             }
10016         }
10017         close(IMAGE);
10019         # adjust for non-trivial $scale factor.
10020         my ($img_w,$img_h) = ($width,$height);
10021         if ($scale && ($width * $height) > 0) {
10022             $img_w = int($width / $scale + .5);
10023             $img_h = int($height / $scale + .5);
10024         }
10025         $size = qq{WIDTH="$img_w" HEIGHT="$img_h"};
10027         # allow height/width to be stored in the stylesheet
10028         my ($img_name,$imgID);
10029         if ($SCALABLE_IMAGES && $USING_STYLES) {
10030             if ($imagefile =~ /(^|[$dd$dd])([^$dd$dd]+)\.(\Q$IMAGE_TYPE\E|old)$/o) {
10031                 $img_name = $2;
10032                 $imgID = $img_name . ($img_name =~ /img/ ? '' : $IMAGE_TYPE);
10033             }
10034             if ($imgID) {
10035                 $width = $width/$LATEX_FONT_SIZE/$MATH_SCALE_FACTOR;
10036                 $height = 1.8 * $height/$LATEX_FONT_SIZE/$MATH_SCALE_FACTOR;
10037                 # How wide is an em in the most likely browser font ?
10038                 if ($scale) {
10039                 # How high is an ex in the most likely browser font ?
10040                     $width = $width/$scale; $height = $height/$scale;
10041                 }
10042                 $width = int(100*$width + .5)/100;
10043                 $height = int(100*$height + .5)/100;
10044                 $img_style{$imgID} = qq(width:${width}em ; height:${height}ex );
10045                 #join('','width:',$width,'em ; height:',$height,'ex ');
10046                 $imgID = qq{ CLASS="$imgID"};
10047             }
10048         }
10049     }
10050     ($size, $imgID);
10053 sub find_unique { # clean
10054     my ($image1) = @_;
10055     local($/) = undef; # slurp in complete files
10057     my $imagedata;
10058     if(open(IMG1,"<$image1")) {
10059         binmode(IMG1); # needed with .png under DOS
10060         $imagedata = <IMG1>;
10061         close(IMG1);
10062     } else {
10063         print "\nError: Cannot read '$image1': $!\n"
10064             unless ($image1 =~ /^\s*$HTTP_start/i);
10065         return $image1;
10066     }
10068     my ($image2,$result);
10069     foreach $image2 (keys(%image_size)) {
10070         if ( $image1 ne $image2 &&
10071             $image_size{$image1} eq $image_size{$image2} ) {
10072             if(open(IMG2,$image2)) {
10073                 binmode(IMG2); # needed with .png under DOS
10074                 $result = ($imagedata eq <IMG2>);
10075                 close(IMG2);
10076             } else {
10077                 print "\nWarning: Cannot read '$image2': $!\n"
10078                     unless ($image2 =~ /^\s*$HTTP_start/i);
10079             }
10081 #  If we've found a match, rename the new image to a temporary one.
10082 #  Then try to link the new name to the old image.
10083 #  If the link fails, restore the temporary image.
10085             if ( $result ) {
10086                 my $tmp = "temporary.$IMAGE_TYPE";
10087                 L2hos->Unlink($tmp);
10088                 L2hos->Rename($image1, $tmp);
10089                 if (L2hos->Link($image2, $image1)) {
10090                     L2hos->Unlink($tmp);
10091                 } else {
10092                     L2hos->Rename($tmp, $image1);
10093                 }
10094                 return $image1;
10095             }
10096         }
10097     }
10098     $image1;
10101 sub save_image_map { # clean
10102     my ($url, $urlimg, $map, $name, $altst, $ausemp) = @_;
10103     unless(open(IMAGE_MAP, ">$urlimg")) {
10104         print "\nError: Cannot write '$urlimg': $!\n";
10105         return;
10106     }
10107     ### HWS  Pass server map unchanged from user
10108     print IMAGE_MAP "<HTML>\n<BODY>\n<A HREF=\"$map\">\n";
10109     print IMAGE_MAP "<IMG\n SRC=\"$url\" ISMAP $ausemp $altst> </A>";
10110     print IMAGE_MAP "</BODY>\n</HTML>\n";
10111     close IMAGE_MAP;
10114 #  Subroutine used mainly to rename an old image file about to recycled.
10115 #  But for active image maps, we must edit the auxiliary HTML file to point
10116 #     to the newly renames image.
10117 sub rename_html {
10118     local ($from, $to) = @_;
10119     local ($from_prefix, $to_prefix, $suffix);
10120     ($from_prefix, $suffix) = split(/\./, $from);
10121     ($to_prefix, $suffix) = split(/\./, $to);
10122     if ($EXTN =~ /$suffix$/) {
10123         if (open(FROM, "<$from") && open(HTMP, ">HTML_tmp")) {
10124             while (<FROM>) {
10125                 s/$from_prefix\.$IMAGE_TYPE/$to_prefix.$IMAGE_TYPE/g;
10126                 print HTMP;
10127             }
10128             close (FROM);
10129             close (HTMP);
10130             L2hos->Rename ("HTML_tmp", $to);
10131             L2hos->Unlink($from) unless ($from eq $to);
10132         }
10133         else {
10134             &write_warnings("File $from is missing!\n");
10135         }
10136     }
10137     L2hos->Rename("$from_prefix.old", "$to_prefix.$IMAGE_TYPE");
10138     $to;
10141 sub save_captions_in_file {
10142     local ($type, $_) = @_;
10143     if ($_) {
10144         s/^\n//om;
10145         &replace_markers;
10146         &add_dir_to_href if ($DESTDIR);
10147         if(open(CAPTIONS, ">${PREFIX}$type.pl")) {
10148             print CAPTIONS $_;
10149             close (CAPTIONS);
10150         } else {
10151             print "\nError: Cannot write '${PREFIX}$type.pl': $!\n";
10152         }
10153     }
10156 sub add_dir_to_href {
10157     $_ =~ s/'/\\'/g;
10158     $_ =~ s/(<LI><A )(NAME\=\"tex2html\d+\")?\s*(HREF=\")/$1$3\'.\$dir.\'/og;
10159     $_ = join('', "\'", $_, "\'\n");
10162 sub save_array_in_file {
10163     local ($type, $array_name, $append, %array) = @_;
10164     local ($uutxt,$file,$prefix,$suffix,$done_file,$depth,$title);
10165     $prefix = $suffix = "";
10166     my $filespec = ($append ? '>>' : '>') . "${PREFIX}$type.pl";
10167     $prefix = q("$URL/" . )
10168         if ($type eq "labels") && !($array_name eq "external\_latex\_labels");
10169     $suffix = " unless (\$$array_name\{\$key\})"
10170         if (($type =~ /(sections|contents)/)||($array_name eq "printable\_key"));
10171     if ((%array)||($type eq "labels")) {
10172         print "\nSAVE_ARRAY:$array_name in FILE: ${PREFIX}$type.pl"
10173             if ($VERBOSITY > 1);
10174         unless(open(FILE,$filespec)) {
10175             print "\nError: Cannot write '${PREFIX}$type.pl': $!\n";
10176             return;
10177         }
10178         if (($array_name eq "sub\_index") || ($array_name eq "printable\_key")) {
10179             print FILE "\n# LaTeX2HTML $TEX2HTMLVERSION\n";
10180             print FILE "# Printable index-keys from $array_name array.\n\n";
10181         } elsif ($array_name eq "index\_labels") {
10182             print FILE "\n# LaTeX2HTML $TEX2HTMLVERSION\n";
10183             print FILE "# labels from $array_name array.\n\n";
10184         } elsif ($array_name eq "index\_segment") {
10185             print FILE "\n# LaTeX2HTML $TEX2HTMLVERSION\n";
10186             print FILE "# segment identifier from $array_name array.\n\n";
10187         } elsif ($array_name eq "external\_latex\_labels") {
10188             print FILE "\n# LaTeX2HTML $TEX2HTMLVERSION\n";
10189             print FILE "# labels from $array_name array.\n\n";
10190         } else {
10191             print FILE "# LaTeX2HTML $TEX2HTMLVERSION\n";
10192             print FILE "# Associate $type original text with physical files.\n\n";
10193         }
10194         while (($uutxt,$file) = each %array) {
10195             $uutxt =~ s|/|\\/|g;
10196             $uutxt =~ s|\\\\/|\\/|g;
10198             if (!($array_name =~/images/)&&($file =~ /</)) {
10199                 do { local $_ = $file;
10200                      &replace_markers;
10201                      $file = $_; undef $_;
10202                      $file =~ s/(\G|[^q])[\\\|]\|/$1\\Vert/sg;
10203                      $file =~ s/(\G|[^q])\|/$1\\vert/sg;
10204                 };
10205             }
10207             local ($nosave);    
10208             if ($MULTIPLE_FILES && $ROOTED && 
10209                     $type =~ /(sections|contents)/) {
10210                 #RRM: save from $THIS_FILE only
10211                 if ( $uutxt =~ /^$THIS_FILE /) {
10212                     #RRM: save from $THIS_FILE only
10213                     $nosave = ''
10214                 } else { $nosave = 1 }
10215             } else {
10216                 #RRM: suppress info from other segments
10217                 $nosave = $noresave{$uutxt}; 
10218             }
10220             if (!$nosave && ($file ne ''))  {
10221                 print FILE "\n\$key = q/$uutxt/;\n";
10223                 $file =~ s/\|/\\\|/g; # RRM:  escape any occurrences of |
10224                 $file =~ s/\\\\\|/\\\|/g; # unless already escaped as \|
10225                 $file =~ s|\\\\|\\\\\\\\|g;
10226                 $file =~ s/(SRC=")($HTTP_start)?/$1.($2 ? '' :"|.\"\$dir\".q|").$2/seg;
10229 # added code for  $dir  with segmented docs;  RRM  15/3/96
10231                 if ($type eq "contents") {
10232                     ($depth, $done_file) = split($delim, $file, 2 );
10233                     next if ($depth > $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH);
10234                     print FILE 
10235     "\$$array_name\{\$key\} = '$depth$delim'.\"\$dir\".q|$done_file|$suffix; \n";
10237                 } elsif ($type eq "sections") {
10238                     ($depth, $done_file) = split($delim, $file, 2 );
10239                     next if ($depth > $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH);
10240                     print FILE 
10241     "\$$array_name\{\$key\} = '$depth$delim'.\"\$dir\".q|$done_file|$suffix; \n";
10243                 } elsif ($type eq "internals") {
10244                     print FILE 
10245     "\$$array_name\{\$key\} = \"\$dir\".q|$file|$suffix; \n";
10247                 } elsif ($array_name eq "sub_index") {
10248                     print FILE
10249     "\$$array_name\{\$key\} .= q|$file|$suffix; \n";
10251                 } elsif ($array_name eq "index") {
10252                     local($tmp_file) = '';
10253                     ($depth, $done_file) = split('HREF=\"', $file, 2 );
10254                     if ($done_file) {
10255                         while ($done_file) {
10256                             $depth =~ s/\s*$/ / if ($depth);
10257                             $tmp_file .= "q|${depth}HREF=\"|.\"\$dir\".";
10258                             ($depth, $done_file) = split('HREF=\"', $done_file, 2 );
10259                         }
10260                         print FILE
10261     "\$$array_name\{\$key\} .= ${tmp_file}q|$depth|$suffix; \n";
10263                     } else {
10264                         print FILE
10265     "\$$array_name\{\$key\} .= q|$file|$suffix; \n";
10266                     }
10267                 } elsif ($array_name eq "printable_key") {
10268                     print FILE
10269     "\$$array_name\{\$key\} = q|$file|$suffix; \n";
10271                 } else {
10272                     print FILE
10273     "\$$array_name\{\$key\} = ${prefix}q|$file|$suffix; \n";
10274                 }
10276                 if ($type =~ /(figure|table|images)/) {} else {
10277                     print FILE "\$noresave\{\$key\} = \"\$nosave\";\n";
10278                 }
10280                 if ($type eq "sections") {
10281                     ($depth, $done_file, $title) = split($delim, $file);
10282                     print FILE "\$done\{\"\$\{dir\}$done_file\"\} = 1;\n";
10283                 }
10284             }
10285         }
10286         print FILE "\n1;\n\n"  unless  ( $array_name =~ /index/ );
10287         close (FILE);
10288     } else {
10289         print "\nSAVE_FILE:$array_name: ${PREFIX}$type.pl  EMPTY " if ($VERBOSITY > 1);
10290     }
10293 # returns true if $AUTO_NAVIGATION is on and there are more words in $_
10294 # than $WORDS_IN_PAGE
10295 sub auto_navigation {
10296     # Uses $_;
10297     local(@tmp) = split(/\W*\s+\W*/, $_);
10298     ($AUTO_NAVIGATION && ( (scalar @tmp) > $WORDS_IN_PAGE));
10301 # Returns true if $f1 is newer than $f2
10302 sub newer {
10303     ($f1,$f2) = @_;
10304     local(@f1s) = stat($f1);
10305     local(@f2s) = stat($f2);
10306     ($f1s[9] > $f2s[9]);
10309 sub iso_map {
10310     local($char, $kind, $quiet) = @_;
10311     my($character_map,$enc);
10312     local ($this);
10314     if ( $CHARSET && $HTML_VERSION ge "2.1" ) {
10315         # see if it is a character in the charset
10316         $character_map = ((($charset =~ /utf/)&&!$NO_UTF)?
10317                           'iso_10646' : $CHARSET );
10318         $character_map =~ tr/-/_/;
10319         eval "\$enc = \$${character_map}_character_map\{\"$char$kind\"\}";
10320         print "\n no support for $CHARSET: $@ " if ($@);
10321     }
10322     if ($USE_ENTITY_NAMES && $enc) { return(";SPM$char$kind;") }
10324     if ($enc) {
10325         $enc =~ /^\&\#(\d{3});$/;
10326         # maybe convert it to an 8-bit character
10327         if ($NO_UTF && !$USE_UTF && ($1<=255)) { $enc = chr($1) }
10328 #       elsif (!$USE_UTF &&($1>127)&&($1<160)) { $enc = chr($1) }
10329         elsif ($character_map !~ /^iso_(8859_1|10646)/) {
10330         # get its latin1 or unicode entity encoding
10331             $enc = $iso_8859_1_character_map{"$char$kind"}
10332                 ||$iso_8859_1A_character_map{"$char$kind"}
10333                 ||$iso_10646_character_map{"$char$kind"}
10334         }
10335      } else {
10336         # get its latin1 or unicode entity encoding, if available
10337         $enc = $iso_8859_1_character_map{"$char$kind"}
10338             ||$iso_8859_1A_character_map{"$char$kind"}
10339             ||$iso_10646_character_map{"$char$kind"};
10340     }
10342     if ($enc) {
10343         $ISOLATIN_CHARS = 1; $enc;
10344     } elsif (!$image_made{"$char$kind"}) {
10345         print "\ncouldn't convert character $char$kind into available encodings"
10346             if (!quiet &&($VERBOSITY > 1));
10347         &write_warnings(
10348             "couldn't convert character $char$kind into available encodings"
10349             . ($ACCENT_IMAGES ? ', using image' : '')) unless ($quiet);
10350         $image_made{"$char$kind"} = 1;
10351         '';
10352     } else {''}
10355 sub titles_language {
10356     local($_) = @_;
10357     local($lang) = $_ . "_titles";
10358     if (defined(&$lang)) { &$lang }
10359     else {
10360         &english_titles;
10361         &write_warnings(
10362             "\nThere is currently no support for the $tmp language." .
10363             "\nSee the file $CONFIG_FILE for examples on how to add it\n\n");
10364     }
10367 sub translate_titles {
10368     $toc_title = &translate_commands($toc_title) if ($toc_title =~ /\\/);
10369     $lof_title = &translate_commands($lof_title) if ($lof_title =~ /\\/);
10370     $lot_title = &translate_commands($lot_title) if ($lot_title =~ /\\/);
10371     $idx_title = &translate_commands($idx_title) if ($idx_title =~ /\\/);
10372     $ref_title = &translate_commands($ref_title) if ($ref_title =~ /\\/);
10373     $bib_title = &translate_commands($bib_title) if ($bib_title =~ /\\/);
10374     $abs_title = &translate_commands($abs_title) if ($abs_title =~ /\\/);
10375     $app_title = &translate_commands($app_title) if ($app_title =~ /\\/);
10376     $pre_title = &translate_commands($pre_title) if ($pre_title =~ /\\/);
10377     $foot_title = &translate_commands($foot_title) if ($foot_title =~ /\\/);
10378     $fig_name = &translate_commands($fig_name) if ($fig_name =~ /\\/);
10379     $tab_name = &translate_commands($tab_name) if ($tab_name =~ /\\/);
10380     $prf_name = &translate_commands($prf_name) if ($prf_name =~ /\\/);
10381     $page_name = &translate_commands($page_name) if ($page_name =~ /\\/);
10382     $child_name = &translate_commands($child_name) if ($child_name =~ /\\/);
10383     $info_title = &translate_commands($info_title) if ($info_title =~ /\\/);
10384     $part_name = &translate_commands($part_name) if ($part_name =~ /\\/);
10385     $chapter_name = &translate_commands($chapter_name)
10386         if ($chapter_name =~ /\\/);
10387     $section_name = &translate_commands($section_name)
10388         if ($section_name =~ /\\/);
10389     $subsection_name = &translate_commands($subsection_name)
10390         if ($subsection_name =~ /\\/);
10391     $subsubsection_name = &translate_commands($subsubsection_name)
10392         if ($subsubsection_name =~ /\\/);
10393     $paragraph_name = &translate_commands($paragraph_name)
10394         if ($paragraph_name =~ /\\/);
10395     $see_name = &translate_commands($see_name) if ($see_name =~ /\\/);
10396     $also_name = &translate_commands($also_name) if ($also_name =~ /\\/);
10397     $next_name = &translate_commands($next_name) if ($next_name =~ /\\/);
10398     $prev_name = &translate_commands($prev_name) if ($prev_name =~ /\\/);
10399     $up_name = &translate_commands($up_name) if ($up_name =~ /\\/);
10400     $group_name = &translate_commands($group_name) if ($group_name =~ /\\/);
10401     $encl_name = &translate_commands($encl_name) if ($encl_name =~ /\\/);
10402     $headto_name = &translate_commands($headto_name) if ($headto_name =~ /\\/);
10403     $cc_name = &translate_commands($cc_name) if ($cc_name =~ /\\/);
10404     $default_title = &translate_commands($default_title)
10405         if ($default_title =~ /\\/);
10407 ####################### Code Generation Subroutines ############################
10408 # This takes a string of commands followed by optional or compulsory
10409 # argument markers and generates a subroutine for each command that will
10410 # ignore the command and its arguments.
10411 # The commands are separated by newlines and have the format:
10412 ##      <cmd_name>#{}# []# {}# [] etc.
10413 # {} marks a compulsory argument and [] an  optional one.
10414 sub ignore_commands {
10415     local($_) = @_;
10416     foreach (/.*\n?/g) {
10417         s/\n//g;
10418         # For each line
10419         local($cmd, @args) = split('\s*#\s*',$_);
10420         next unless $cmd;
10421         $cmd =~ s/ //;
10422         ++$ignore{$cmd};
10423         local ($body, $code, $thisone) = ("", "");
10424         
10425         # alter the pattern here to debug particular commands
10426         $thisone = 1 if ($cmd =~ /let/);
10428         if (@args) {
10429             print "\n$cmd: ".scalar(@args)." arguments" if ($thisone);
10430             # Replace the argument markers with appropriate patterns
10431             foreach $arg (@args) {
10432                 print "\nARG: $arg" if ($thisone);
10433                 if ($arg =~ /\{\}/) {
10434                     $body .= 'local($cmd) = '."\"$cmd\"".";\n";
10435                     $body .= '$args .= &missing_braces'."\n ".'unless (';
10436                     $body .= '(s/$next_pair_pr_rx/$args .= $2;\'\'/eo)'."\n";
10437                     $body .= '  ||(s/$next_pair_rx/$args .= $2;\'\'/eo));'."\n";
10438                     print "\nAFTER:$'" if (($thisone)&&($'));
10439                     $body .= $' if ($');
10440                 } elsif ($arg =~ /\[\]/) {
10441                     $body .= '($dummy, $pat) = &get_next_optional_argument;'
10442                         . '$args .= $pat;'."\n";
10443                     print "\nAFTER:$'" if (($thisone)&&($'));
10444                     $body .= $' if ($');
10445                 } elsif ($arg =~ /^\s*\\/) {                
10446                     $body .= '($dummy, $pat) = &get_next_tex_cmd;'
10447                         . '$args .= $pat;'."\n";
10448                     print "\nAFTER:$'" if (($thisone)&&($'));
10449                     $body .= $' if ($');
10450                 } elsif ($arg =~ /<<\s*([^>]*)[\b\s]*>>/) {
10451                     local($endcmd, $after) = ($1,$');
10452                     $after =~ s/(^\s*|\s*$)//g;
10453                     $endcmd = &escape_rx_chars($endcmd);
10454                     $body .= 'if (/'.$endcmd.'/o) { $args .= $`; $_ = $\' };'."\n";
10455                     print "\nAFTER:$after" if (($thisone)&&($after));
10456                     $body .= "$after" if ($after);
10457                 } else {
10458                     print "\nAFTER:$'" if (($thisone)&&($arg));
10459                     $body .= $arg ;
10460                 }
10461             }
10462             # Generate a new subroutine
10463 #           $code = "sub do_cmd_$cmd {\n".'local($_) = @_;'. join('',@args) .'$_}';
10464             $code = "sub do_cmd_$cmd {\n"
10465                 . 'local($_,$ot) = @_; '
10466                 . 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R; '
10467                 . 'local($args); '
10468                 . "\n" . $body . (($body)? ";\n" : '')
10469                 . (($thisone)? "print \"\\n$cmd:\".\$args.\"\\n\";\n" : '')
10470                 . (($arg)? $arg : '$_') . "}";
10471             print STDOUT "\n$code\n" if ($thisone); # for error-checking
10472             eval ($code); # unless ($thisone);
10473             print STDERR "\n\n*** sub do_cmd_$cmd failed: $@\n" if ($@);
10474         } else {
10475             $code = "sub do_cmd_$cmd {\n".'$_[0]}';
10476             print "\n$code\n" if ($thisone); # for error-checking
10477             eval ($code); # unless ($thisone);
10478             print STDERR "\n\n*** sub do_cmd_$cmd failed: $@\n" if ($@);
10479         }
10480     }
10484 sub ignore_numeric_argument {
10485     # Chop this off
10486     #RRM: 2001/11/8: beware of taking too much, when  <num> <num> 
10487     local($num) = '(^|width|height|plus|minus)\s*[+-]?[\d\.]+(cm|em|ex|in|pc|pt|mm)?\s*';
10488     do { s/^\s*=?\s*//so; s/^($num)*//so } unless (/^(\s*\<\<\d+\>\>|$)/);
10491 sub get_numeric_argument {
10492     my ($num_rx,$num) = ('','');
10493     # Collect the numeric part
10494     #RRM: 2001/11/8: beware of taking too much, when  <num> <num> 
10495     $num_rx = '(^|width|height|plus|minus)\s*[+-]?[\d\.]+(cm|em|ex|in|pc|pt|mm)?\s*';
10496     do { s/^\s*=?\s*//so; s/($num_rx)*/$num=$&;''/soe } unless (/^(\s*\<\<\d+\>\>|$)/);
10497     $num;
10500 sub process_in_latex_helper {
10501     local($ctr,$val,$cmd) = @_;
10502     ($ASCII_MODE ? "[$cmd]" : 
10503         &process_in_latex("\\setcounter{$ctr}{$val}\\$cmd"))
10506 sub do_cmd_catcode {
10507     local($_) = @_;
10508     s/^\s*[^=]+(=?\s*\d+\s|\\active)\s?//;
10509     $_;
10512 sub do_cmd_string {
10513     local($_) = @_;
10514     local($tok);
10515     s/^\s*(\\([a-zA-Z]+|.)|[&;]\w+;(#\w+;)?|.)/$tok=$1;''/e;
10516     if ($2) {$tok = "\&#92;$2"};
10517     "$tok".$_
10520 sub do_cmd_boldmath {
10521     local($_) = @_;
10522     $BOLD_MATH = 1;
10523     $_;
10526 sub do_cmd_unboldmath {
10527     local($_) = @_;
10528     $BOLD_MATH = 0;
10529     $_;
10532 sub do_cmd_lq {
10533     local($_) = @_ ;
10534     local($lquote);
10535     # check for double quotes
10536     if (s/^\s*\\lq(\b|$|[^A-Za-z])/$1/) {
10537         $lquote = ((($HTML_VERSION < 4)&&!($charset =~ /utf/)) ? '``'
10538                 : &do_leftquotes($_));
10539     } else {
10540         $lquote = ((($HTML_VERSION < 4)&&!($charset =~ /utf/)) ? '`'
10541                 : &do_leftquote($_));
10542     }
10543     $lquote . $_;
10546 sub do_leftquote {
10547     # MRO: use $_[0] : local(*_) = @_;
10548     local($quote,$lquo) = ('',($HTML_VERSION<5)? '&#8216;' : ';SPMlsquo;');
10549     # select whole quotation, if \lq matches \rq
10550     if ($_[0] =~ /^(.*)((\\rq\\rq|'')*)(\\rq)/) {
10551         $quote = $1.$2; $_[0] = $';
10552         local($rquo) = &do_rightquote();
10553         &process_quote($lquo,$quote,$rquo);
10554     } else { $lquo; }
10557 sub do_leftquotes {
10558     # MRO: use $_[0] : local(*_) = @_;
10559     local($quote,$lquo) = ('',($HTML_VERSION<5)? '&#8220;' : ';SPMldquo;');
10560     # select whole quotation, if \lq\lq matches \rq\rq or ''
10561     if ($_[0] =~ /^(.*)(\\rq\\rq|'')/) {
10562         $quote = $1; $_[0] = $';
10563         local($rquo) = &do_rightquotes();
10564         &process_quote($lquo,$quote,$rquo);
10565     } else { $lquo; }
10568 # RRM: By default this just concatenates the strings; e.g. ` <quote> '
10569 # This can be overridden in a html-version file
10570 sub process_quote { join ('', @_) }
10572 sub do_cmd_rq {
10573     local($_) = @_ ;
10574     local($rquote);
10575     if ($_ =~ s/^\s*\\rq\b//) {
10576         $rquote = ((($HTML_VERSION < 4)&&!($charset =~ /utf/)) ? "''"
10577                 : &do_rightquotes());
10578     } else { 
10579         $rquote = ((($HTML_VERSION < 4)&&!($charset =~ /utf/)) ? "'"
10580                 : &do_rightquote());
10581     }
10582     $rquote . $_;
10585 sub do_rightquote { (($HTML_VERSION < 5)? '&#8217;' : ';SPMrsquo;') }
10586 sub do_rightquotes { (($HTML_VERSION < 5)? '&#8221;' : ';SPMrdquo;') }
10588 sub do_cmd_parbox {
10589     local($_) = @_;
10590     local($args, $contents, $dum, $pat);
10591     $* = 1;                     # Multiline matching ON
10592     ($dum,$pat) = &get_next_optional_argument; # discard this
10593     ($dum,$pat) = &get_next_optional_argument; # discard this
10594     ($dum,$pat) = &get_next_optional_argument; # discard this
10595     $args .= $pat if ($pat);
10596     $pat = &missing_braces unless (
10597         (s/$next_pair_pr_rx/$pat=$2;''/eo)
10598         ||(s/$next_pair_rx/$pat=$2;''/eo));
10599     $args .= "{".$`.$pat."}";
10600     $contents = &missing_braces unless (
10601         (s/$next_pair_pr_rx/$contents=$2;''/eo)
10602         ||(s/$next_pair_rx/$contents=$2;''/eo));
10603     $* = 0;                     # Multiline matching OFF
10604     $args .= "{".$`.$contents."}";
10605     if ($NO_PARBOX_IMAGES) {
10606         $contents = join ('', &do_cmd_par(), $contents, '</P>' );
10607     } else {
10608         $contents = &process_math_in_latex('','text',0,"\\parbox$args")
10609             if ($contents);
10610     }
10611     $contents . $_;
10615 sub do_cmd_mbox {
10616     local($_) = @_;
10617     local($text,$after)=('','');
10618     $text = &missing_braces unless (
10619         (s/$next_pair_pr_rx/$text = $2;''/eo)
10620         ||(s/$next_pair_rx/$text = $2;''/eo));
10621     $after = $_;
10623     # incomplete macro replacement
10624     if ($text =~ /(^|[^\\<])#\d/) { return($after) }
10626     if ($text =~ /(tex2html_wrap_inline|\$$OP(\d+)$CP$OP\2$CP\$|\$$O(\d+)$C$O\2$C\$)/) {
10627         if ($text =~ 
10628             /$image_mark#([^#]+)#([\.,;:\)\]])?(\001)?([ \t]*\n?)(\001)?/) {
10629             local($mbefore, $mtext, $mafter) = ($`, $&, $');
10630             $mbefore = &translate_commands($mbefore) if ($mbefore =~ /\\/);
10631             $mafter = &translate_commands($mafter) if ($mafter =~ /\\/);
10632             join('', $mbefore, $mtext, $mafter, $after);
10633         } else {
10634             join ('', &process_math_in_latex('','','',"\\hbox{$text}"), $after )
10635         }
10636     } else {
10637         $text = &translate_environments($text);
10638         $text = &translate_commands($text);
10639         join('', $text, $after);
10640     }
10645 # *Generates* subroutines to handle each of the declarations
10646 # like \em, \quote etc., in case they appear with the begin-end
10647 # syntax.
10648 sub generate_declaration_subs {
10649     local($key, $val, $pre, $post, $code );
10650     print "\n *** processing declarations ***\n";
10651     while ( ($key, $val) = each %declarations) {
10652         if ($val) {
10653             ($pre,$post) = ('','');
10654             $val =~ m|</.*$|;
10655             do {$pre = $`; $post = $& } unless ($` =~ /^<>/);
10656             $pre =~ s/"/\\"/g; $post =~ s/"/\\"/g;
10657             $code = "sub do_env_$key {"
10658 #               . 'local($_) = @_;' . "\n"
10659 #               . 'push(@$open_tags_R, $key);'. "\n"
10660 #               . '$_ = &translate_environments($_);'. "\n"
10661 #               . '$_ = &translate_commands($_);'. "\n"
10662 #               . "join('',\"$pre\",\"\\n\"," .'$_' .",\"$post\");\n};";
10663                 . '&declared_env('.$key.',@_)};';
10664             eval $code;
10665             if ($@) {print "\n *** $key ".  $@ };
10666         }
10667     }
10670 # *Generates* subroutines to handle each of the sectioning commands.
10671 sub generate_sectioning_subs {
10672     local($key, $val, $cmd, $body);
10673     while ( ($key, $val) = each %standard_section_headings) {
10674         $numbered_section{$key} = 0;
10675         eval "sub do_cmd_$key {"
10676             . 'local($after,$ot) = @_;'
10677             . 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'
10678             . '&reset_dependents('. $key . ');'
10679             . '&do_cmd_section_helper('.$val.','.$key.');}';
10680         print STDERR "\n*** sub do_cmd_$key failed:\n$@\n" if ($@);
10681         # Now define the *-form of the same commands. The difference is that the
10682         # $key is not passed as an argument.
10683         eval "sub do_cmd_$key" . "star {"
10684             . 'local($after,$ot) = @_;'
10685             . 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'
10686             . '&do_cmd_section_helper(' . $val . ');}';
10687         print STDERR "\n*** sub do_cmd_${key}star failed:\n$@\n" if ($@);
10688         # Now define the macro  \the$key  
10689         &process_commands_wrap_deferred("the$key \# {}\n");
10690 ###     local($_) = "<<1>>$key<<1>>";
10691         $body = "<<1>>$key<<1>>";
10692         &make_unique($body);
10693         $cmd = "the$key";
10694         eval "sub do_cmd_$cmd {"
10695             . 'local($after,$ot) = @_;'
10696             . 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'
10697             . '&do_cmd_arabic(' . "\"$body\"" . ").\$after;};";
10698         print STDERR "\n*** sub do_cmd_$cmd failed:\n$@\n" if ($@);
10699         $raw_arg_cmds{$cmd} = 1;
10700     }
10701     &addto_dependents('chapter','section');
10702     &addto_dependents('section','subsection');
10703     &addto_dependents('subsection','subsubsection');
10704     &addto_dependents('subsubsection','paragraph');
10705     &addto_dependents('paragraph','subparagraph');
10708 sub addto_dependents {
10709     local($ctr, $dep) = @_;
10710     local($tmp, $depends);
10711     if ($depends = $depends_on{$dep}) {
10712         &remove_dependency($depends, $dep) }
10713     $depends_on{$dep} = $ctr;
10715     $tmp = $dependent{$ctr};
10716     if ($tmp) { 
10717         $dependent{$ctr} = join($delim, $tmp, $dep);
10718     } else { $dependent{$ctr} = $dep }
10721 sub remove_dependency {
10722     local($ctr, $dep) = @_;
10723     local(@tmp, $tmp, $dtmp);
10724     print "\nremoving dependency of counter {$dep} from {$ctr}\n";
10725     foreach $dtmp (split($delim, $dependent{$ctr})) {
10726         push(@tmp, $dtmp) unless ($dtmp =~ /$dep/);
10727     }
10728     $dependent{$ctr} = join($delim, @tmp);
10732 # Uses $after which is defined in the caller (the caller is a generated subroutine)
10733 # Also uses @curr_sec_id
10735 #JCL(jcl-tcl) (changed almost everything)
10737 sub do_cmd_section_helper {
10738     local($H,$key) = @_;
10739     local($section_number, $titletext, $title_key, @tmp, $align, $dummy);
10740     local($anchors,$pre,$run_title,$_) = ('', "\n", '', $after);
10741     local($open_tags_R) = [];
10743     # if we have a $key the current section is not of the *-form, so we need
10744     # to update the counters.
10745     &do_cmd_stepcounter("${O}0$C$key${O}0$C")
10746 #       if ($key && !$making_name);
10747 #       if ($key && !($unnumbered_section_commands{$key}) && !$making_name);
10748         if ($key && !($unnumbered_section_commands{$key}));
10749 #   $latex_body .= "\\stepcounter{$key}\n" if $key;
10750 #   &reset_dependents($key) if ($dependent{$key});
10752     local($br_id);
10753 #    if ($USING_STYLES) {
10754 #       $txt_style{"H$H.$key"} = " " unless $txt_style{"H$H.$key"}; 
10755 #       $H .= " CLASS=\"$key\"; 
10756 #    };
10758     local ($align, $dummy)=&get_next_optional_argument;
10759     if (($align =~/^(left|right|center)$/i)&&($HTML_VERSION > 2.0)) {
10760         $align = "ALIGN=\"$1\"";
10761     } elsif ($align) {
10762         # data was meant to be a running-head !
10763         $br_id = ++$global{'max_id'};
10764         $run_title = &translate_environments("$O$br_id$C$align$O$br_id$C");
10765         $run_title = &translate_commands($run_title) if ($run_title =~ /\\/);
10766         $run_title =~ s/($O|$OP)\d+($C|$CP)//g;
10767         $align = '';
10768     } else {
10769     }
10770     $titletext = &missing_braces 
10771         unless s/$next_pair_rx/$titletext=$2;''/eo;
10772     $br_id = ++$global{'max_id'};
10773     $titletext = &translate_environments("$O$br_id$C$titletext$O$br_id$C");
10775     $title_key = $run_title || $titletext;
10776     $title_key =~ s/$image_mark\#([^\#]+)\#(\\space)?/&purify_caption($1)/e;
10777     # This should reduce to the same information as contained in the .aux file.
10778     $title_key = &sanitize(&simplify($title_key));
10780     # RRM: collect all anchors from \label and \index commands
10781     ($anchors,$titletext) = &extract_anchors($titletext);
10782     local($saved_title) = $titletext;
10783     do {
10784         # to ensure a style ID is not saved and re-used in (mini-)TOCs
10785         local($USING_STYLES) = 0;
10786         $titletext = &translate_environments($titletext);
10787         $titletext = &translate_commands($titletext) 
10788             if ($titletext =~/\\/);
10789     };
10790     # but the style ID can be used for the title on the HTML page
10791     if (!($titletext eq $saved_title)) {
10792         $saved_title = &translate_environments($saved_title);
10793         $saved_title = &translate_commands($saved_title) 
10794             if ($saved_title =~/\\/);
10795         $saved_title = &simplify($saved_title);
10796     }
10797     local($closures) = &close_all_tags();
10798     $saved_title .= $closures;
10799     $title_text .= $closures;
10801     # This is the LaTeX section number read from the $FILE.aux file
10802     @tmp = split(/$;/,$encoded_section_number{$title_key});
10803     $section_number = shift(@tmp);
10804     $section_number = "" if ($section_number eq "-1");
10805     $encoded_section_number{$title_key} = join($;, @tmp)
10806 #       unless (defined $title);
10807         unless ($title);
10809     # need to check also &{wrap_cmd_... also, if \renewcommand has been used; 
10810     # thanks Bruce Miller
10811     local($thehead,$whead) = ("do_cmd_the$key","wrap_cmd_the$key");
10812 #    $thehead = ((defined &$thehead)? 
10813 #       &translate_commands("\\the$key") : '');
10814     $thehead = ((defined &$thehead)||(defined &$whead)
10815         ? &translate_commands("\\the$key") : '');
10816     $thehead .= $SECNUM_PUNCT
10817         if ($SECNUM_PUNCT &&($thehead)&& !($thehead =~ /\./));
10818     $section_number = $thehead if (($thehead)&&($SHOW_SECTION_NUMBERS));
10820     #JKR: Don't prepend whitespace 
10821     if ($section_number) {
10822         $titletext = "$section_number " . $titletext;
10823         $saved_title = "$section_number " . $saved_title;
10824         $run_title = "$section_number " . $run_title if $run_title;
10825     }
10827 #    $toc_sec_title = $titletext;
10828 #    $toc_sec_title = &purify($titletext);
10829     $toc_sec_title = &simplify($titletext);
10830     $titletext = &simplify($titletext);
10831 #    $TITLE = &purify($titletext);
10832     local($after) = $_;
10833     do {
10834         local($_) = $titletext; &remove_anchors; 
10835         if ($run_title) {
10836             $TITLE = $run_title;
10837         } elsif ($_) {
10838             $TITLE = $_
10839         } else { $TITLE = '.' };
10840     };
10841     $global{$key}-- if ($key && $making_name);
10842     return ($TITLE) if (defined $title);
10844     #RRM: no preceding \n when this is the first section-head on the page.
10845     if (! $key || $key < $MAX_SPLIT_DEPTH) { $pre = '' };
10846     if ( defined &make_pre_title) {
10847         $pre = &make_pre_title($saved_title, $H);
10848     }
10850     undef $open_tags_R;
10851     $open_tags_R = [ @save_open_tags ];
10852     
10853     join('', $pre, &make_section_heading($saved_title, $H, $align.$anchors)
10854         , $open_all, $_);
10857 sub do_cmd_documentclass {
10858     local($_) = @_;
10859     local ($docclass)=('');
10860     local ($cloptions,$dum)=&get_next_optional_argument;
10861     $docclass = &missing_braces unless (
10862         (s/$next_pair_pr_rx/$docclass = $2;''/eo)
10863         ||(s/$next_pair_rx/$docclass = $2;''/eo));
10864     local($rest) = $';
10865     &do_require_package($docclass);
10866     if (! $styles_loaded{$docclass}) {
10867         &no_implementation("document class",$docclass);
10868     } else {
10869         if($cloptions =~ /\S+/) { # are there any options?
10870             &do_package_options($docclass,$cloptions);
10871         }
10872     }
10873     $rest;
10875 sub do_cmd_documentstyle { &do_cmd_documentclass($_[0]); }
10877 sub do_cmd_usepackage {
10878     local($_) = @_;
10879     # RRM:  allow lists of packages and options
10880     local ($package, $packages)=('','');
10881     local ($options,$dum)=&get_next_optional_argument;
10882     $packages = &missing_braces unless (
10883         (s/$next_pair_pr_rx/$packages = $2;''/eo)
10884         ||(s/$next_pair_rx/$packages = $2;''/eo));
10885     local($rest) = $_;
10886     # MRO: The files should have already been loaded by
10887     #      TMP_styles, but we better make it sure.
10888     foreach $package (split (',',$packages)) {  # allow multiple packages
10889         $package =~ s/\s|\%|$comment_mark\d*//g; # remove whitespace 
10890         $package =~ s/\W/_/g; # replace non-alphanumerics
10891         &do_require_package($package);
10892         if (! $styles_loaded{$package}) {
10893             &no_implementation("package",$package);
10894         } else {
10895             if($options =~ /\S+/) { # are there any options?
10896                 &do_package_options($package,$options);
10897             }
10898         }
10899     }
10900     $rest;
10904 sub no_implementation {
10905     local($what,$which)= @_;
10906     print STDERR "\nWarning: No implementation found for $what: $which";
10909 sub do_cmd_RequirePackage {
10910     local($_)= @_;
10911     local($file);
10912     local($options,$dum)=&get_next_optional_argument;
10913     $file = &missing_braces unless (
10914         (s/$next_pair_pr_rx/$file = $2;''/eo)
10915         ||(s/$next_pair_rx/$file = $2;''/eo));
10916     local($rest) = $_;
10917     $file =~ s/^[\s\t\n]*//o;
10918     $file =~ s/[\s\t\n]*$//o;
10919     # load the package, unless that has already been done
10920     &do_require_package($file) unless ($styles_loaded{$file});
10921     # process any options
10922     if (! $styles_loaded{$file}) {
10923             &no_implementation("style",$file);
10924     } else {
10925         # process any options
10926         &do_package_options($file,$options) if ($options);
10927     }
10928     $_ = $rest;
10929     # ignore trailing optional argument
10930     local($date,$dum)=&get_next_optional_argument;
10931     $_;
10934 sub do_cmd_PassOptionsToPackage {
10935     local($_) = @_;
10936     local($options,$file);
10937     $options = &missing_braces unless (
10938         (s/$next_pair_pr_rx/$options = $2;''/eo)
10939         ||(s/$next_pair_rx/$options = $2;''/eo));
10940     $file = &missing_braces unless (
10941         (s/$next_pair_pr_rx/$file = $2;''/eo)
10942         ||(s/$next_pair_rx/$file = $2;''/eo));
10943     $passedOptions{$file} = $options;
10944     $_;
10946 sub do_cmd_PassOptionsToClass{ &do_cmd_PassOptionsToPackage(@_)}
10948 sub do_package_options {
10949     local($package,$options)=@_;
10950     local($option);
10951     if ($passedOptions{$package}) { $options = $passedOptions{$package}.'.'.$options };
10952     foreach $option (split (',',$options)) {
10953         $option =~ s/^[\s\t\n]*//o;
10954         $option =~ s/[\s\t\n]*$//o;
10955         $option =~ s/\W/_/g; # replace non-alphanumerics
10956         next unless ($option);
10957         if (!($styles_loaded{$package."_$option"})) {
10958             &do_require_packageoption($package."_$option");
10959             if (!($styles_loaded{$package."_$option"})) {
10960                 &no_implementation("option","\`$option\' for \`$package\' package\n");
10961             }
10962         }
10963     }
10964     $rest;
10967 sub do_class_options {
10968     local($class,$options)=@_;
10969     local($option);
10970     if ($passedOptions{$class}) { $options = $passedOptions{$class}.'.'.$options };
10971     foreach $option (split (',',$options)) {
10972         $option =~ s/^[\s\t\n]*//o;
10973         $option =~ s/[\s\t\n]*$//o;
10974         $option =~ s/\W/_/g; # replace non-alphanumerics
10975         next unless ($option);
10976         &do_require_package($option);
10977         if (!($styles_loaded{$class."_$option"})) {
10978             &do_require_packageoption($class."_$option");
10979             if (!($styles_loaded{$class."_$option"})) {
10980                 &no_implementation("option","\`$option\' for document-class \`$class\'\n");
10981             }
10982         }
10983     }
10984     $rest;
10987 sub do_require_package {
10988     local($file)= @_;
10989     local($dir);
10990     #RRM: make common ps/eps-packages use  epsfig.perl
10991     $file = 'epsfig' if ($file =~ /^(psfig|epsf)$/);
10993     if ($file =~ /^graphicx$/) {
10994         # work-around the CVS repository bug: use graphixx , not graphicx
10995         foreach $dir (split(/$envkey/,$LATEX2HTMLSTYLES)) {
10996             if (-f "$dir${dd}graphixx.perl") {
10997                 $file = 'graphixx';
10998                 last;
10999             }
11000         }
11001     }
11003     
11004     if (! $styles_loaded{$file}) {
11005         # look for a file named ${file}.perl
11006         # MRO: use $texfilepath instead of `..'
11007         if ((-f "$texfilepath$dd${file}.perl") && ! $styles_loaded{$file}){
11008             print STDOUT "\nPackage: loading $texfilepath$dd${file}.perl";
11009             require("$texfilepath$dd${file}.perl");
11010             $styles_loaded{$file} = 1;
11011         } else {
11012             foreach $dir (split(/$envkey/,$LATEX2HTMLSTYLES)) {
11013                 if ((-f "$dir$dd${file}.perl") && ! $styles_loaded{$file}){
11014                     print STDOUT "\nPackage: loading $dir$dd${file}.perl";
11015                     require("$dir$dd${file}.perl");
11016                     $styles_loaded{$file} = 1;
11017                     last;
11018                 }
11019             }
11020         }
11021     }
11024 sub do_require_extension {
11025     local($file)= @_;
11026     local($dir);
11028     if (! $styles_loaded{$file}) {
11029         # look for a file named ${file}.pl
11030         # MRO: use $texfilepath instead of `..'
11031         if (-f "$texfilepath$dd${file}.pl") {
11032             print STDOUT "\nExtension: loading $texfilepath$dd${file}.pl";
11033             require("$texfilepath$dd${file}.pl");
11034             ++$styles_loaded{$file};
11035             $NO_UTF = 1 if (($file =~ /latin/)&&($charset =~/utf/));
11036         } else {
11037             foreach $dir (split(/$envkey/,$LATEX2HTMLVERSIONS)) {
11038                 if (-f "$dir$dd${file}.pl"){
11039                     print STDOUT "\nExtension: loading $dir$dd${file}.pl";
11040                     require("$dir$dd${file}.pl");
11041                     ++$styles_loaded{$file};
11042                     $NO_UTF = 1 if (($file =~ /latin/)&&($charset =~/utf/));
11043                     last;
11044                 }
11045             }
11046         }
11047     } else {
11048         if (($file =~ /latin|hebrew/)&&($charset =~/utf|10646/)
11049                         && $loading_extensions) {
11050             $NO_UTF = 1;
11051             $USE_UTF = 0;
11052             print STDOUT "\n\n ...producing $CHARSET output\n";
11053             $charset = $CHARSET;
11054         } 
11055     }
11058 sub do_require_packageoption {
11059     local($option)= @_;
11060     local($do_option);
11061     # first look for a file named ${option}.perl
11062     &do_require_package($option) unless ($styles_loaded{$option});
11063     # next look for a subroutine named  do_$option
11064     $do_option = "do_$option";
11065     if (!($styles_loaded{$option}) && defined(&$do_option)) {
11066         &$do_option();
11067         $styles_loaded{$option} = 1;
11068     }
11071 ############################ Environments ################################
11073 # This is a dummy environment used to synchronise the expansion
11074 # of order-sensitive macros.
11075 sub do_env_tex2html_deferred {
11076     local($_) = @_;
11077     local($tex2html_deferred) = 1;
11078     $_ = &process_command($single_cmd_rx,$_);
11081 # catch wrapped commands that need not have been
11082 sub do_env_tex2html_nomath_inline {
11083     local($_) = @_;
11084     s/^\s+|\s+$//gs;
11085     my($cmd) = $_;
11086     if ($cmd=~s/^\\([a-zA-Z]+)//s) { $cmd = $1 };
11087     return (&translate_commands($_)) if ($raw_arg_cmds{$cmd}<1);
11088     &process_undefined_environment($env, $id, $_);
11091 # The following list environment subroutines still do not handle
11092 # correctly the case where the list counters are modified (e.g. \alph{enumi})
11093 # and the cases where user defined bullets are mixed with the default ones.
11094 # e.g. \begin{enumerate} \item[(1)] one \item two \end{enumerate} will
11095 # not produce the same bullets as in the dvi output.
11096 sub do_env_itemize {
11097     local($_) = @_;
11098     $itemize_level++;
11099     #RRM - catch nested lists
11100     &protect_useritems($_);
11101     $_ = &translate_environments($_);
11103     local($bullet,$bulletx)=('&nbsp;','');
11104     SWITCH: {
11105         if ($itemize_level==1) { $bulletx = "\\bullet"; last SWITCH; }
11106         if ($itemize_level==2) { $bulletx = "\\mathbf{\\circ}"; last SWITCH; }
11107         if ($itemize_level==3) { $bulletx = "\\mathbf{\\ast}"; last SWITCH; }
11108     }
11109     $itemize_level--;
11111     if (/\s*$item_description_rx/) {
11112         # Contains user defined optional labels
11113         $bulletx = &do_cmd_mbox("${O}1$C\$$bulletx\$${O}1$C") if $bulletx;
11114         &do_env_description($_, " COMPACT", $bullet.$bulletx)
11115     } else { &list_helper($_,'UL'); }
11118 sub do_env_enumerate {
11119     local($_) = @_;
11120 # Reiner Miericke provided the main code; integrated by RRM: 14/1/97
11121 # works currently only with 'enumerate' and derived environments
11122 # explicit styled labels are computed for each \item
11123 # ultimately the environment is done as:  &do_env_description($_, " COMPACT")
11124     ++$enum_level;
11125     local(%enum) = %enum;               # to allow local changes
11126 # Reiner: \begin{enumerate}[<standard_label>]
11127     local($standard_label) = "";
11128     local(@label_fields);
11129     local($label_func, $preitems, $enum_type);
11130     local($rlevel) = &froman($enum_level); # e.g. 3 => iii
11132     # \begin{enumerate}[$standard_label]
11133     if (s/^$standard_label_rx//s) {             # multiline on/off ?
11134         # standard label should be used later to modify
11135         # entries in %enum
11136         $standard_label = $1;           # save the standard label
11137 #       s/^$standard_label_rx//;        # and cut it off
11138         $standard_label =~ s/([\\\[\]\(\)])/\\$1/g; # protect special chars
11140         # Search for [aAiI1] which is not between a pair of { }
11141         # Other cases like "\theenumi" are not handled
11142         @label_fields = $standard_label =~ /$enum_label_rx/;
11143         if (($standard_label =~ /^[aAiI1]$/)&&(not(/item\s*\[/))) {
11144             $enum_type = ' TYPE="'.$standard_label.'"';
11145             $standard_label = '';
11146         } else {
11147             $label_func = $enum_label_funcs{$label_fields[$#label_fields-1]} . 
11148                 "(\'enum" . $rlevel . "\')";
11149             $enum{'theenum' . $rlevel} = "\&$label_func";
11150 #       local($thislabel) = "\&$label_func";
11151 #       do { local($_) = $thislabel; &make_unique($_);
11152 #            $enum{'theenum' . $rlevel} = $_; };
11153             $standard_label = 
11154                 "\"$label_fields[0]\" . eval(\$enum{\"theenum$rlevel\"})"
11155                 . ".\"$label_fields[$#label_fields]\"";
11156             $enum{'labelenum' . $rlevel} = $standard_label;
11157         }
11158     }  elsif (s/^((.|\n)+?)\\item/$preitems=$1;"\\item"/es) {
11159         my $pre_preitems; local($cmd); $label_part;
11160         my $num_styles = join('|', values %enum_label_funcs );
11161         while ($preitems =~
11162             /\s*\\renew(ed)?command\s*(($O|$OP)\d+($C|$CP))\\?((label|the)enum(\w+))\s*\2/) {
11163             # this catches one  \renewcommand{\labelenum}{....} 
11164             $pre_preitems .= $`; $preitems = $'; $cmd = $5;
11165             &missing_braces unless (
11166                 ($preitems=~s/$next_pair_pr_rx\s*/$label_part=$2;''/oe)
11167                 ||($preitems=~s/$next_pair_rx\s*/$label_part=$2;''/oe));
11168             $cmd =~ s/^label/the/;
11169             $label_part=~s/\\($num_styles)\s*(($O|$OP)\d+($C|$CP))(\w+)\2/".\&$1\(\'$5\'\)."/g;
11170             $label_part = '"'.$label_part.'"';
11171             $enum{$cmd} = $label_part;
11172         }
11173         $standard_label = 
11174             "\"$label_fields[0]\" . eval(\$enum{\"theenum$rlevel\"})"
11175             . ".\"$label_fields[$#label_fields]\"" if ($cmd);
11176         $_ = $pre_preitems . $preitems . $_ if ($pre_preitems||$preitems);
11177     } else {
11178         @enum_default_type = ('A', '1', 'a', 'i', 'A') unless (@enum_default_type);
11179         $enum_type = $enum_level%4;
11180         $enum_type = ' Type="'.@enum_default_type[$enum_type].'"';
11181     }
11183     # enclose contents of user-defined labels within a group,
11184     # in case of style-change commands, which could bleed outside the label.
11185     &protect_useritems($_);
11186     $_ = &translate_environments($_);   #catch nested lists
11188     local($enum_result);
11189     if (($standard_label)||(/\\item\[/)) {
11190         # split it into items
11191         @items = split(/\\item\b/,$_);
11192         # save anything (non-blank) before the items actually start
11193         $preitems = shift(@items);
11194         $preitems =~ s/^\s*$//;
11195         local($enum_label);
11196         # prepend each item with an item label: \item => \item[<label>]
11197         foreach $item (@items) {
11198 #         unless ( $item =~ /^\s*$/ ) { # first line may be empty
11199             $enum{"enum" . $rlevel}++;  # increase enumi
11200             $enum_label = eval("$enum{'labelenum' . $rlevel}");
11201             # insert a label, removing preceding space, BUT...
11202             # do NOT handle items with existing labels
11203             $item =~ s/^\s*//;
11204             if ($item =~ s/^\s*\[([^]]*)\]//) {
11205                 $enum{"enum" . $rlevel}--;
11206                 $enum_label = "$1";
11207                 local($processed) = ($enum_label =~/$OP/);
11208                 $enum_label = join('',($processed ? "<#0#>" : "<<0>>")
11209                     ,$enum_label ,($processed ? "<#0#>" : "<<0>>"))
11210                         if ($enum_label =~ /\\/);
11211                 if ($processed) { &make_unique_p($enum_label) }
11212                 elsif ($enum_label =~ /$O/) { &make_unique($enum_label) };
11213                 $item = "[${enum_label}]".$item;
11214             } else { 
11215                 local($processed) = ($enum_label =~/$OP/);
11216                 $enum_label = join('',($processed ? "<#0#>" : "<<0>>")
11217                     ,$enum_label ,($processed ? "<#0#>" : "<<0>>"))
11218                         if ($enum_label =~ /\\/);
11219                 if ($processed) { &make_unique_p($enum_label) }
11220                 elsif ($enum_label =~ /$O/) { &make_unique($enum_label) };
11221                 $item = "[$enum_label\]$item";
11222                 $enum_label =~ s/\.$//;
11223             }
11224             if ($standard_label) {
11225                 $item =~ s/(\\labelitem$rlevel|$standard_label)/$enum_label/g
11226             } else {
11227                 $item =~ s/(\\labelitem$rlevel)/$enum_label/g
11228             }
11229         };
11230         $_ = join("\\item ", $preitems, @items);
11232         # Original, but $enum_result
11233         $enum_result = &do_env_description($_, " COMPACT");
11234     } else {
11235         $enum_result = &list_helper($_, "OL$enum_type", '', '');
11236     }
11238     #clean-up and revert the $enum_level
11239     $enum{"enum" . $rlevel} = 0;
11240     $enum{"enum" . &froman($enum_level)} = 0;
11241     --$enum_level;
11242     $enum_result;
11245 sub do_env_list {
11246     local ($_) = @_;
11247     local ($list_type,$labels,$lengths) = ('UL','','');
11249     $labels = &missing_braces unless     ( # get the label specifier
11250         (s/$next_pair_pr_rx/$labels=$2;''/e)
11251         ||(s/$next_pair_rx/$labels=$2;''/e));
11253     $lengths = &missing_braces unless ( # get the length declarations
11254         (s/$next_pair_pr_rx/$lengths=$2;''/e)
11255         ||(s/$next_pair_rx/$lengths=$2;''/e));
11256     # switch to enumerated style if they include a \usecounter.
11257     $list_type = 'OL' if $lengths =~ /\\usecounter/;
11259     /\\item\b/; local($preitems) = $`;
11260         $_ =~ s/^\Q$preamble//s if ($preitems);
11261     $preitems =~s/^\s*|\s*$//g;
11262     if ($preitems) {
11263         $preitems = &translate_environments($preitems);
11264         $preitems = &translate_commands($preitems) if ($preitems =~ /\\/);
11265 #       &write_warnings("\nDiscarding: $preitems before 1st item in list")
11266 #           if ($preitems);
11267     }
11269     #RRM - catch nested lists
11270     #RRM unfortunately any uses of the \\usecounter  within \item s
11271     #    may be broken --- sigh.
11272     &protect_useritems($_);
11273     $_ = &translate_environments($_);
11275     if (($list_type =~ /OL/)&&($labels)) {
11276         local($br_ida,$br_idb,$label,$aft);
11277         $br_ida = ++$global{'max_id'};
11278         $lengths =~ s/\\usecounter((($O|$OP)\d+($C|$CP))[^<]+\2)/
11279                 &make_nowrapper(1)."\\stepcounter$1".&make_nowrapper(0)/e;
11280         $labels = "$O$br_ida$C$lengths$O$br_ida$C".$labels;
11282 #       s/\\item\b\s*([^\[])/do {
11283 #               $label = $labels; $aft = $1;
11284 #               $br_id = ++$global{'max_id'};
11285 #               $label = &translate_environments(
11286 #                       "$O$br_id$C$label$O$br_id$C");
11287 #               join('',"\\item\[" , $label, "\]$aft" );
11288 #           }/eg;
11289 #       $labels ='';
11290     }
11292     if (($labels)||(/\\item\[/)) {
11293         $_ = &list_helper($_, 'DL', $labels, $lengths)
11294     } else {
11295         $_ = &list_helper($_, $list_type, '', $lengths)
11296     }
11297     $_;
11300 sub do_env_trivlist {
11301     local($_) = @_;
11302     local($compact,$item_sep,$pre_items) = ' COMPACT';
11303     &protect_useritems($_);
11305     # assume no styles initially for this list
11306     local($close_tags,$reopens) = &close_all_tags();
11307     local($open_tags_R) = [];
11308     local(@save_open_tags) = ();
11310     # include \label anchors from [...] items
11311     s/$item_description_rx\s*($labels_rx8)?\s*/
11312         (($9)? "<A NAME=\"$9\">$1<\/A>" : $1 ) ."\n"/eg;
11313     # remove unwanted space before \item s
11314     s/[ \t]*\\item\b/\\item/g;
11315     
11316     local($this_item,$br_id) = ('','');
11317     local($this_sitem,$this_eitem) = ("\n<P>","</P>\n",'');
11319     # assume no sub-lists, else...  why use {trivlist} ?
11320     # extract up to the 1st \item
11321     local(@items) = split(/\\item\b/, $_);
11322     $pre_items = shift @items;
11323     $_ = '';
11324     while (@items) {
11325         $br_id = ++$global{'max_id'};
11326         $this_item = shift @items;
11327         $this_item = &translate_environments(
11328              "$O$br_id$C".$pre_items.$this_item."$O$br_id$C" );
11329         if ($this_item =~ /\\/) {
11330             $this_item = &translate_commands($this_item);
11331             $_ .= join('' , $this_sitem 
11332                        , $this_item
11333                        # , $this_eitem
11334                        )
11335         } else { $_ .= $this_sitem . $this_item }
11336     }
11337         
11338     $_ = &translate_environments($_);
11339     $_ = &translate_commands($_);
11341     join('' , $close_tags , $_ , $reopens);
11345 # enclose the contents of any user-defined labels within a group,
11346 # else any style-change commands may bleed outside the label.
11347 sub protect_useritems {
11348     # MRO: use $_[0] instead: local(*_) = @_;
11349     local($preitems, $thisitem);
11350     $_[0] =~ s/^$par_rx\s*//s; # discard any \par before 1st item
11352     # locate \item with optional argument 
11353     local($saveRS) = $/; undef $/;
11354     local(@preitems);
11355     # allow one level of nested []
11356     # MRO: Caution! We have a double-wildcarded RX here, this may cause
11357     # trouble. Should be re-coded.
11358     $_[0] =~ s/\\item[\s\r]*(\b(\[(([^\[\]]|\[[^]]*\])*)\])?|[^a-zA-Z\s])/
11359         $thisitem = " $1";
11360         if ($2) {
11361             $br_id = ++$global{'max_id'};
11362             $thisitem = '['.$O.$br_id.$C.$3.$O.$br_id.$C.']';
11363         };
11364         "\\item".$thisitem
11365     /egm;
11367     $/ = $saveRS;
11368     $_[0] = join(@preitems, $_[0]);
11371 sub do_env_description {
11372     local($_, $compact, $bullet) = @_;
11373     #RRM - catch nested lists
11374     &protect_useritems($_);
11375     $_ = &translate_environments($_) unless ($bullet);
11377     # MRO: replaced $* with /m
11378     $compact = "" unless $compact;
11379     if ($compact) {             # itemize/enumerate with optional labels
11380         s/\n?$item_description_rx\s*($labels_rx8)?\s*/"\n<\/DD>\n<DT>". 
11381             (($9)? "<A NAME=\"$9\">$1<\/A>" : $1 ) ."<\/DT>\n<DD>"/egm;
11382     } else {
11383         s/\n?$item_description_rx\s*($labels_rx8)?\s*/"\n<\/DD>\n<DT>". 
11384             (($9)? "<A NAME=\"$9\"><STRONG>$1<\/STRONG><\/A>" 
11385              : "<STRONG>$1<\/STRONG>") ."<\/DT>\n<DD>"/egm;
11386     }
11387     # and just in case the description is empty ...
11388 #JCL(jcl-del) - $delimiter_rx -> ^$letters
11389     s/\n?\\item\b\s*([^$letters\\]|)\s*/\n<\/DD>\n<DT>$bullet<\/DT>\n<DD>$1/gm;
11390     s/^\s+//m;
11392     $_ = '<DD>'.$_ unless ($_ =~ s/^\s*<\/D(T|D)>\n?//s);
11393     $_ =~ s/\n$//s;
11394     "<DL$compact>\n$_\n</DD>\n</DL>";
11397 sub list_helper {
11398     local($_, $tag, $labels, $lengths) = @_;
11399     local($item_sep,$pre_items,$compact,$etag,$ctag);
11400     $ctag = $tag; $ctag =~ s/^(.*)\s.*$/$1/;
11402     # assume no styles initially for this list
11403     local($close_tags,$reopens) = &close_all_tags();
11404     local($open_tags_R) = [];
11405     local(@save_open_tags) = ();
11407 #    #RRM: cannot have anything before the first <LI>
11408 #    local($savedRS) = $/; $/='';
11409 #    $_ =~ /\\item[\b\r]/s;
11410 #    if ($`) { 
11411 #       $preitems = $`; $_ = $&.$';
11412 #       $preitems =~ s/<P( [^>]*)?>//g;
11413 #       $close_tags .= "\n".$preitems if $preitems;
11414 #    }
11415 #    $/ = $savedRS; 
11418     $* = 1;                     # Multiline matching ON
11419     if (($tag =~ /DL/)&&$labels) {
11420         local($label,$aft,$br_id);
11421         s/\\item\b[\s\r]*([^\[])/do {
11422                 $label = $labels; $aft = $1;
11423                 $br_id = ++$global{'max_id'};
11424                 $label = &translate_environments(
11425                         "$O$br_id$C$label$O$br_id$C");
11426                 join('',"\\item\[" , $label, "\]$aft" );
11427             }/eg;
11428     }
11429     $* = 0;                     # Multiline matching OFF
11431     # This deals with \item[xxx] ...
11432     if ($tag =~ /DL/) {
11433         $compact = ' COMPACT';
11434         # include \label anchors in the <DT> part
11435         # and  $pre_item  tags in the <DD> part:
11436         if ($labels && $lengths) { 
11437             $item_sep = "\n</DD>\n<DT>";
11438         } else {
11439             $item_sep = ($labels ? "<DT>$labels\n" : '') ."</DT>\n<DD>";
11440         }
11441         $etag = "\n</DD>";
11442         s/$item_description_rx[\r\s]*($labels_rx8)?[\r\s]*/"<DT>" .
11443             (($9)? "<A NAME=\"$9\">$1<\/A>" : $1 ) ."\n<DD>"/egm;
11444     } else {
11445         $item_sep = "\n</LI>\n<LI>";
11446         $etag = "\n</LI>";
11447     }
11449     # remove unwanted space before \item s
11450     s/[ \t]*\\item\b/\\item/gm;
11452     #JCL(jcl-del) - $delimiter_rx -> ^$letters
11453     s/\n?\\item\b[\r\s]*/$item_sep/egm;
11455     #RRM: cannot have anything before the first <LI>
11456     local($savedRS) = $/; $/='';
11457     $_ =~ /\Q$item_sep\E|<DT>|<LI>/s;
11458     #RRM: ...try putting it before the list-open tag
11459     if ($`) { 
11460         $preitems = $`; $_ = $&.$';
11461         $preitems =~ s/<P( [^>]*)?>//gm;
11462         $close_tags .= "\n".$preitems if $preitems;
11463     }
11464     $_ =~ s/^\s*<\/[^>]+>\s*//s;
11466     # remove \n from end of the last item
11467     $_ =~ s/\n$//s;
11468     $/ = $savedRS;
11470     join('' , $close_tags , "\n<$tag$compact>\n" 
11471          , $_ , "$etag\n</$ctag>" , $reopens);
11475 # RRM:  A figure environment generates a picture UNLESS it contains a 
11476 # {makeimage} sub-environment; in which case it creates a <DIV>
11477 # inside which the contents are interpreted as much as is possible.
11478 # When there are captions, this modifies $before .
11479 sub do_env_figure {
11480     local($_) = @_;
11481     local($halign, $anchors) = ('CENTER','');
11482     local ($border, $attribs );
11483     local($cap_width) = $cap_width;
11484     my ($opt, $dummy) = &get_next_optional_argument;
11486     my $abovedisplay_space = $ABOVE_DISPLAY_SPACE||"<P></P>\n";
11487     my $belowdisplay_space = $BELOW_DISPLAY_SPACE||"<P></P>\n";
11489     ($_,$anchors) = &extract_labels($_); # extract labels
11490     # Try to establish the alignment
11491     if (/^(\[[^\]]*])?\s*\\begin\s*<<\d*>>(\w*)<<\d*>>|\\(\w*)line/) {
11492         $halign = $2.$3;
11493         if ($halign =~ /right/i)  { $halign = 'RIGHT' }
11494         elsif ($halign =~ /left/i) { $halign = 'LEFT' }
11495         elsif ($halign =~ /center/i) { $halign = 'CENTER' }
11496         else { $halign = 'CENTER' }
11497     }
11499     # allow caption-alignment to be variable
11500     local($cap_align);
11501     if ($FIGURE_CAPTION_ALIGN =~ /^(TOP|BOTTOM|LEFT|RIGHT)/i) {
11502         $cap_align = join('', ' ALIGN="', $&, $','"')};  
11504     local($cap_env, $captions,$has_minipage) = ('figure','');
11505     if ((/\\begin\s*($O\d+$C)\s*(makeimage|minipage)\s*\1|\\docode/)||
11506         (/\\includegraphics/&&(!/$htmlborder_rx|$htmlborder_pr_rx|\\htmlimage/))){
11507         $has_minipage = ($2 =~ /minipage/sg );
11508         $_ = &translate_environments($_);
11509         if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11510         elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11511         do { local($contents) = $_;
11512             &extract_captions($cap_env); $_ = $contents;
11513         } if (/\\caption/);
11514         $_ = &translate_commands($_);
11515         while ($_ =~ s/(^\s*<BR>\s*|\s*<BR>\s*$)//sg){}; # remove unneeded breaks
11516     } else {
11517         do { local($contents) = $_;
11518             # MRO: no effect: &extract_captions($cap_env, *cap_width); $_ = $contents;
11519             &extract_captions($cap_env); $_ = $contents;
11520         } if (/\\caption/);
11521         # Generate picture of the whole environment
11522         if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11523         elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11524         $_ = &process_undefined_environment($env, $id, $_);
11525         $_ = &post_latex_do_env_figure($_);
11526         $_ =~ s/\s*<BR>\s*$//g;
11527     }
11529     if ($captions) {
11530         # MRO: replaced $* with /m
11531         $captions =~ s/^\n//m;
11532         $captions =~ s/\n$//m;
11533     }
11534     s/$caption_mark//g;
11536     local($close_tags) = &close_all_tags;
11537     $_ .= $close_tags;
11539     # place all the pieces inside a TABLE, if available
11540     if ($HTML_VERSION > 2.1) {
11541         if ($captions) {
11542             local($pxs,$len) = &convert_length($cap_width,$MATH_SCALE_FACTOR)
11543                 if $cap_width;
11544             local($table) = "<TABLE$env_id"; # WIDTH="65%"';
11545             $table .= " WIDTH=\"$pxs\"" if ($pxs);
11546             if ($border) { $table .= " BORDER=\"$border\"" } # no checking !!
11547             $table .= ">";
11548             s/^\s*|\s*$//g;
11549             join (''
11550                     , $above_display_space
11551                     , "\n<DIV", ($halign ? " ALIGN=\"$halign\"" :'')
11552                     , '>', $anchors , $cap_anchors
11553                     , "\n$table\n<CAPTION", $cap_align, '>'
11554                     , $captions , "</CAPTION>\n<TR><TD>"
11555                     , ($cap_width ? '</TD><TD>' : '')
11556                     , $_ , '</TD>'
11557                     , ($cap_width ? '<TD></TD>' : '')
11558                     , "</TR>\n</TABLE>\n</DIV>\n"
11559                     , $below_display_space
11560             )
11561         } elsif ($halign) {
11562             if ($border||($attributes)||$env_id) {
11563                 &make_table( $border, $attribs, $anchors, '', $halign, $_ );
11564             } else {
11565                 join (''
11566                         , $above_display_space
11567                         , "\n<DIV ALIGN=\"$halign\">\n"
11568                         , ($anchors ? "\n<P>$anchors</P>" : '')
11569                         , $_
11570                         , "\n</DIV>"
11571                         , $below_display_space
11572                 )
11573             }
11574         } else {
11575             if ($border||($attributes)||$env_id) {
11576                 join (''
11577                         , $above_display_space
11578                         , "\n<DIV", ($halign ? " ALIGN=\"$halign\"":'')
11579                         , '>'
11580                         , &make_table( $border, $attribs, $anchors, '', $halign, $_ )
11581                         , "\n</DIV><BR"
11582                         , (($HTML_VERSION > 3.1)? " CLEAR=\"ALL\"" :'')
11583                         , '>'
11584                         , $below_display_space
11585                 );
11586             } else {  
11587                 join (''
11588                         , $above_display_space
11589                         , "\n<DIV", ($halign ? " ALIGN=\"$halign\"":'')
11590                         , ">$anchors\n" , $_ , "\n</DIV><BR"
11591                         , (($HTML_VERSION > 3.1)? " CLEAR=\"ALL\"" :'')
11592                         , '>'
11593                         , $below_display_space
11594                 );
11595             }
11596         }
11597     } else {
11598         # MRO: replaced $* with /m
11599         s/^\n//m;
11600         s/\n$//m;
11601         if ($captions) {
11602             join('', "\n<BR>\n", (($anchors) ? "$anchors" : '')
11603                 , "$cap_anchors\n$captions\n<BR>" 
11604                 , "\n<P", ($halign ? " ALIGN=\"$halign\"":'')
11605                 , '>', $_ , "\n</P>");
11606         } elsif ($halign) {
11607             join ('', "<BR>\n$anchors", $_ , "\n<BR>" )
11608         } else {
11609             join('', "<BR>\n<P", ($halign ? " ALIGN=\"$halign\"":'')
11610                 , ">$anchors\n" , $_ , "\n</P><BR>");
11611         }
11612     }
11615 sub do_env_figurestar { &do_env_figure(@_) }
11617 sub do_env_table {
11618     local($_) = @_;
11619     local($halign, $anchors) = ('','');
11620     local ( $border, $attribs );
11621     &get_next_optional_argument;
11623     # Try to establish the alignment 
11624     if (/^(\[[^\]]*])?\s*\\begin\s*<<\d*>>(\w*)<<\d*>>|\\(\w*)line/) {
11625         $halign = $2.$3;
11626         if ($halign =~ /right/i)  { $halign = 'RIGHT' }
11627         elsif ($halign =~ /left/i) { $halign = 'LEFT' }
11628         elsif ($halign =~ /center/i) { $halign = 'CENTER' }
11629         else { $halign = '' }
11630     }
11632     local($cap_env, $captions) = ('table','');
11634     # allow caption-alignment to be variable
11635     local($cap_align);
11636     if ($TABLE_CAPTION_ALIGN =~ /^(TOP|BOTTOM|LEFT|RIGHT)/i) {
11637         $cap_align = join('', ' ALIGN="', $&, $','"')};  
11639     if ((/\\(begin|end)\s*($O\d+$C)\s*makeimage\s*\2/)||
11640             ($HTML_VERSION > 2.0 && (
11641                 /\\begin\s*($O\d+$C)\s*((super)?tabular|longtable)\s*\1/))) {
11642         $_ = &translate_environments($_);
11643         ($_,$anchors) = &extract_labels($_); # extract labels
11644         do { local($contents) = $_;
11645             &extract_captions($cap_env); $_ = $contents;
11646         } if (/\\caption/);
11647         if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11648         elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11649         $_ = &translate_commands($_);
11650         while ($_ =~ s/(^\s*<BR>\s*|\s*<BR>\s*$)//g){};
11651     } else {
11652         # Make an image of the whole environment.
11653         ($_,$anchors) = &extract_labels($_); # extract labels
11654         do { local($contents) = $_;
11655             &extract_captions($cap_env); $_ = $contents;
11656         } if (/\\caption/);
11657         if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11658         elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11659         $_ = &process_undefined_environment($env, $id, $_);
11660         $_ = &post_latex_do_env_table($_);
11661         $_ =~ s/\s*<BR>\s*$//g;
11662     }
11664     if ($captions) {
11665         # MRO: replaced $* with /m
11666         $captions =~ s/^\n//m;
11667         $captions =~ s/\n$//m;
11668     }
11669     s/$caption_mark//g;
11671     local($close_tags) = &close_all_tags;
11672     $_ .= $close_tags;
11674     #  when $captions remain place all the pieces inside a TABLE, if available
11675     if ($HTML_VERSION > 2.1) {
11676         if ($captions) {
11677             $halign = 'CENTER' unless $halign;
11678             local($table) = '<TABLE';
11679             if ($border) { $table .= " BORDER=\"$border\"" } # no checking !!
11680             $table .= ">";
11681             join ('', "<BR><P></P>\n<DIV$env_id ALIGN=\"$halign\">"
11682                 , "$anchors$cap_anchors\n$table\n<CAPTION", $cap_align, '>'
11683                 , $captions , "</CAPTION>\n<TR><TD>"
11684                 , $_ , "</TD></TR>\n</TABLE>\n</DIV><P></P><BR>" )
11685         } elsif ($halign) {
11686             if ($halign) {
11687                 # MRO: replaced $* with /m
11688                 s/^\s*(<(P|DIV)$env_id ALIGN=\"\w+[^>]+>)/$1$anchors/m
11689                     if ($anchors);
11690                 join('', "<BR>", $_, "\n<BR>" )
11691             } else {
11692                 join ('', "<BR>\n$anchors", $_ , "\n<BR>" )
11693             }
11694         } else {
11695             join ('', "<BR><P></P>\n<DIV$env_id ALIGN=\"CENTER\">$anchors\n", $_ , "\n</DIV><BR>" )
11696         }
11697     } else {
11698         # MRO: replaced $* with /m
11699         s/^\n//m;
11700         s/\n$//m;
11701         if ($captions) {
11702             join('', "<BR>\n", (($anchors) ? "$anchors" : ''), "$cap_anchors\n$captions\n<BR>"
11703                 , "\n<P ALIGN=\"$halign\">", $_, "\n</P><BR>");
11704         } elsif ($halign) {
11705             join ('', "<BR><P></P>\n$anchors", $_ , "\n<P></P>" )
11706         } else {
11707             join('', "<BR>\n<P ALIGN=\"CENTER\">$anchors\n", $_, "\n</P><BR>");
11708         }
11709     }
11712 sub do_env_tablestar { &do_env_table(@_) }
11714 # RRM:  A makeimage environment generates a picture of its entire contents, 
11715 #  UNLESS it is empty.
11717 sub do_env_makeimage {
11718     local($_) = @_;
11719     local($attribs, $border);
11720     s/^\s*//;
11721     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11722     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11723     if (/^((\\begin\s*(($O|$OP)\d+($C|$CP))tex2html_deferred\3)?\\par(\\end(($O|$OP)\d+($C|$CP))tex2html_deferred\7)?\%?\s*\n)+$/s) { return("\n<BR>\n") }
11724     if (/^(\s\%?\n)+$/s) { return() }
11725     $_ = &process_undefined_environment($env, $id, $_);
11726     if (($border||($attributes))&&($HTML_VERSION > 2.1 ))
11727         { $_ = &make_table( $border, $attribs, '', '', '', $_ ) }
11728     $_ . ((!$_=~/^\s*$/)? "\n<BR>\n" :'');
11731 sub do_env_abstract { &make_abstract($_[0]) }
11733 sub do_env_minipage {
11734     local($_) = @_;
11735     &get_next_optional_argument;
11736     local($width);
11737     $width = &missing_braces unless (
11738         (s/$next_pair_pr_rx/$width=$2;''/e)
11739         ||(s/$next_pair_rx/$width=$2;''/e));
11740     local($pxs,$len) = &convert_length($width,$MATH_SCALE_FACTOR) if $width;
11741     $width = " WIDTH=\"$pxs\"";
11742     
11743     local ( %mpfootnotes, $mpfootnotes ) unless ($MINIPAGE);
11744     local ( $border, $attribs, $footfile);
11745     $global{'mpfootnote'} = 0 unless ($MINIPAGE);
11746     $MINIPAGE++;
11747     print "\n *** doing minipage *** " if ($VERBOSITY > 1);
11748     local($open_tags_R) = [ @$open_tags_R ];
11749     local($close_tags,$reopens) = &close_all_tags();
11750     local(@save_open_tags) = @$open_tags_R;
11751    
11752     local($minipage_caption) if $cap_env;
11753     if ($cap_env &&($HTML_VERSION>2.1)) {
11754         do {
11755             local($captions);
11756             local($contents) = $_;
11757             &extract_captions($cap_env) if ($_ =~ /\\caption/m);
11758             $minipage_caption = $captions;
11759             $_ = $contents;
11760             undef $contents; undef $captions;
11761         };
11762     }
11764     if (s/^\s*$htmlborder_rx//so) {
11765         $attribs = $2; $border = (($4)? "$4" : 1)
11766     } elsif (s/^\s*$htmlborder_pr_rx//so) {
11767         $attribs = $2; $border = (($4)? "$4" : 1)
11768     }
11769     if (/^\s*\\/) {
11770         local($tmp) = ++$global{'max_id'};
11771         $_ = $O.$tmp.$C.$_.$O.$tmp.$C
11772     }
11773     $_ = &translate_environments($_);
11774     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11775     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11776     $_ = &translate_commands($_);
11777     $MINIPAGE--; $MINIPAGE='' if ($MINIPAGE==0);
11779     $_ .= &balance_tags();
11780     $attribs .= $width unless ($attribs =~ /WIDTH/i);
11781 #    if (($border||$attribs)&&$MINIPAGE&&($HTML_VERSION>2.1)) { 
11782     if (($border||$attribs||$env_id)&&$MINIPAGE&&($HTML_VERSION>2.1)) { 
11783         $_ = &make_table( $border, $attribs, '', '', '', $_ );
11784     } elsif ($MINIPAGE) { 
11785         $_ = join ('', '<BR><HR>', $_ , '<BR><HR><BR>' );
11786     } elsif (($border||($attribs)||$minipage_caption)&&($HTML_VERSION > 2.1 )) {
11787         $mpfootnotes = '<DL>'.$mpfootnotes.'</DL>' if $mpfootnotes;
11788         $_ = &make_table( $border, $attribs, '', $mpfootnotes, '', $_ );
11789         $_ = join('','<BR><HR'
11790                 , (($HTML_VERSION > 3.0)? ' WIDTH="50\%" ALIGN="CENTER"' : '')
11791                 , '>', $_ , '<BR><HR'
11792                 , (($HTML_VERSION > 3.0)? ' WIDTH="50\%" ALIGN="CENTER"' : '')
11793                 , '><BR>') unless ($border||$attribs||$mpfootnotes);
11794     } else {
11795         $global{'mpfootnote'} = 0;
11796         if ($mpfootnotes) {
11797             $mpfootnotes = '<DD>'.$mpfootnotes unless ($mpfootnotes =~ /^\s*<D(T|D)>/);
11798             $_ = join('','<BR><HR>', $_ , '<BR><HR'
11799                 , (($HTML_VERSION > 3.0)? ' WIDTH="200" ALIGN="LEFT"' : '')
11800                 , '><DL>', $mpfootnotes , '</DL><HR><BR'
11801                 , (($HTML_VERSION > 3.0)? ' CLEAR="all"' : '')
11802                 , '>' );
11803         } else {
11804             $_ = join ('', '<BR><HR><P></P>', $_ , '<BR><HR><BR>' );
11805         }
11806     }
11807     join('', $close_tags, $_, $reopens);
11810 if (($HTML_VERSION > 2.1)&&($HTML_VERSION < 4.0)) {
11811     $TABLE_attribs = ",ALIGN,";
11812     $TABLE__ALIGN = ",left,right,center,";
11813     $TABLE_attribs_rx_list = ",CELLPADDING,BORDER,WIDTH,CELLSPACING,";
11814     $TABLE__WIDTH_rx = "\^\\d+%?";
11815     $TABLE__BORDER_rx = $TABLE__CELLSPACING_rx = $TABLE__CELLPADDING_rx = "\^\\d+";
11818 sub make_table {
11819     local($border, $attribs, $anchors, $extra_cell, $halign, $_) = @_;
11820     local($table,$caption,$div,$end,$Tattribs);
11821     $caption = join('',"<CAPTION$cap_align>"
11822         , $minipage_caption
11823         ,'</CAPTION>') if ($minipage_caption);
11824     $end = "</TD></TR>\n</TABLE>";
11825     $table = join('', "<TABLE$env_id"
11826         , ((($caption)&&!($attribs =~/WIDTH/i)) ? " WIDTH=\"100\%\"" : '')
11827         , ((($border)&&!($attribs =~/BORDER/i)) ? " BORDER=\"$border\"" : '')
11828         );
11829     if ($attribs) {
11830         if (!($attribs =~ /=/)) {
11831             $Tattribs = &parse_valuesonly($attribs,"TABLE");
11832         } else {
11833             $Tattribs = &parse_keyvalues($attribs,"TABLE");
11834         }
11835         $table .= " $Tattribs" if ($Tattribs);
11836     }
11837     print STDOUT "\nTABLE: $table>" if ($VERBOSITY >2 );
11838     $table .= ">".$caption."\n<TR><TD>";
11839     if ($extra_cell) {
11840         local($sep) = "</TD></TR>\n<TR ALIGN=\"LEFT\">\n<TD>";
11841         join ('', $div, $anchors, $table, $_ , $sep, $extra_cell, $end );
11842     } else {
11843         join ('', $div, $anchors, $table, $_ , $end );
11844     }
11847 sub do_cmd_etalchar {
11848     local($_) = @_;
11849     my $etalchar;
11850     $etalchar = &missing_braces unless (
11851         (s/$next_pair_pr_rx/$etalchar = $2;''/eo)
11852         ||(s/$next_pair_rx/$etalchar = $2;''/eo));
11853     $etalchar = &translate_commands($etalchar) if ($etalchar =~ /\\/);
11854     if ($HTML_VERSION < 3.0) {
11855         $etalchar = &process_in_latex("\$^\{$etalchar\}\$");
11856     } else {
11857         $etalchar = '<SUP>'.$etalchar.'</SUP>';
11858     }
11859     $etalchar . $_
11862 sub do_env_thebibliography {
11863     # Sets $citefile and $citations defined in translate
11864     local($_) = @_;
11865     $bibitem_counter = 0;
11866     $citefile = $CURRENT_FILE;
11867     $citefiles{$bbl_nr} = $citefile;
11868     local($dummy,$title);
11869     $dummy = &missing_braces unless (
11870         (s/$next_pair_pr_rx/$dummy=$2;''/e)
11871         ||(s/$next_pair_rx/$dummy=$2;''/e));
11872     # MRO: replaced $* with /m
11873     s/^\s*$//gm; # Remove empty lines (otherwise will have paragraphs!)
11874     s/^\s*//m;
11876     # Replace non-breaking spaces, particularly in author names.
11877 #    s/([^\\])~/$1 /g; # Replace non-breaking spaces.
11879     $_ = &translate_environments($_);
11880     $_ = &translate_commands($_);
11882     # RRM: collect all anchors from initial \label and \index commands
11883     local($anchors) = &extract_anchors('',1);
11884     $_ = '<DD>'.$_ unless ($_ =~ /^\s*<D(T|D)>/);
11885     $citations = join('',"<DL COMPACT>", $_, "</DL>");
11886     $citations{$bbl_nr} = $citations;
11887     local($br_id);
11888     if ((defined &do_cmd_bibname)||$new_command{'bibname'}) {
11889         $br_id=++$global{'max_id'};
11890         $title = &translate_environments("$O$br_id$C\\bibname$O$br_id$C");
11891     } else { $title = $bib_title }
11892     if (! $title ) {
11893         if ((defined &do_cmd_refname)||$new_command{'refname'}) {
11894             $br_id=++$global{'max_id'};
11895             $title = &translate_environments("$O$br_id$C\\refname$O$br_id$C");
11896         } else { $title = $ref_name }
11897     }
11898     local($closures,$reopens) = &preserve_open_tags();
11899     $toc_sec_title = $title ;
11900     local $bib_head = $section_headings{'bibliography'};
11901     $_ = join('', $closures
11902             , &make_section_heading($title, $bib_head, $anchors)
11903             , "$bbl_mark#$bbl_nr#" , $reopens );
11904     $bbl_nr++ if $bbl_cnt > 1;
11905     $_ =~ s/;SPMnbsp;/ /g;  # replace non-breaking spaces with real ones
11906     $_;
11909 # IGNORE - We construct our own index
11910 sub do_env_theindex { "" }
11912 # This is defined in html.sty
11913 sub do_env_comment { "" }
11916 sub do_env_equation{
11917     local($_)=@_;  
11918     local($attribs, $border, $no_num);
11919     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11920     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11921     if (/\\nonumber/) {
11922         $no_num = 1;
11923         $_ = &process_undefined_environment($env,$id,$_);
11924     } else {
11925         $latex_body .= join('', "\n\\setcounter{equation}{"
11926                         , $global{'eqn_number'}, "}\n");
11928         #include equation-number into the key, with HTML 2.0
11929 #       $_ = join("\n", "%EQNO:".$global{'eqn_number'}, $_)
11930         $_ .= "%EQNO:".$global{'eqn_number'}."\n" if ($HTML_VERSION < 2.2);
11932         $_ = &process_undefined_environment($env,$id,$_);
11933         $global{'eqn_number'}++;
11934         local($save) = $_;
11935         $_ = join('', $save, &post_latex_do_env_equation($eqno_prefix));
11936     }
11937     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
11938         join('',"<BR>\n<DIV$env_id ALIGN=\"CENTER\">\n"
11939             , &make_table( $border, $attribs, '', '', '', $_ )
11940             , "\n<BR CLEAR=\"ALL\">");
11941     } elsif ($HTML_VERSION < 2.2 ) { 
11942         join('', "\n<P>", $_ , "\n<BR></P>" )
11943     } elsif ($HTML_VERSION > 2.1 ) { 
11944         join('', "\n<P ALIGN="
11945             , ((!$no_num &&($EQN_TAGS =~ /L/))?
11946                 '"LEFT"':($no_num ?'"CENTER"':'"RIGHT"'))
11947             , '>', $_ , "\n<BR></P>" )
11948     } else { $_ }
11951 sub do_env_eqnarray{
11952     local($_)=@_;
11953     local($attribs, $border, $no_num);
11954     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11955     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11956     local($contents) = $_;
11957 #    $_ = join("\n", "%EQNO:".$global{'eqn_number'}, $_)
11958 #       if ($HTML_VERSION < 3.2);  #include equation-number into the key.
11959     $_ .= "%EQNO:".$global{'eqn_number'}."\n" if ($HTML_VERSION < 2.2);
11960     $_ = &process_undefined_environment($env,$id,$_);
11961     $_ .= &post_latex_do_env_eqnarray($eqno_prefix,$contents);
11962     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
11963         join('',"<BR>\n<DIV ALIGN=\"CENTER\">\n"
11964             , &make_table( $border, $attribs, '', '', '', $_ )
11965             , "\n<BR CLEAR=\"ALL\">");
11966     } elsif ($HTML_VERSION < 2.2 ) { 
11967         join('', "\n<P>", $_ , "\n<BR></P>" )
11968     } elsif ($HTML_VERSION > 3.1 ) { 
11969         join('',"<BR>\n<DIV ALIGN=\"CENTER\">\n", $_ 
11970              , "\n</DIV><BR CLEAR=\"ALL\">" );
11971     } else {
11972         join('', "\n<P ALIGN="
11973              , (($EQN_TAGS =~ /L/)? '"LEFT"' : '"RIGHT"')
11974              , '>' , $_ , "\n<BR></P>" )
11975     }
11978 #RRM: these are needed with later versions, when {eqnarray}
11979 #  environments are split into <TABLE> cells.
11981 sub protect_array_envs {
11982     local($_) = @_;
11983     local($cnt, $arraybit, $thisbit, $which) = (0,'','','');
11984     # MRO: replaced $* with /m
11985     while (/\\(begin|end)\s*(<(<|#)\d+(#|>)>)($sub_array_env_rx)(\*|star)?\2/m ) {
11986         $thisbit = $` . $&; $_ = $'; $which = $1;
11987         do {
11988             # mark rows/columns in nested arrays
11989             $thisbit =~ s/;SPMamp;/$array_col_mark/g;
11990             $thisbit =~ s/\\\\/$array_row_mark/g;
11991             $thisbit =~ s/\\text/$array_text_mark/g;
11992             $thisbit =~ s/\\mbox/$array_mbox_mark/g;
11993         } if ($cnt > 0);
11994         $arraybit .= $thisbit;
11995         if ($which =~ /begin/) {$cnt++} else {$cnt--};
11996     }
11997     $_ = $arraybit . $_;
11999     local($presub,$thisstack) = '';
12000     for (;;) {
12001       # find \\s needing protection within \substack commands
12002       # a while-loop is simpler syntax, but uses longer strings
12003       if ( /(\\substack\s*(<(<|#)\d+(#|>)>)(.|\n)*)\\\\((.|\n)*\2)/m ) {
12004         $presub .= $`; $thisstack =$1.${array_row_mark}.$6; $_ = $';
12005         # convert all \\s in the \substack
12006         $thisstack =~ s/\\\\/${array_row_mark}/og;
12007         $presub .= $thisstack;
12008         } else { last }
12009     }
12010     $_ = $presub . $_ if ($presub);
12011     $_;
12014 sub revert_array_envs {
12015     local($array_contents) = @_;
12016     $array_contents =~ s/$array_col_mark/$html_specials{'&'}/go;
12017     $array_contents =~ s/$array_row_mark/\\\\/go;
12018     $array_contents =~ s/$array_text_mark/\\text/go;
12019     $array_contents =~ s/$array_mbox_mark/\\mbox/go;
12020     $array_contents;
12025 sub do_env_tabbing {
12026     local($_) = @_;
12027     local($attribs, $border);
12028     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
12029     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
12030     $_ = &tabbing_helper($_);
12031     if (/$image_mark/) {
12032         local($tab_warning) = 
12033            "*** Images are not strictly valid within HTML <pre> tags\n"
12034            . "Please change your use of {tabbing} to a {tabular} environment.\n\n";
12035            &write_warnings("\n".$tab_warning);
12036            print "\n\n **** invalid tabbing environment ***\n";
12037            print $tab_warning;
12038     }
12039     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
12040         join('',"<BR>\n<DIV$env_id ALIGN=\"CENTER\">\n"
12041             , &make_table( $border, $attribs, '', '', '', $_ )
12042             , "\n</DIV><BR CLEAR=\"ALL\">");
12043     } else { $_ }
12046 sub tabbing_helper {
12047     local($_) = @_;
12048     s/\\=\s*//go;  # cannot alter the tab-stops
12049     s/\t/ /g;      # convert any tabs to spaces
12050     # MRO: replaced $* with /m
12051     s/(^|\n)[^\n]*\\kill *\n/\n/gm;
12052     s/( )? *\n/$1/gm; # retain at most 1 space for a \n
12053     # replace \\ by \n ... , ignoring any trailing space
12054 #    s/\\\\ */\n/gm;
12055     # ...but make sure successive \\ do not generate a <P> tag
12056 #    s/\n( *)?\n/\n&nbsp;\n/gm;
12057     s/\\\&gt;//go;
12058     s/(^| *([^\\]))\\[>]/$2\t\t/go;
12059     s/([^\\])\\>/$1\t\t/go;
12060     s/\n$//; s/^\n//;           # strip off leading/trailing \n
12061     local($inside_tabbing) = 1;
12062     $_ = &translate_commands(&translate_environments($_));
12063     "<PRE><TT>\n$_\n</TT></PRE>";
12066 ################# Post Processing Latex Generated Images ################
12068 # A subroutine of the form post_latex_do_env_<ENV> can be used to
12069 # format images that have come back from latex
12071 # Do nothing (avoid the paragraph breaks)
12072 sub post_latex_do_env_figure { $_[0] }
12073 sub post_latex_do_env_figurestar { &post_latex_do_env_figure(@_) }
12075 sub post_latex_do_env_table { $_[0] }
12076 sub post_latex_do_env_tablestar { &post_latex_do_env_table(@_) }
12078 sub post_latex_do_env_equation {
12079     local($prefix) = @_;
12080     $global{'eqn_number'}+=1;
12081     # include equation number at the side of the image -- HTML 3.2
12082     if ($HTML_VERSION >= 3.2){
12083         join('',"<P ALIGN=\"" , (($EQN_TAGS eq "L") ? "left" : "right")
12084                 , "\">$EQNO_START" , $prefix 
12085                 , &translate_commands('\theequation')
12086                 , "$EQNO_END</P>\n<BR CLEAR=\"all\">" );
12087     # </P> creates unwanted space in some browsers, but others need it.
12088     } else { "" }
12091 sub do_cmd_theequation {
12092     if ($USING_STYLES) {
12093         $txt_style{'eqn-number'} = " " unless ($txt_style{'eqn-number'});
12094         join('', "<SPAN CLASS=\"eqn-number\">"
12095                 ,&get_counter_value('eqn_number'),"</SPAN>", $_[0]);
12096     } else { join('',&get_counter_value('eqn_number'), $_[0]); }
12099 sub post_latex_do_env_eqnarray {
12100     local($prefix,$body) = @_;
12101     local($num_string,$line,@lines) = '';
12102     local($side) = (($EQN_TAGS eq "L") ? "\"left\"" : "\"right\"" );
12103     # MRO: replaced $* with /m
12104     @lines = split(/\\\\\\\\/m, $body);
12105     $line = pop(@lines);
12106     if (!($line=~/^\s*$/)&&!($line =~/\\nonumber/)) {
12107         $global{'eqn_number'}++;
12108         $num_string .= join('', "<BR><BR>\n" , $EQNO_START , $prefix
12109             , &translate_commands('\theequation')
12110             , $EQNO_END);
12111     }
12112     foreach $line (@lines) {
12113         next if ($line=~/^\s*$/);
12114         $num_string .= "\n<BR>". (($MATH_SCALE_FACTOR > 1.3)? '<BR>' : '')
12115                         . "<BR CLEAR=$side>";
12116         if (!($line =~/\\(nonumber|(no)?tag)/)) {
12117             $global{'eqn_number'}+=1;
12118             $num_string .= join('', $EQNO_START , $prefix
12119                 , &translate_commands('\theequation')
12120                 , $EQNO_END);
12121          }
12122     }
12123     # include equation numbers at the side of the image -- HTML 3.2
12124     if ($HTML_VERSION >= 3.2){
12125         "<P ALIGN=\"" . (($EQN_TAGS eq "L") ? "left" : "right")
12126             . "\">" . (($DISP_SCALE_FACTOR >= 1.2 ) ? '<BIG>' : '')
12127             . ${num_string}
12128             . (($DISP_SCALE_FACTOR >= 1.2 ) ? '</BIG>' : '')
12129             . "</P>\n<BR CLEAR=\"all\">"
12130     # </P> creates unwanted space in some browsers, but others need it.
12131     } else { "" };
12134 sub post_latex_do_env_eqnarraystar {
12135     local($_) = @_;
12136     if (($HTML_VERSION >= 3.2)&&(!$NO_SIMPLE_MATH)){
12137         join('', "<BR>\n<DIV ALIGN=\"CENTER\">\n"
12138             , $_ , "\n<BR CLEAR=\"ALL\">\n<P>");
12139     } elsif (($HTML_VERSION >= 2.2)&&(!$NO_SIMPLE_MATH)) {
12140         join('', "\n<BR><P ALIGN=\"CENTER\">\n", $_ , "\n<BR></P>\n<P>");
12141     } else {
12142         join('', "\n<BR><P>\n", $_ , "\n<BR></P>\n<P>");
12143     }
12146 ############################ Grouping ###################################
12148 sub do_cmd_begingroup { $latex_body .= "\n\\begingroup\n"; $_[0] }
12149 sub do_cmd_endgroup { $latex_body .= "\\endgroup\n\n"; $_[0] }
12150 sub do_cmd_bgroup { $latex_body .= "\n\\bgroup\n"; $_[0] }
12151 sub do_cmd_egroup { $latex_body .= "\\egroup\n\n"; $_[0] }
12153 sub do_env_tex2html_begingroup {
12154     local($_) = @_;
12155     $latex_body .= "\\begingroup ";
12156     $_ = &translate_environments($_);
12157     $_ = &translate_commands($_);
12158     $latex_body .= "\\endgroup\n";
12159     $_;
12162 sub do_env_tex2html_bgroup {
12163     local($_) = @_;
12164     $latex_body .= "\\bgroup ";
12165     $_ = &translate_environments($_);
12166     $_ = &translate_commands($_);
12167     $latex_body .= "\\egroup\n";
12168     $_;
12172 ############################ Commands ###################################
12174 # Capitalizes what follows the \sc declaration
12175 # *** POTENTIAL ERROR ****
12176 # (This is NOT the correct meaning of \sc in the cases when it
12177 # is followed by another declaration (e.g. \em).
12178 # The scope of \sc should be limited to the next occurence of a
12179 # declaration.
12180 #sub do_cmd_sc {
12181 #    local($_) = @_;
12182 #    local(@words) = split(" ");
12183 # Capitalize the words which are not commands and do not contain any markers
12184 #   grep (do {tr/a-z/A-Z/ unless /(^\\)|(tex2html)/}, @words);
12185 #    grep (do {s/([a-z]+)/<small>\U$1\E<\/small>/g unless /(^\\)|(tex2html)/}, @words);
12186 #    join(" ", @words);
12188 sub do_cmd_sc { &process_smallcaps(@_) }
12189 sub do_cmd_scshape { &do_cmd_sc(@_) }
12191 # This is supposed to put the font back into roman.
12192 # Since there is no HTML equivalent for reverting
12193 # to roman we keep track of the open font tags in
12194 # the current context and close them.
12195 # *** POTENTIAL ERROR ****#
12196 # This will produce incorrect results in the exceptional
12197 # case where \rm is followed by another context
12198 # containing font tags of the type we are trying to close
12199 # e.g. {a \bf b \rm c {\bf d} e} will produce
12200 #       a <b> b </b> c   <b> d   e</b>
12201 # i.e. it should move closing tags from the end
12202 sub do_cmd_rm { # clean
12203     my ($str, $ot) = @_;
12204     $ot = $open_tags_R unless(defined $ot);
12205     return("<\#rm\#>".$str) if ($inside_tabular);
12207     my ($size,$color,$tags);
12208     while (@$ot) {
12209         my $next = pop (@$ot);
12210         print STDOUT "\n</$next>" if $VERBOSITY > 2;
12211         if ($next =~ /$sizechange_rx/) {
12212             $size = $next unless ($size);
12213         }
12214 #       if ($next =~ /$colorchange_rx/) {
12215 #           $color = $next unless ($color);
12216 #       }
12217         $declarations{$next} =~ m|</.*$|;
12218         $tags .= $& unless ($` =~ /^<>/);
12219     }
12220     if ($size) {
12221         $declarations{$size} =~ m|</.*$|;
12222         $tags .= $` unless ($` =~ /^<>/);
12223         push (@$ot,$size);
12224         print STDOUT "\n<$size>" if $VERBOSITY > 2;
12225     }
12226     $tags.$str;
12229 sub do_cmd_rmfamily{ &do_cmd_rm(@_) }
12231 sub do_cmd_textrm { 
12232     local($_) = @_;
12233     local($text,$br_id)=('','0');
12234     $text = &missing_braces unless (
12235         (s/$next_pair_pr_rx/$text=$2;$br_id=$1;''/eo)
12236         ||(s/$next_pair_rx/$text=$2;$br_id=$1;''/eo));
12237     join ('' ,
12238           &translate_environments("$O$br_id$C\\rm $text$O$br_id$C")
12239           , $_ );
12242 sub do_cmd_emph { 
12243     local($_) = @_;
12244     local($ifstyle,$join_tags) = ('',join(',',@$open_tags_R));
12245     $join_tags =~ s/(^|,)(text)?(it|rm|normalfont)/$if_style=$3;''/eg; 
12246     if ($if_style =~ /it/) {
12247         ($ifstyle,$join_tags) = ('',join(',',@$open_tags_R));
12248         $join_tags =~ s/(^|,)(text)?(bf|rm|normalfont)/$if_style=$3;''/eg; 
12249         if ($if_style =~ /bf/) { &do_cmd_textrm(@_) }
12250         else { &do_cmd_textbf(@_) }
12251     } else { &do_cmd_textit(@_) }
12254 #RRM: These cope with declared commands for which one cannot
12255 #     simply open a HTML single tag.
12256 #     The do_cmd_... gets found before the $declaration .
12258 sub do_cmd_upshape{&declared_env('upshape',$_[0],$tex2html_deferred)}
12259 sub do_cmd_mdseries{&declared_env('mdseries',$_[0],$tex2html_deferred)}
12260 sub do_cmd_normalfont{&declared_env('normalfont',$_[0],$tex2html_deferred)}
12263 # This is supposed to put the font back into normalsize.
12264 # Since there is no HTML equivalent for reverting
12265 # to normalsize we keep track of the open size tags in
12266 # the current context and close them.
12267 sub do_cmd_normalsize { # clean
12268     my ($str, $ot) = @_;
12269     $ot = $open_tags_R unless(defined $ot);
12271     my ($font,$fontwt,$closures,$reopens,@tags);
12273     while (@$ot) {
12274         my $next = pop @$ot;
12275         $declarations{$next} =~ m|</.*$|;
12276         my ($pre,$post) = ($`,$&);
12277         if ($post =~ /$block_close_rx|$all_close_rx/ ) {
12278             push (@$ot, $next);
12279             last;
12280         }
12281         $closures .= $post unless ($pre =~ /^<>/);
12282         print STDOUT "\n</$next>" if $VERBOSITY > 2;
12284         if ($next =~ /$fontchange_rx/) {
12285             $font = $next unless ($font);
12286         } elsif ($next =~ /$fontweight_rx/) {
12287             $fontwt = $next unless ($fontwt);
12288         } elsif ($next =~ /$sizechange_rx/) {
12289             # discard it
12290         } else {
12291             unshift (@tags, $next);
12292             print STDOUT "\n<<$next>" if $VERBOSITY > 2;
12293             $reopens .= $pre unless ($pre =~ /^<>/);
12294         }
12295     }
12296     push (@$ot, @tags);
12297     if ($font) {
12298         $declarations{$font} =~ m|</.*$|;
12299         $reopens .= $` unless ($` =~ /^<>/);
12300         push (@$ot,$font);
12301         print STDOUT "\n<$font>" if $VERBOSITY > 2;
12302     }
12303     if ($fontwt) {
12304         $declarations{$fontwt} =~ m|</.*$|;
12305         $reopens .= $` unless ($` =~ /^<>/);
12306         push (@$ot,$fontwt);
12307         print STDOUT "\n<$fontwt>" if $VERBOSITY > 2;
12308     }
12309     join('', $closures, $reopens, $str);
12314 #JCL(jcl-tcl)
12315 # changed everything
12317 sub do_cmd_title {
12318     local($_) = @_;
12319     &get_next_optional_argument;
12320     local($making_title,$next) = (1,'');
12321     $next = &missing_braces unless (
12322         (s/$next_pair_pr_rx/$next = $2;''/eo)
12323         ||(s/$next_pair_rx/$next = $2;''/eo));
12324     $t_title = &translate_environments($next);
12325     $t_title = &translate_commands($t_title);
12326 #    $toc_sec_title = &simplify(&translate_commands($next));
12327     $toc_sec_title = &purify(&translate_commands($next));
12328     $TITLE = (($toc_sec_title)? $toc_sec_title : $default_title)
12329         unless ($TITLE && !($TITLE =~ /^($default_title|\Q$FILE\E)$/));
12330 #    $TITLE = &purify($TITLE);
12332     #RRM: remove superscripts inserted due to \thanks
12333     $TITLE =~ s/<A[^>]*><SUP>\d+<\/SUP><\/A>/$1/g;
12334     $_;
12337 sub do_cmd_author {
12338     local($_) = @_;
12339     &get_next_optional_argument;
12340     my $next;
12341     $next = &missing_braces unless (
12342         (s/$next_pair_pr_rx/$next = $2;''/seo)
12343         ||(s/$next_pair_rx/$next = $2;''/seo));
12344     local($after) = $_;
12345     if ($next =~ /\\and/) {
12346         my @author_list = split(/\s*\\and\s*/, $next);
12347         my $t_author, $t_affil, $t_address;
12348         foreach (@author_list) {
12349             $t_author = &translate_environments($_);
12350             $t_author =~ s/\s+/ /g;
12351             $t_author = &simplify(&translate_commands($t_author));
12352             ($t_author,$t_affil,$t_address) = split (/\s*<BR>s*/, $t_author);
12353             push @authors, $t_author;
12354             push @affils, $t_affil;
12355             push @addresses, $t_address;
12356         }
12357     } else {
12358         $_ = &translate_environments($next);
12359         $next = &translate_commands($_);
12360         ($t_author) = &simplify($next);
12361         ($t_author,$t_affil,$t_address) = split (/\s*<BR>s*/, $t_author);
12362         push @authors, $t_author;
12363         push @affils, $t_affil if $t_affil;
12364         push @addresses, $t_address if $t_address;
12365     }
12366     $after;
12369 sub do_cmd_address {
12370     local($_) = @_;
12371     &get_next_optional_argument;
12372     local($next);
12373     $next = &missing_braces unless (
12374         (s/$next_pair_pr_rx/$next = $&;''/eo)
12375         ||(s/$next_pair_rx/$next = $&;''/eo));
12376     ($t_address) = &simplify(&translate_commands($next));
12377     push @addresses, $t_address;
12378     $_;
12381 sub do_cmd_institute {
12382     local($_) = @_;
12383     &get_next_optional_argument;
12384     local($next);
12385     $next = &missing_braces unless (
12386         (s/$next_pair_pr_rx/$next = $&;''/eo)
12387         ||(s/$next_pair_rx/$next = $&;''/eo));
12388     ($t_institute) = &simplify(&translate_commands($next));
12389     push @affils, $t_institute;
12390     $_;
12393 sub do_cmd_dedicatory {
12394     local($_) = @_;
12395     &get_next_optional_argument;
12396     local($next);
12397     $next = &missing_braces unless (
12398         (s/$next_pair_pr_rx/$next = $&;''/eo)
12399         ||(s/$next_pair_rx/$next = $&;''/eo));
12400     ($t_affil) = &simplify(&translate_commands($next));
12401     push @affils, $t_affil;
12402     $_;
12405 sub do_cmd_email {
12406     local($_) = @_;
12407     local($next,$target)=('','notarget');
12408     $next = &missing_braces unless (
12409         (s/$next_pair_pr_rx/$next = $2;''/eo)
12410         ||(s/$next_pair_rx/$next = $2;''/eo));
12411     local($mail) = &translate_commands($next);
12412     ($t_email) = &make_href("mailto:$mail","$mail");
12413     push @emails, $t_email;
12414     $_;
12417 sub do_cmd_authorURL {
12418     local($_) = @_;
12419     local($next);
12420     $next = &missing_braces unless (
12421         (s/$next_pair_pr_rx/$next = $2;''/eo)
12422         ||(s/$next_pair_rx/$next = $2;''/eo));
12423     ($t_authorURL) =  &translate_commands($next);
12424     push @authorURLs, $t_authorURL;
12425     $_;
12428 sub do_cmd_date {
12429     local($_) = @_;
12430     local($next);
12431     $next = &missing_braces unless (
12432         (s/$next_pair_pr_rx/$next = $&;''/eo)
12433         ||(s/$next_pair_rx/$next = $&;''/eo));
12434     ($t_date) = &translate_commands($next);
12435     $_;
12438 sub make_multipleauthors_title {
12439     local($alignc, $alignl) = (@_);
12440     local($t_author,$t_affil,$t_institute,$t_date,$t_address,$t_email,$t_authorURL)
12441         = ('','','','','','','');
12442     local ($t_title,$auth_cnt) = ('',0);
12443     if ($MULTIPLE_AUTHOR_TABLE) {
12444         $t_title = '<TABLE' .($USING_STYLES? ' CLASS="author_info_table"' : '')
12445                 .' WIDTH="90%" ALIGN="CENTER" CELLSPACING=15>'
12446                 ."\n<TR VALIGN=\"top\">";
12447     }
12448     foreach $t_author (@authors) {
12449         $t_affil = shift @affils;
12450         $t_institute = ''; # shift @institutes;
12451         $t_address = shift @addresses;
12452         $t_email = shift @emails;
12453         $t_authorURL = shift @authorURLs;
12454         if ($MULTIPLE_AUTHOR_TABLE) {
12455             if ($auth_cnt == $MAX_AUTHOR_COLS) {
12456                 $t_title .= join("\n", '</TR><TR>', '');
12457                 $auth_cnt -= $MAX_AUTHOR_COLS;
12458             }
12459             $t_title .= join("\n"
12460                 , '<TD>'
12461                 , &make_singleauthor_title($alignc, $alignl ,$t_author
12462                     , $t_affil,$t_institute,$t_date,$t_address,$t_email,$t_authorURL)
12463                 , '</TD>' );
12464             ++$auth_cnt;
12465         } else {
12466             $t_title .= &make_singleauthor_title($alignc, $alignl ,$t_author
12467                 , $t_affil,$t_institute,$t_date,$t_address,$t_email,$t_authorURL);
12468         }
12469     }
12470     if ($MULTIPLE_AUTHOR_TABLE) {
12471         $t_title .= "\n</TR></TABLE>\n";
12472     }
12473     $t_title;
12476 sub do_cmd_maketitle {
12477     local($_) = @_;
12478     local($the_title) = '';
12479     local($alignc, $alignl);
12480     if ($HTML_VERSION > 2.1) {
12481         $alignc = " ALIGN=\"CENTER\""; 
12482         $alignl = " ALIGN=\"LEFT\""; 
12483         $alignl = $alignc if ($MULTIPLE_AUTHOR_TABLE);
12484     }
12485     if ($t_title) {
12486         $the_title .= "<H1$alignc>$t_title</H1>";
12487     } else { &write_warnings("\nThis document has no title."); }
12488     if (($#authors >= 1)||$MULTIPLE_AUTHOR_TABLE) {
12489         $the_title .= &make_multipleauthors_title($alignc,$alignl);
12490         if ($t_date&&!($t_date=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12491             $the_title .= "\n<P$alignc><STRONG>$t_date</STRONG></P>";}
12492     } else {
12493         $the_title .= &make_singleauthor_title($alignc,$alignl ,$t_author
12494             , $t_affil,$t_institute,$t_date,$t_address,$t_email,$t_authorURL);
12495     }
12496     $the_title . $_ ;
12499 sub make_singleauthor_title {
12500     local($alignc, $alignl , $t_author
12501         , $t_affil,$t_institute,$t_date,$t_address,$t_email,$t_authorURL) = (@_);
12502     my $t_title = '';
12503     my ($s_author_info, $e_author_info) = ('<DIV','</DIV>');
12504     $s_author_info .= ($USING_STYLES ? ' CLASS="author_info"' : '').'>';
12506     if ($t_author) {
12507         if ($t_authorURL) {
12508             local($href) = &translate_commands($t_authorURL);
12509             $href = &make_named_href('author'
12510                         , $href, "<STRONG>${t_author}</STRONG>");
12511             $t_title .= "\n<P$alignc>$href</P>";
12512         } else {
12513             $t_title .= "\n<P$alignc><STRONG>$t_author</STRONG></P>";
12514         }
12515     } else { &write_warnings("\nThere is no author for this document."); }
12517     if ($t_institute&&!($t_institute=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12518         $t_title .= "\n<P$alignc><SMALL>$t_institute</SMALL></P>";}
12519     if ($t_affil&&!($t_affil=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12520         $t_title .= "\n<P$alignc><I>$t_affil</I></P>";}
12521     if ($t_date&&!($t_date=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12522         $t_title .= "\n<P$alignc><STRONG>$t_date</STRONG></P>";}
12523     if ($t_address&&!($t_address=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12524         $t_title .= "\n<P$alignl><SMALL>$t_address</SMALL></P>";
12525     }  # else { $t_title .= "\n<P$alignl>"}
12526     if ($t_email&&!($t_email=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12527         $t_title .= "\n<P$alignl><SMALL>$t_email</SMALL></P>";
12528     }  # else { $t_title .= "</P>" }
12529     join("\n", $s_author_info, $t_title, $e_author_info);
12532 sub do_cmd_abstract {
12533     local($_) = @_;
12534     local($abstract);
12535     $abstract = &missing_braces unless (
12536         (s/$next_pair_pr_rx/$abstract = $&;''/eo)
12537         ||(s/$next_pair_rx/$abstract = $&;''/eo));
12538     join('', &make_abstract($abstract), $_);
12541 sub make_abstract {
12542     local($_) = @_;
12543     # HWS  Removed emphasis (hard to read)         
12544     $_ = &translate_environments($_);
12545     $_ = &translate_commands($_);
12546     local($title);
12547     if ((defined &do_cmd_abstractname)||$new_command{'abstractname'}) {
12548         local($br_id)=++$global{'max_id'};
12549         $title = &translate_environments("$O$br_id$C\\abstractname$O$br_id$C");
12550     } else { $title = $abs_title }
12551     local($env_id) = " CLASS=\"ABSTRACT\"" if ($USING_STYLES);
12552     join('',"\n<H3>", $title, ":</H3>\n"
12553         , (($HTML_VERSION > 3)? "<DIV$env_id>" : "<P>"), $_ 
12554         , (($HTML_VERSION > 3)? "</DIV>" : "</P>"), "\n<P>");
12557 sub set_default_language {
12558     # MRO: local($lang,*_) = @_;
12559     my $lang = shift;
12560     push(@language_stack, $default_language);
12561     $default_language = $lang;
12562     $_[0] .= '\popHtmlLanguage';
12565 sub do_cmd_popHtmlLanguage {
12566     $default_language = pop(@language_stack);
12567     $_[0];
12570 sub do_cmd_today {
12571     local($lang);
12572     if ($PREAMBLE) {
12573         $lang = $TITLES_LANGUAGE || $default_language ;
12574     } else {
12575         $lang = $current_language || $default_language ;
12576     }
12577     local($today) = $lang . '_today';
12578     if (defined &$today) { join('', eval "&$today()", $_[0]) }
12579     else { join('', &default_today(), $_[0]) }
12582 sub default_today {
12583     #JKR: Make it more similar to LaTeX
12584     ## AYS: moved french-case to styles/french.perl
12585     my $today = &get_date();
12587     $today =~ s|(\d+)/0?(\d+)/|$Month[$1] $2, |;
12588     join('',$today,$_[0]);
12591 sub do_cmd_textbackslash { join('','&#92;', $_[0]);}
12592 sub do_cmd_textbar { join('','|', $_[0]);}
12593 sub do_cmd_textless { join('',';SPMlt;', $_[0]);}
12594 sub do_cmd_textgreater { join('',';SPMgt;', $_[0]);}
12595 sub do_cmd_textasciicircum { join('','&#94;', $_[0]);}
12596 sub do_cmd_textasciitilde { join('','&#126;', $_[0]);}
12597 sub do_cmd_textquoteleft { join('','&#96;', $_[0]);}
12598 sub do_cmd_textquoteright { join('','&#39;', $_[0]);}
12600 sub do_cmd_textcompwordmark { join('','', $_[0]);}
12601 sub do_cmd_texttrademark { join('','<SUP><SMALL>TM</SMALL></SUP>', $_[0]);}
12603 sub do_cmd_textsubscript   { &make_text_supsubscript('SUB',$_[0]);} 
12604 sub do_cmd_textsuperscript { &make_text_supsubscript('SUP',$_[0]);}
12606 sub make_text_supsubscript { 
12607     local ($supsub, $_) = (@_);
12608     my $arg = '';
12609     $arg = &missing_braces unless (
12610         (s/$next_pair_pr_rx/$arg = $&;''/eo)
12611         ||(s/$next_pair_rx/$arg = $&;''/eo));
12612     $arg = &translate_commands($arg) if ($arg =~ m!\\!);
12613     join('', "<$supsub>", $arg, "</$supsub>", $_);
12616 sub do_cmd_textcircled { 
12617     local ($_) = (@_);
12618     my $arg = '';
12619     $arg = &missing_braces unless (
12620         (s/$next_pair_pr_rx/$arg = $&;''/eo)
12621         ||(s/$next_pair_rx/$arg = $&;''/eo));
12622     my $after = $_;
12623     join('', &process_undefined_environment("tex2html_nomath_inline"
12624            , ++$global{'max_id'}
12625            , "\\vbox{\\kern3pt\\textcircled{$arg}}" )
12626         , $after );
12629 # these can be overridded in charset (.pl) extension files:
12630 sub do_cmd_textemdash { join('','---', $_[0]);}
12631 sub do_cmd_textendash { join('','--', $_[0]);}
12632 #sub do_cmd_exclamdown { join('','', $_[0]);}
12633 #sub do_cmd_questiondown { join('','', $_[0]);}
12634 sub do_cmd_textquotedblleft { join('',"``", $_[0]);}
12635 sub do_cmd_textquotedblright { join('',"''", $_[0]);}
12636 sub do_cmd_textbullet { join('','*', $_[0]);}
12637 sub do_cmd_textvisiblespace { join('','_', $_[0]);}
12639 sub do_cmd_ldots {
12640     join('',(($math_mode&&$USE_ENTITY_NAMES) ? ";SPMldots;" : "..."),$_[0]);
12643 sub do_cmd_dots {
12644     join('',(($math_mode&&$USE_ENTITY_NAMES) ? ";SPMldots;" : "..."),$_[0]);
12647 sub do_cmd_hrule {
12648     local($_) = @_;
12649     &ignore_numeric_argument;
12650     #JKR: No need for <BR>
12651     local($pre,$post) = &minimize_open_tags('<HR>');
12652     join('',$pre,$_);
12655 #sub do_cmd_hrulefill {
12656 #    "<HR ALIGN=\"right\">\n<BR CLEAR=\"right\">";
12659 sub do_cmd_linebreak {
12660     local($num,$dum) = &get_next_optional_argument;
12661     if (($num)&&($num<4)) { return $_[0] }
12662     join('',"<BR>", $_[0]);
12665 sub do_cmd_pagebreak {
12666     local($_) = @_;
12667     local($num,$dum) = &get_next_optional_argument;
12668     if (($num)&&($num<4)) { return($_) }
12669     elsif (/^ *\n *\n/) {
12670         local($after) = $';
12671         local($pre,$post) = &minimize_open_tags("<BR>\n<P>");
12672         join('',$pre, $')
12673     } else { $_ }
12677 sub do_cmd_newline { join('',"<BR>", $_[0]); }
12678 # this allows for forced newlines in tables, etc.
12679 sub do_cmd_endgraf { join('',"<BR>", $_[0]); }
12681 sub do_cmd_space { join(''," ",$_[0]); }
12682 sub do_cmd_enspace { join('',"\&nbsp;",$_[0]); }
12683 sub do_cmd_quad { join('',"\&nbsp;"x4,$_[0]); }
12684 sub do_cmd_qquad { join('',"\&nbsp;"x8,$_[0]); }
12686 sub do_cmd_par {
12687     local ($_) = @_;
12688     my ($pre,$post) = &preserve_open_tags();
12689     my ($spar, $lcode) = ("\n<P", '');
12690     if (($USING_STYLES) &&(!($default_language eq $TITLES_LANGUAGE))) {
12691         $lcode = &get_current_language();
12692         $spar .= $lcode if $lcode;
12693     }
12694     join('', $pre, $spar, ">\n",$post,$_);
12697 sub do_cmd_medskip {
12698     local ($_) = @_;
12699     local($pre,$post) = &preserve_open_tags();
12700     join('',$pre,"\n<P><BR>\n",$post,$_);
12703 sub do_cmd_smallskip {
12704     local ($_) = @_;
12705     local($pre,$post) = &preserve_open_tags();
12706     join('',$pre,"\n<P></P>\n",$post,$_);
12709 sub do_cmd_bigskip {
12710     local ($_) = @_;
12711     local($pre,$post) = &preserve_open_tags();
12712     join('',$pre,"\n<P><P><BR>\n",$post,$_);
12715 # MEH: Where does the slash command come from?
12716 # sub do_cmd_slash {
12717 #    join('',"/",$_[0]);
12719 sub do_cmd_esc_slash { $_[0]; }
12720 sub do_cmd_esc_hash { "\#". $_[0]; }
12721 sub do_cmd_esc_dollar { "\$". $_[0]; }
12722 sub do_cmd__at_ { $_[0]; }
12723 sub do_cmd_lbrace { "\{". $_[0]; }
12724 sub do_cmd_rbrace { "\}". $_[0]; }
12725 sub do_cmd_Vert { "||". $_[0]; }
12726 sub do_cmd_backslash { "\\". $_[0]; }
12728 #RRM: for subscripts outside math-mode
12729 # e.g. in Chemical formulae
12730 sub do_cmd__sub {
12731     local($_) = @_;
12732     local($next);
12733     $next = &missing_braces unless (
12734         (s/$next_pair_pr_rx/$next = $2;''/e)
12735         ||(s/$next_pair_rx/$next = $2;''/e));
12736     join('',"<SUB>",$next,"</SUB>",$_);   
12739 #JCL(jcl-del) - the next two ones must only have local effect.
12740 # Yet, we don't have a mechanism to revert such changes after
12741 # a group has closed.
12743 sub do_cmd_makeatletter {
12744     $letters =~ s/@//;
12745     $letters .= '@';
12746     &make_letter_sensitive_rx;
12747     $_[0];
12750 sub do_cmd_makeatother {
12751     $letters =~ s/@//;
12752     &make_letter_sensitive_rx;
12753     $_[0];
12757 ################## Commands to be processed by Latex #################
12759 # The following commands are passed to Latex for processing.
12760 # They cannot be processed at the same time as normal commands
12761 # because their arguments must be left untouched by the translator.
12762 # (Normally the arguments of a command are translated before the
12763 # command itself).
12765 # In fact, it's worse:  it is not correct to process these
12766 # commands after we process environments, because some of them
12767 # (for instance, \parbox) may contain unknown or wrapped
12768 # environments.  If math mode occurs in a parbox, the
12769 # translate_environments routine should *not* process it, lest
12770 # we encounter the lossage outlined above.
12772 # On the other hand, it is not correct to process these commands
12773 # *before* we process environments, or figures containing
12774 # parboxes, etc., will be mishandled.
12776 # RRM: (added for V97.1) 
12777 #  \parbox now uses the  _wrap_deferred  mechanism, and has a  do_cmd_parbox
12778 #  subroutine defined. This means that environments where parboxes are
12779 #  common (.g. within table cells), can detect the \parbox command and
12780 #  adjust the processing accordingly.
12782 # So, the only way to handle these commands is to wrap them up
12783 # in null environments, as for math mode, and let translate_environments
12784 # (which can handle nesting) figure out which is the outermost.
12786 # Incidentally, we might as well make these things easier to configure...
12788 sub process_commands_in_tex {
12789     local($_) = @_;
12790     local($arg,$tmp);
12791     foreach (/.*\n?/g) {
12792         chop;
12793         # For each line
12794         local($cmd, @args) = split('#',$_);
12795         next unless $cmd;
12796         $cmd =~ s/ //g;
12798         # skip if a proper implementation already exists
12799         $tmp = "do_cmd_$cmd";
12800         next if (defined &$tmp);
12802         # Build routine body ...
12803         local ($body, $code, $thisone) = ("", "");
12805         # alter the pattern here to debug particular commands
12806 #       $thisone = 1 if ($cmd =~ /mathbb/);
12808         print "\n$cmd: ".scalar(@args)." arguments" if ($thisone);
12809         foreach $arg (@args) {
12810             print "\nARG: $arg" if ($thisone);
12811             print "\nARG: $next_pair_rx" if ($thisone);
12812             if ($arg =~ /\{\}/) {
12813 # RRM: the $` is surely wrong, allowing no error-checking.
12814 # Use <<...>> for specific patterns
12815 #               $body .= '$args .= "$`$&" if s/$next_pair_rx//o;'."\n"; 
12816                 $body .= '$args .= join("","{", &missing_braces, "}") unless ('."\n";
12817                 $body .= '  (s/$next_pair_pr_rx/$args.=$`.$&;""/es)'."\n";
12818                 $body .= '  ||(s/$next_pair_rx/$args.=$`.$&;""/es));'."\n";
12819                 print "\nAFTER:$'" if (($thisone)&&($'));
12820                 $body .= $' if ($');
12821             } elsif ($arg =~ /\[\]/) {
12822                 $body .= '($dummy, $pat) = &get_next_optional_argument;'
12823                     . '$args .= $pat;'."\n";
12824                 print "\nAFTER:$'" if (($thisone)&&($'));
12825                 $body .= $' if ($');
12826             } elsif ($arg =~ /^\s*\\/) {                    
12827                 $body .= '($dummy, $pat) = &get_next_tex_cmd;'
12828                     . '$args .= $pat;'."\n";
12829                 print "\nAFTER:$'" if (($thisone)&&($'));
12830                 $body .= $' if ($');
12831             } elsif ($arg =~ /<<\s*/) {
12832                 $arg = $';
12833                 if ($arg =~ /\s*>>/) {
12834                     # MRO: replaced $* with /m
12835                     $body .= '$args .= "$`$&" if (/\\'.$`.'/m);' . "\n"
12836 #                   $body .= '$args .= "$`$&" if (/\\\\'.$`.'/);' . "\n"
12837                         . "\$_ = \$\';\n";
12838                     print "\nAFTER:$'" if (($thisone)&&($'));
12839                     $body .= $' if ($');
12840                 } else { $body .= $arg ; }
12841             } else {
12842                 print "\nAFTER:$'" if (($thisone)&&($arg));
12843                 $body .= $arg ;
12844             }
12845         }
12847         # Generate a new subroutine
12848         local($padding) = " ";
12849         $padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
12850         $code = "sub wrap_cmd_$cmd {" . "\n"
12851             . 'local($cmd, $_) = @_; local ($args, $dummy, $pat) = "";' . "\n"
12852             . $body
12853             . (($thisone)? "print STDERR \"\\n$cmd:\".\$args.\"\\n\";\n" : '')
12854             . '(&make_wrapper(1).$cmd'
12855             . ($padding ? '"'.$padding.'"' : '')
12856             . '.$args.&make_wrapper(0), $_)}'
12857             . "\n";
12858         print "\nWRAP_CMD: $code " if ($thisone); # for debugging
12859         eval $code; # unless ($thisone);
12860         print STDERR "\n*** sub wrap_cmd_$cmd  failed: $@" if ($@);
12862         # And make sure the main loop will catch it ...
12863 #       $raw_arg_cmds{$cmd} = 1;
12864         ++$raw_arg_cmds{$cmd};
12865     }
12868 sub process_commands_nowrap_in_tex {
12869     local($_) = @_;
12870     local($arg);
12871     foreach (/.*\n?/g) {
12872         chop;
12873         local($cmd, @args) = split('#',$_);
12874         next unless $cmd;
12875         $cmd =~ s/ //g;
12876         # Build routine body ...
12877         local ($bodyA, $codeA, $bodyB, $codeB, $thisone) = ("", "", "", "");
12879         # alter the pattern here to debug particular commands
12880 #       $thisone = 1 if ($cmd =~ /epsf/);
12882         print "\n$cmd: ".scalar(@args)." arguments" if ($thisone);
12883         foreach $arg (@args) {
12884             print "\nARG: $arg" if ($thisone);
12885             if ($arg =~ /\{\}/) {
12886 #               $bodyA .= '$args .= "$`"."$&" if (s/$any_next_pair_rx//);'."\n";
12887                 $bodyA .= 'if (s/$next_pair_rx//s){$args.="$`"."$&"; $_='."\$'};\n";
12888                 $bodyB .= '$args .= &missing_braces'."\n unless (";
12889                 $bodyB .= '(s/$any_next_pair_pr_rx/$args.=$`.$&;\'\'/eo)'."\n";
12890                 $bodyB .= '  ||(s/$any_next_pair_rx/$args.=$`.$&;\'\'/eo));'."\n";
12891                 print "\nAFTER:$'" if (($thisone)&&($'));
12892 #               $bodyA .= $'.";\n" if ($');
12893                 $bodyB .= $'.";\n" if ($');
12894             } elsif ($arg =~ /\[\]/) {
12895                 $bodyA .= '($dummy, $pat) = &get_next_optional_argument;'
12896                     . '$args .= $pat;'."\n";
12897                 print "\nAFTER:$'" if (($thisone)&&($'));
12898 #               $bodyA .= $'.";\n" if ($');
12899                 $bodyB .= $'.";\n" if ($');
12900             } elsif ($arg =~ /^\s*\\/) {                    
12901                 $bodyA .= '($dummy, $pat) = &get_next_tex_cmd;'
12902                     . '$args .= $pat;'."\n";
12903                 $bodyB .= '($dummy, $pat) = &get_next_tex_cmd;'
12904                     . '$args .= $pat;'."\n";
12905                 print "\nAFTER:$'" if (($thisone)&&($'));
12906                 $bodyA .= $'.";\n" if ($');
12907                 $bodyB .= $'.";\n" if ($');
12908             } elsif ($arg =~ /<<\s*/) {
12909                 $arg = $';
12910                 if ($arg =~ /\s*>>/) {
12911                     # MRO: replaced $* with /m
12912                     $bodyA .= '$args .= "$`$&" if (/\\'.$`.'/m);' . "\n"
12913 #                   $bodyA .= '$args .= $`.$& if (/\\\\'.$`.'/);' . "\n"
12914                         . "\$_ = \$\';\n";
12915                     $bodyB .= '$args .= "$`$&" if (/\\'.$`.'/m);' . "\n"
12916                         . "\$_ = \$\';\n";
12917                     print "\nAFTER:$'" if (($thisone)&&($'));
12918 #                   $bodyA .= $'.";\n" if ($');
12919                     $bodyB .= $'.";\n" if ($');
12920                 } else { 
12921                     print "\nAFTER:$arg" if (($thisone)&&($arg));
12922 #                   $bodyA .= $arg.";\n" if ($arg);
12923                     $bodyB .= $arg.";\n" if ($arg);
12924                 }
12925             } else { 
12926                 print "\nAFTER:$arg" if (($thisone)&&($arg));
12927                 $bodyA .= '$args .= '.$arg.";\n" if ($');
12928                 $bodyB .= $arg.";\n" if ($'); 
12929             }
12930         }
12931         local($padding) = " ";
12932         $padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
12933         # Generate 2 new subroutines
12934         $codeA = "sub wrap_cmd_$cmd {" . "\n"
12935             .'local($cmd, $_) = @_; local($args, $dummy, $pat) = "";'."\n"
12936             . $bodyA
12937             . (($thisone)? "print \"\\nwrap $cmd:\\n\".\$args.\"\\n\";\n" : '')
12938             . '(&make_nowrapper(1)."\n".$cmd.'."\"$padding\""
12939             . '.$args.&make_nowrapper(0)," ".$_)}'
12940             ."\n";
12941         print "\nWRAP_CMD: $codeA " if ($thisone); # for debugging
12942         eval $codeA;
12943         print STDERR "\n\n*** sub wrap_cmd_$cmd  failed: $@\n" if ($@);
12944         $codeB = "do_cmd_$cmd";
12945         do {
12946             $bodyB = '"";' if !($bodyB);
12947             $codeB = "sub do_cmd_$cmd {" . "\n"
12948                 . 'local($_,$ot) = @_;'."\n"
12949                 . 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'."\n"
12950                 . 'local($cmd,$args,$dummy,$pat)=("'.$cmd.'","","","");'."\n"
12951                 . $bodyB
12952                 . (($thisone)? "print \"\\ndo $cmd:\".\$args.\"\\n\";\n" : '')
12953 #               . '$latex_body.="\\n".&revert_to_raw_tex("'."\\\\$cmd$padding".'$args")."\\n\\n";'
12954                 . "\$_;}\n";
12955             print STDOUT "\nDO_CMD: $codeB " if ($thisone); # for debugging
12956             eval $codeB;
12957             print STDERR "\n\n*** sub do_cmd_$cmd  failed: $@\n" if ($@);
12958         } unless (defined &$codeB );
12960         # And make sure the main loop will catch it ...
12961 #       $raw_arg_cmds{$cmd} = 1;
12962         ++$raw_arg_cmds{$cmd};
12963     }
12966 sub process_commands_wrap_deferred {
12967     local($_) = @_;
12968     local($arg,$thisone);
12969     foreach (/.*\n?/g) {
12970         chop;
12971         local($cmd, @args) = split('#',$_);
12972         next unless $cmd;
12973         $cmd =~ s/ //g;
12974         # Build routine body ...
12975         local ($bodyA, $codeA, $bodyB, $codeB, $after, $thisone);
12977         # alter the pattern here to debug particular commands
12978 #       $thisone = 1 if ($cmd =~ /selectlanguage/);
12980         print "\n$cmd: ".scalar(@args)." arguments" if ($thisone);
12981         foreach $arg (@args) {
12982             print "\nARG: $arg" if ($thisone);
12983             if ($arg =~ /\{\}/) {
12984 #               $bodyA .= '$args .= "$`$&" if (s/$any_next_pair_rx//o);';
12985                 $bodyA .= '$args .= "$`$&" if (s/$next_pair_rx//so);';
12986                 $after = $';
12987                 print "\nAFTER:$'" if (($thisone)&&($'));
12988             } elsif ($arg =~ /\[\]/) {
12989                 $bodyA .= '($dummy, $pat) = &get_next_optional_argument;' .
12990                     "\n". '$args .= $pat;';
12991                 $after = $';
12992                 print "\nAFTER:$'" if (($thisone)&&($'));
12993             } elsif ($arg =~ /^\s*\\/) {                    
12994                 $bodyA .= '($dummy, $pat) = &get_next_tex_cmd;'
12995                     . '$args .= $pat;'."\n";
12996                 print "\nAFTER:$'" if (($thisone)&&($'));
12997                 $bodyA .= $'.";\n" if ($');
12998             } elsif (/<<\s*([^>]*)[\b\s]*>>/) {
12999                 local($endcmd, $afterthis) = ($1,$');
13000                 $afterthis =~ s/(^\s*|\s*$)//g;
13001                 $endcmd =~ s/\\/\\\\/g;
13002                 $bodyA .= "\n". 'if (/'.$endcmd.'/) { $args .= $`.$& ; $_ = $\' };';
13003                 $after .= $afterthis if ($afterthis);
13004                 print "\nAFTER:$'" if (($thisone)&&($'));
13005             } else { 
13006                 print "\nAFTER:$arg" if (($thisone)&&($arg));
13007                 $bodyB .= $arg.";\n" ; $after = ''
13008             }
13009             $after =~ s/(^\s*|\s*$)//g if ($after);
13010             $bodyB .= $after . ";" if ($after);
13011             $bodyA .= "\$args .= ".$after . ";" if ($after);
13012         }
13013         local($padding) = " ";
13014         $padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
13015         # Generate 2 new subroutines
13016         $codeA = "sub wrap_cmd_$cmd {" . "\n"
13017             .'local($cmd, $_) = @_; local ($args, $dummy, $pat) = "";'."\n"
13018             . $bodyA #. ($bodyA ? "\n" : '')
13019             . (($thisone)? ";print \"\\nwrap $cmd:\".\$args.\"\\n\";\n" : '')
13020             .'(&make_deferred_wrapper(1).$cmd.'.$padding
13021                 .'$args.&make_deferred_wrapper(0),$_)}'
13022             ."\n";
13023         print STDERR "\nWRAP_CMD: $codeA " if ($thisone); # for debugging
13024         eval $codeA;
13025         print STDERR "\n\n*** sub wrap_cmd_$cmd  failed: $@\n" if ($@);
13027         #RRM: currently these commands only go to LaTeX or access counters.
13028         #   They could be implemented more generally, as below with  do_dcmd_$cmd
13029         #   requiring replacement to be performed before evaluation.
13030         $codeB = "sub do_dcmd_$cmd {" . "\n"
13031             .'local($cmd, $_) = @_; local ($args, $dummy, $pat) = "";'."\n"
13032             . $bodyA . "\n" 
13033             . (($thisone)? ";print \"\\ndo_def $cmd:\".\$args.\"\\n\";\n" : '')
13034             . $bodyB . "}" . "\n";
13035         print "\nDEF_CMD: $codeB " if ($thisone); # for debugging
13036         local($tmp) = "do_cmd_$cmd";
13037         eval $codeB unless (defined &$tmp);
13038         print STDERR "\n\n*** sub do_dcmd_$cmd  failed: $@\n" if ($@);
13040         # And make sure the main loop will catch it ...
13041 #       $raw_arg_cmds{$cmd} = 1;
13042         ++$raw_arg_cmds{$cmd};
13043     }
13046 sub process_commands_inline_in_tex {
13047     local($_) = @_;
13048     foreach (/.*\n?/g) {
13049         chop;
13050         local($cmd, @args) = split('#',$_);
13051         next unless $cmd;
13052         $cmd =~ s/ //g;
13053         # Build routine body ...
13054         local ($body, $code, $thisone) = ("", "");
13056         # uncomment and alter the pattern here to debug particular commands
13057 #       $thisone = 1 if ($cmd =~ /L/);
13059         print "\n$cmd: ".scalar(@args)." arguments" if ($thisone);
13060         foreach (@args) {
13061             print "\nARG: $_" if ($thisone);
13062             if (/\{\}/) {
13063 #               $body .= '$args .= $`.$& if (/$any_next_pair_rx/);' . "\n"
13064 #                   . "\$_ = \$\';\n";
13065                 $body .= '$args .= $`.$& if (s/$next_pair_rx//s);' . "\n"
13066             } elsif (/\[\]/) {
13067                 $body .= 'local($dummy, $pat) = &get_next_optional_argument;' .
13068                     "\n". '$args .= $pat;';
13069             } elsif ($arg =~ /^\s*\\/) {                    
13070                 $body .= '($dummy, $pat) = &get_next_tex_cmd;'
13071                     . '$args .= $pat;'."\n";
13072                 print "\nAFTER:$'" if (($thisone)&&($'));
13073                 $body .= $'.";\n" if ($');
13074             } elsif (/<<\s*/) {
13075                 $_ = $';
13076                 if (/\s*>>/) {
13077                     # MRO: replaced $* with /m
13078                     $body .= '$args .= "$`$&" if (/\\'.$`.'/m);' . "\n"
13079                         . "\$_ = \$\';\n"
13080                 } else { $body .= $_.";\n" ; }
13081             } else { $body .= $_.";\n" ; }
13082         }
13083         local($padding) = " ";
13084         $padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
13085         # Generate a new subroutine
13086         my $itype = ($cmd =~ /^f.*box$/ ? 'inline' : 'nomath');
13087         $code = "sub wrap_cmd_$cmd {" . "\n"
13088             .'local($cmd, $_) = @_; local ($args) = "";' . "\n"
13089             . $body . "\n"
13090             . (($thisone)? ";print \"\\ndo $cmd:\".\$args.\"\\n\";\n" : '')
13091             .'(&make_'.$itype.'_wrapper(1).$cmd.$padding.$args.'
13092             . '&make_'.$itype.'_wrapper(0),$_)}'
13093             ."\n";
13094         print "\nWRAP_CMD:$raw_arg_cmds{$cmd}: $code "
13095                 if ($thisone); # for debugging
13096         eval $code;
13097         print STDERR "\n\n*** sub wrap_cmd_$cmd  failed: $@\n" if ($@);
13098         # And make sure the main loop will catch it ...
13099 #       $raw_arg_cmds{$cmd} = 1;
13100         ++$raw_arg_cmds{$cmd};
13101     }
13105 # Invoked before actual translation; wraps these commands in
13106 # tex2html_wrap environments, so that they are properly passed to
13107 # TeX in &translate_environments ...
13108 # JCL(jcl-del) - new usage of $raw_arg_cmd_rx
13109 sub wrap_raw_arg_cmds {
13110     local ($processed_text, $cmd, $wrapper, $wrap, $after);
13111     print "\nwrapping raw arg commands " if ($VERBOSITY>1);
13112     local($seg, $par_wrap, $teststar, @processed);
13113 #   local(@segments) = split(/\\par\b/,$_);
13114 #   foreach (@segments) {
13115 #      $par_wrap = join('',&make_deferred_wrapper(1), "\\par"
13116 #                       , &make_deferred_wrapper(0));
13117 #     push(@processed, $par_wrap ) if ($seg); ++$seg;
13118     if (%renew_command) {
13119         local($key);
13120         foreach $key (keys %renew_command) {
13121             $raw_arg_cmds{$key} = 1;
13122             $raw_arg_cmd_rx =~ s/^(\(\)\\\\\()/$1$key\|/;
13123         }
13124     }
13125     print "\n" if (/$raw_arg_cmd_rx/);
13127     # MRO: replaced $* with /m
13128     while (/$raw_arg_cmd_rx/m) {
13129         local($star);
13130         push (@processed, $`); print "\@";
13131         $after = $';
13132         #JCL(jcl-del) - status of starred raw arg cmds yet unclear
13133         ($cmd, $star) = ($1.$2,$4);
13134         if ($star eq '*') { $star = 'star';}
13135         else { $after = $star.$after; $star = ''; }
13136         $wrapper = "wrap_cmd_$cmd"; $teststar = $wrapper.'star';
13137         if ($star && defined &$teststar) { $wrapper = $teststar; $star = '*'; }
13138         # MRO: make {\bf**} work
13139         elsif($star) { $after = '*'.$after; $star = '' }
13140         print "\nWRAPPED: $cmd as $wrapper" if ($VERBOSITY > 5);
13142         # ensure that the result is separated from following words...
13143         my $padding = ($after =~ /^[a-zA-Z]/s)? ($cmd =~ /\W$/ ? '':' '):'';
13145         if ($raw_arg_cmds{$cmd} && defined &$wrapper) {
13146             $* = 1;
13147             ($wrap, $_) = &$wrapper("\\$cmd$star", $padding . $after);
13148             $* = 0;
13149             # ...but don't leave an unwanted space at the beginning
13150             $_ =~ s/^ //s if($padding && $wrap !~ /\w$/m
13151                 && (length($_) == length($after)+1) );
13152             push (@processed, $wrap);
13153         } elsif ($raw_arg_cmds{$cmd}) {
13154             print STDERR "\n*** $wrapper not defined, cannot wrap \\$cmd";
13155             &write_warnings("\n*** $wrapper not defined, cannot wrap \\$cmd ");
13156             push (@processed, "\\$cmd$padding");
13157             $_ = $after;
13158         } else {
13159             push (@processed, "\\$cmd$padding");
13160             $_ = $after;
13161         }
13162         last unless ($after =~ /\\/);
13163     }
13165     # recombine the pieces
13166     $_ = join('',@processed, $_);
13169 #########################################################################
13171 # To make a table of contents, list of figures and list of tables commands
13172 # create a link to corresponding files which do not yet exist.
13173 # The binding of the file variable in each case acts as a flag
13174 # for creating the actual file at the end, after all the information
13175 # has been gathered.
13177 sub do_cmd_tableofcontents { &do_real_tableofcontents(@_) }
13178 sub do_real_tableofcontents {
13179 #    local($_) = @_;
13180     if ((defined &do_cmd_contentsname)||$new_command{'contentsname'}) {
13181         local($br_id)=++$global{'max_id'};
13182         $TITLE = &translate_environments("$O$br_id$C\\contentsname$O$br_id$C");
13183     } else { $TITLE = $toc_title }
13184     $toc_sec_title = $TITLE;
13185     $tocfile = $CURRENT_FILE;  # sets  $tocfile  this globally
13186     local $toc_head = $section_headings{'tableofcontents'};
13187     if ($toc_style) {
13188         $toc_head .= " CLASS=\"$toc_style\"";
13189         $env_style{"$toc_head.$toc_style"} = " "
13190             unless ($env_style{"$toc_head.$toc_style"});
13191     }
13192     local($closures,$reopens) = &preserve_open_tags();
13193     join('', "<BR>\n", $closures
13194         , &make_section_heading($TITLE, $toc_head), $toc_mark
13195         , $reopens, @_[0]);
13197 sub do_cmd_listoffigures {
13198     local($_) = @_;
13199     local($list_type) = ($SHOW_SECTION_NUMBERS ? 'UL' : 'OL' );
13200     if ((defined &do_cmd_listfigurename)||$new_command{'listfigurename'}) {
13201         local($br_id)=++$global{'max_id'};
13202         $TITLE = &translate_environments("$O$br_id$C\\listfigurename$O$br_id$C");
13203     } else { $TITLE = $lof_title }
13204     $toc_sec_title = $TITLE;
13205     $loffile = $CURRENT_FILE;  # sets  $loffile  this globally
13206     local $lof_head = $section_headings{'listoffigures'};
13207     local($closures,$reopens) = &preserve_open_tags();
13208     join('', "<BR>\n", $closures
13209          , &make_section_heading($TITLE, $lof_head)
13210          , "<$list_type>", $lof_mark, "</$list_type>"
13211          , $reopens, $_);
13213 sub do_cmd_listoftables {
13214     local($_) = @_;
13215     local($list_type) = ($SHOW_SECTION_NUMBERS ? 'UL' : 'OL' );
13216     if ((defined &do_cmd_listtablename)||$new_command{'listtablename'}) {
13217         local($br_id)=++$global{'max_id'};
13218         $TITLE = &translate_environments("$O$br_id$C\\listtablename$O$br_id$C");
13219     } else { $TITLE = $lot_title }
13220     $toc_sec_title = $TITLE;
13221     $lotfile = $CURRENT_FILE;  # sets  $lotfile  this globally
13222     local $lot_head = $section_headings{'listoftables'};
13223     local($closures,$reopens) = &preserve_open_tags();
13224     join('', "<BR>\n", $closures
13225          , &make_section_heading($TITLE, $lot_head)
13226          , "<$list_type>", $lot_mark, "</$list_type>"
13227          , $reopens, $_);
13230 # Indicator for where to put the CHILD_LINKS table.
13231 sub do_cmd_tableofchildlinks {
13232     local($_) = @_;
13233     local($thismark) = $childlinks_mark;
13234     local($option,$dum) = &get_next_optional_argument;
13235     $thismark = &check_childlinks_option($option) if ($option);
13236     local($pre,$post) = &minimize_open_tags("$thismark\#0\#");
13237     join('', "<BR>", $pre, $_);
13240 # leave out the preceding <BR>
13241 sub do_cmd_tableofchildlinksstar {
13242     local($_) = @_;
13243     local($thismark) = $childlinks_mark;
13244     local($option,$dum) = &get_next_optional_argument;
13245     $thismark = &check_childlinks_option($option) if ($option);
13246     local($pre,$post) = &minimize_open_tags("$thismark\#1\#");
13247     join('', $pre, $_);
13250 sub check_childlinks_option {
13251     local($option) = @_;
13252     if ($option =~ /none/i) {
13253         $childlinks_mark = $childlinks_null_mark;
13254         $childlinks_null_mark }
13255     elsif ($option =~ /off/i) { $childlinks_null_mark }
13256     elsif ($option =~ /all/i) {
13257         $childlinks_mark = $childlinks_on_mark;
13258         $childlinks_on_mark }
13259     elsif ($option =~ /on/i) { $childlinks_on_mark }
13262 sub remove_child_marks {
13263     # Modifies $_
13264     s/($childlinks_on_mark|$childlinks_null_mark)\#\d\#//go;
13268 sub do_cmd_htmlinfo {
13269     local($_) = @_;
13270     local($option,$dum) = &get_next_optional_argument;
13271     if ($option =~ /^(off|none)/i) { $INFO = 0; return ($_) }
13272     local($pre,$post) = &minimize_open_tags($info_title_mark.$info_page_mark);
13273     join('', "<BR>", $pre, $_);
13275 sub do_cmd_htmlinfostar {
13276     local($_) = @_;
13277     local($option,$dum) = &get_next_optional_argument;
13278     if ($option =~ /^(off|none)/i) { $INFO = 0; return ($_) }
13279     local($pre,$post) = &minimize_open_tags($info_page_mark);
13280     join('', $pre, $_);
13283 # $idx_mark will be replaced with the real index at the end
13284 sub do_cmd_textohtmlindex {
13285     local($_) = @_;
13286     if ((defined &do_cmd_indexname )||$new_command{'indexname'}) {
13287         local($br_id)=++$global{'max_id'};
13288         $TITLE = &translate_environments("$O$br_id$C\\indexname$O$br_id$C");
13289     } else { $TITLE = $idx_title }
13290     $toc_sec_title = $TITLE;
13291     $idxfile = $CURRENT_FILE;
13292     if (%index_labels) { &make_index_labels(); }
13293     if (($SHORT_INDEX) && (%index_segment)) { &make_preindex(); }
13294     else { $preindex = ''; }
13295     local $idx_head = $section_headings{'textohtmlindex'};
13296     local($heading) = join(''
13297         , &make_section_heading($TITLE, $idx_head)
13298         , $idx_mark );
13299     local($pre,$post) = &minimize_open_tags($heading);
13300     join('',"<BR>\n" , $pre, $_);
13303 #RRM: added 17 May 1996
13304 # allows labels within the printable key of index-entries,
13305 # when using  makeidx.perl
13306 sub make_index_labels {
13307     local($key, @keys);
13308     @keys = keys %index_labels;
13309     foreach $key (@keys) {
13310         if (($ref_files{$key}) && !($ref_files{$key} eq "$idxfile")) {
13311             local($tmp) = $ref_files{$key};
13312             &write_warnings("\nmultiple label $key , target in $idxfile masks $tmp ");
13313         }
13314         $ref_files{$key} .= "$idxfile";
13315     }
13317 #RRM: added 17 May 1996
13318 # constructs a legend for the SHORT_INDEX, with segments
13319 # when using  makeidx.perl
13320 sub make_preindex { &make_real_preindex }
13321 sub make_real_preindex {
13322     local($key, @keys, $head, $body);
13323     $head = "<HR>\n<H4>Legend:</H4>\n<DL COMPACT>";
13324     @keys = keys %index_segment;
13325     foreach $key (@keys) {
13326         local($tmp) = "segment$key";
13327         $tmp = $ref_files{$tmp};
13328         $body .= "\n<DT>$key<DD>".&make_named_href('',$tmp,$index_segment{$key});
13329 #       $body .= "\n<DT>$key<DD>".&make_named_href('',
13330 #               $tmp."\#CHILD\_LINKS",$index_segment{$key})
13331 #                    unless ($CHILD_STAR);
13332     }
13333     $preindex = join('', $head, $body, "\n</DL>") if ($body);
13336 sub do_cmd_printindex { &do_real_printindex(@_); }
13337 sub do_real_printindex {
13338     local($_) = @_;
13339     local($which) = &get_next_optional_argument;
13340     $idx_name = $index_names{$which}
13341         if ($which && $index_names{$which});
13342     @_;
13345 sub do_cmd_newindex {
13346     local($_) = @_;
13347     local($dum,$key,$title);
13348     $key = &missing_braces unless (
13349         (s/$next_pair_pr_rx/$key=$2;''/eo)
13350         ||(s/$next_pair_rx/$key=$2;''/eo));
13351     $dum = &missing_braces unless (
13352         (s/$next_pair_pr_rx/$dum=$2;''/eo)
13353         ||(s/$next_pair_rx/$dum=$2;''/eo));
13354     $dum = &missing_braces unless (
13355         (s/$next_pair_pr_rx/$dum=$2;''/eo)
13356         ||(s/$next_pair_rx/$dum=$2;''/eo));
13357     $title = &missing_braces unless (
13358         (s/$next_pair_pr_rx/$title=$2;''/eo)
13359         ||(s/$next_pair_rx/$title=$2;''/eo));
13360     $index_names{$key} = $title if ($key && $title);
13361     @_;
13364 # FOOTNOTES , also within Mini-page environments
13365 # allow easy way to override and inherit; e.g. for frames 
13367 sub do_cmd_footnotestar { &do_real_cmd_footnote(@_) }
13368 sub do_cmd_footnote { &do_real_cmd_footnote(@_) }
13369 sub do_real_cmd_footnote {
13370     local($_) = @_;
13371     local($cnt,$marker,$smark,$emark)=('', $footnote_mark);
13372     local($mark,$dum) = &get_next_optional_argument;
13373     local($anchor_name);
13375     $footfile = "${PREFIX}$FOOT_FILENAME$EXTN"
13376         unless ($footfile||$MINIPAGE||$NO_FOOTNODE);
13378     if ($mark) { 
13379         $cnt = $mark;
13380         if ($MINIPAGE) { $global{'mpfootnote'} = $cnt }
13381         else { $global{'footnote'} = $cnt }
13382     } else {
13383         $cnt = (($MINIPAGE)? ++$global{'mpfootnote'} : ++$global{'footnote'});
13384     }
13385     local($br_id, $footnote)=(++$global{'max_id'},'');
13386     $footnote = &missing_braces unless (
13387         (s/$next_pair_pr_rx/${br_id}=$1; $footnote=$2;''/eo)
13388         ||(s/$next_pair_rx/${br_id}=$1; $footnote=$2;''/eo));
13389     $br_id = "mp".$br_id if ($MINIPAGE);
13390     $marker = &get_footnote_mark($MINIPAGE);
13391     local($last_word) = &get_last_word();
13392     local($href) = &make_href("$footfile#foot$br_id",$marker);
13393     if ($href =~ /NAME="([^"]*)"/) { $anchor_name=$1 }
13394     $last_word .= $marker unless ($anchor_name);
13395     &process_footnote($footnote,$cnt,$br_id,$last_word,$mark
13396               ,($MINIPAGE? $marker : '')
13397               ,($MINIPAGE? '' : "$marker:$anchor_name") );
13398     # this may not work if there is a <BASE> tag and !($file) !!! #
13399 #   join('',&make_href("$file#foot$br_id",$marker),$_);
13400     $href . $_ 
13403 sub process_image_footnote {
13404     # MRO: modified to use $_[0]
13405     # local(*math) = @_;
13406     local($in_image, $keep, $pre, $this_anchor, $out, $foot_counters_recorded, @foot_anchors) = (1,'','');
13407     local($image_contents) = $_[0];
13408     $image_contents =~ s/\\(begin|end)(($O|$OP)\d+($C|$CP))tex2html_\w+\2//go;
13409     $image_contents =~ s!(\\footnote(mark\b\s*(\[[^\]]*\])?|\s*(\[[^\]]*\])?\s*(($O|$OP)\d+($C|$CP))(.*)\5))!
13410         $keep = $`; $out = '\footnotemark '.$3.$4;
13411         #MRO: $*=1; local($saveRS) = $/; $/='';
13412         if ($8) {
13413             $this_anchor = &do_cmd_footnote($2);
13414         } else {
13415             $this_anchor = &do_cmd_footnotemark($3);
13416         }
13417         #MRO: $*=0; $/ = $saveRS;
13418         $foot_counters_recorded = 1;
13419         push(@foot_anchors, $this_anchor);
13420         $out!oesg;
13421     $_[0] = $image_contents;
13422     @foot_anchors;
13425 sub do_cmd_thanks { &do_cmd_footnote(@_); }
13427 sub get_footnote_mark {
13428     local($mini) = @_;
13429     return($footnote_mark) if ($HTML_VERSION < 3.0 );
13430     local($cmd,$tmp,@tmp,$marker);
13431     $cmd = "the". (($mini)? 'mp' : '') . "footnote";
13432     if ($new_command{$cmd}) {
13433         $tmp = "do_cmd_$cmd";
13434         @tmp = split (':!:', $new_command{$cmd});
13435         pop @tmp; $tmp = pop @tmp;
13436         if ($tmp =~ /$O/) {
13437 ###         local($_) = &translate_commands($tmp);
13438             $marker = &translate_commands(&translate_environments($tmp));
13439             &make_unique($marker);
13440 ###         $marker = $_;
13441         } else { $marker = &translate_commands(&translate_environments($tmp)); }
13442     } elsif ($mini) {
13443         $marker = &translate_commands('\thempfootnote');
13444     } elsif ((defined &do_cmd_thefootnote)||$new_command{'thefootnote'}) { 
13445         local($br_id)=++$global{'max_id'};
13446         $marker = &translate_environments("$O$br_id$C\\thefootnote$O$br_id$C");
13447     } else { $marker = $footnote_mark; }
13448     join('','<SUP>',$marker,'</SUP>');
13451 sub make_numbered_footnotes {
13452     eval "sub do_cmd_thefootnote {\&numbered_footnotes}" }
13453 sub numbered_footnotes { &do_cmd_arabic('<<0>>footnote<<0>>');}
13455 # default numbering style for minipage notes
13456 sub do_cmd_thempfootnote { &do_cmd_arabic('<<0>>mpfootnote<<0>>'); }
13458 sub do_cmd_footnotemark { &do_real_cmd_footnotemark(@_) }
13459 sub do_real_cmd_footnotemark {
13460     local($_) = @_;
13461     local($br_id, $footnote,$marker,$mpnote,$tmp,$smark,$emark);
13462     # Don't use ()'s for the optional argument!
13463     local($mark,$dum) = &get_next_optional_argument;
13464     local ($cnt,$text_known) = ('','');
13465     if ($mark) {
13466         $cnt = (($mark =~ /\\/)? &translate_commands($mark) : $mark);
13467         if (($MINIPAGE)&&($mpfootnotes{$cnt})) {
13468             $mpnote = 1;
13469             $br_id  = $mpfootnotes{$cnt};
13470             $text_known = 1;
13471         } else {
13472             $global{'footnote'} = $cnt;
13473             local($tmp) = $footnotes{$cnt};
13474             if ($tmp) {
13475                 $br_id  = $tmp;
13476                 $text_known = 1;
13477             } else { $footnotes{$cnt} = $br_id }
13478         }
13479     } else {
13480         $cnt = ++$global{'footnote'};
13481         $text_known = 1 if ($footnotes{$cnt});
13482     }
13483     if ($text_known) {
13484         $br_id = ($MINIPAGE ? $mpfootnotes{$cnt} : $footnotes{$cnt});
13485         $marker = &get_footnote_mark($mpnote);
13486         return (join('', &make_href("$footfile#foot$br_id",$marker),$_));
13487     }
13488     
13489     local($last_word) = &get_last_word() unless ($mpnote);
13491     # Try to find a  \footnotetext  further on.
13492     do {
13493         if (s/\\footnotetext\s*\[\s*$cnt\s*]*\]\s*$any_next_pair_pr_rx//o) {
13494             ($br_id, $footnote) = ($2, $3);  
13495         } else { 
13496             $br_id = "fnm$cnt";
13497             $footnotes{$cnt} = $br_id;
13498         }
13499     } unless ($br_id);
13501     $marker = &get_footnote_mark($mpnote);
13502     $last_word .= $marker unless ($marker =~ /$footnote_mark/ );
13503     if ($footnote) {
13504         # found a  \footnotetext  further on
13505         &process_footnote($footnote,$cnt,$br_id,$last_word,$mark);
13506         join('',&make_named_href("foot$br_id","$footfile#$br_id",$marker),$_);
13507     } elsif ($br_id =~ /fnm/) {
13508         # no  \footnotetext  yet, so make the entry in $footnotes
13509         &process_footnote('',$cnt,$br_id,$last_word,$mark);
13510         # this may not work if there is a <BASE> tag and !($footfile) !!! #
13511         join('',&make_named_href("foot$br_id","$footfile#$br_id",$marker),$_);
13512     } elsif ($br_id) {
13513         # \footnotetext  already processed
13514         if ($mpnote) {
13515             $mpfootnotes =~ s/(=\"$br_id\">...)(<\/A>)/$1$last_word$3/
13516                 if ($last_word);
13517             # this may not work if there is a <BASE> tag !!! #
13518             join('',&make_named_href("foot$br_id","#$br_id",$marker),$_);
13519         } else {
13520             $footnotes =~ s/(=\"$br_id\">...)(<\/A>)/$1$last_word$3/;
13521             # this may not work if there is a <BASE> tag and !($footfile) !!! #
13522             join(''
13523                 ,&make_named_href("foot$br_id","$footfile#$br_id",$marker),$_);
13524         }
13525     } else { 
13526         print "\nCannot find \\footnotetext for \\footnotemark $cnt";
13527         # this may not work if there is a <BASE> tag and !($footfile) !!! #
13528         join('',&make_named_href("foot$br_id","$footfile",$marker),$_);
13529     }
13532 # Under normal circumstances this is never executed. Any commands \footnotetext
13533 # should have been processed when the corresponding \footnotemark was
13534 # encountered. It is possible however that when processing pieces of text
13535 # out of context (e.g. \footnotemarks in figure and table captions)
13536 # the pair of commands gets separated. Until this is fixed properly,
13537 # this command just puts the footnote in the footnote file in the hope
13538 # that its context will be obvious ....
13539 sub do_cmd_footnotetext {
13540     local($_) = @_;
13541     local($mark,$dum) = &get_next_optional_argument;
13542     local($br_id, $footnote, $prev, $key)=(1,'','','');
13543     $footnote = &missing_braces unless (
13544         (s/$next_pair_pr_rx/($br_id,$footnote)=($1,$2);''/eo)
13545         ||(s/$next_pair_rx/($br_id,$footnote)=($1,$2);''/eo));
13547     $mark = $global{'footnote'} unless $mark;
13548     $prev = $footnotes{$mark};
13549     if ($prev) {
13550         $prev = ($MINIPAGE ? 'mp' : '') . $prev;
13551         # first prepare the footnote-text
13552         $footnote = &translate_environments("${OP}$br_id$CP$footnote${OP}$br_id$CP")
13553             if ($footnote);
13554         $footnote = &translate_commands($footnote) if ($footnote =~ /\\/);
13556         # now merge it onto the Footnotes page
13557         $footnotes =~ s/(=\"$prev\">\.\.\.)(.*<\/A>)(<\/DT>\n<DD>)\n/
13558                 $1.'<html_this_mark>'.$3.$footnote/e;
13559         local($this_mark) = $2;
13560         $this_mark =~ s|(<SUP>)(?:<#\d+#>)?(\d+)(?:<#\d+#>)?(<\/SUP>)(<\/A>)$|
13561                 "$4<A\n HREF=\"$CURRENT_FILE\#foot$prev\">$1$2$3$4"|e;
13562         $footnotes =~ s/<html_this_mark>/$this_mark/;
13563     } else {
13564         &process_footnote($footnote,$mark,$br_id,'','') if $footnote;
13565     }
13566     $_;
13570 sub process_footnote {
13571     # Uses $before
13572     # Sets $footfile defined in translate
13573     # Modifies $footnotes defined in translate
13574     local($footnote, $cnt, $br_id, $last_word, $mark, $mini, $same_page) = @_;
13575     local($target) = $target;
13577     # first prepare the footnote-text
13578     local($br_idd, $fcnt); $br_id =~ /\D*(\d+)/; $br_idd = $1;
13579     $footnote = &translate_environments("$O$br_idd$C$footnote$O$br_idd$C")
13580         if ($footnote);
13581     $footnote = &translate_commands($footnote) if ($footnote =~ /\\/);
13583     local($space,$sfoot_style,$efoot_style) = ("\n",'','');
13584     if ((!$NO_FOOTNODE)&&(!$mini)&&(!$target)) {
13585         $footfile = "${PREFIX}$FOOT_FILENAME$EXTN";
13586         $space = ".\n" x 30;
13587         $space = "\n<PRE>$space</PRE>";
13588     } elsif ($target) {
13589         $target = $frame_body_name
13590             if (($frame_body_name)&&($target eq $frame_foot_name));
13591         $sfoot_style = '<SMALL>';
13592         $efoot_style = '</SMALL>';
13593     }
13595     if ($mark) {
13596         if ($mini) {
13597             $cnt = $mpfootnotes{$mark};
13598             if ($in_image) {
13599                 $fcnt = $global{'mpfootnote'}; --$fcnt if $fcnt;
13600                 $latex_body .= '\setcounter{mpfootnote}{'.($fcnt||"0")."}\n"
13601                     unless ($foot_counters_recorded);
13602             }
13603         } else {
13604             $cnt = $footnotes{$mark};
13605             if ($in_image) {
13606                 $fcnt = $global{'footnote'}; --$fcnt if $fcnt;
13607                 $latex_body .= '\setcounter{footnote}{'.($fcnt||"0")."}\n"
13608                     unless ($foot_counters_recorded);
13609             }
13610         }
13611         if ($cnt) { 
13612             &write_warnings("\nredefined target for footnote $mark" )
13613                 unless ( $cnt eq $br_id )
13614         }
13615         if ($mini) { $mpfootnotes{$mark} = "$br_id" }
13616         elsif ($br_id =~ /fnm\d+/) {
13617             $mark = "$footnotes{$cnt}";
13618             $footnotes{$cnt} = "$br_id";
13619 #           $footnotes .= "\n<DT>$sfoot_style<A NAME=\"foot$br_id\">..."
13620             $footnotes .= "\n<DT>$sfoot_style<A NAME=\"$br_id\">..."
13621                 . $last_word . "</A>$efoot_style</DT>\n<DD>\n"
13622                 . $space . "\n</DD>";
13623             return;
13624         } else { $footnotes{$mark} = "$br_id" }
13625     } else {
13626         if ($mini) {
13627             $mpfootnotes{$cnt} = "$br_id";
13628             if ($in_image) {
13629                 $fcnt = $global{'mpfootnote'}; --$fcnt if $fcnt;
13630                 $latex_body .= '\setcounter{mpfootnote}{'.($fcnt||"0")."}\n"
13631                     unless ($foot_counters_recorded);
13632             }
13633         } else {
13634             $footnotes{$cnt} = "$br_id";
13635             if ($in_image) {
13636                 $fcnt = $global{'footnote'}; --$fcnt if $fcnt;
13637                 $latex_body .= '\setcounter{footnote}{'.($fcnt||"0")."}\n"
13638                     unless ($foot_counters_recorded);
13639             }
13640         }
13641     }
13643     # catch a \footnotemark *after* the \footnotetext
13644     if ((!$footnote)&&($last_word)&&(!$mini)) {
13645 #       $footnotes .= "\n<DT>$sfoot_style<A NAME=\"foot$br_id\">..."
13646         $footnotes .= "\n<DT>$sfoot_style<A NAME=\"$br_id\">..."
13647             . $last_word
13648             . "</A>$efoot_style</DT>\n<DD>\n" . $space . "\n</DD>";
13650     } elsif ($mini) {
13651         if ($HTML_VERSION < 3.0) { $mini .= "." }
13652         $mpfootnotes .= "\n<DD>$sfoot_style<A NAME=\"foot$br_id\">$mini</A> " .
13653             $footnote . $efoot_style . "\n</DD>\n";
13654     } elsif ($same_page) {
13655         local($link,$text);
13656         $same_page =~ s/:/$text=$`;$link=$';''/e;
13657         $same_page = &make_named_href("","$CURRENT_FILE\#$link",$text) if($link);
13658         $footnotes .= "\n<DT>$sfoot_style<A NAME=\"foot$br_id\">...$last_word</A>"
13659             . $same_page . $efoot_style . "</DT>\n<DD>" . $sfoot_style
13660             . $footnote . $efoot_style . "\n". $space . "\n</DD>";
13661     } else {
13662         $footnotes .= "\n<DT>$sfoot_style<A NAME=\"foot$br_id\">...$last_word</A>"
13663                 . $efoot_style . "</DT>\n<DD>" . $sfoot_style
13664                 . $footnote . "$efoot_style\n" . $space . "\n</DD>";
13665     }
13669 sub do_cmd_appendix {
13670     $latex_body .= "\\appendix\n";
13671     if ($section_commands{$outermost_level} == 3) {
13672         $global{'section'} = 0;
13673         &reset_dependents('section');
13674         eval "sub do_cmd_thesection{ &do_cmd_the_appendix(3,\@_) }";
13675     } else {
13676         $global{'chapter'} = 0;
13677         &reset_dependents('chapter');
13678         eval "sub do_cmd_thechapter{ &do_cmd_the_appendix(2,\@_) }";
13679     }
13680     $_[0];
13683 sub do_cmd_the_appendix {
13684     local($val,$level) = (0,$_[0]);
13685     if ($level == 3) { $val=$global{'section'} }
13686     elsif ($level == 2) { $val=$global{'chapter'} }
13687     join('', &fAlph($val), '.', $_[1]);
13690 sub do_cmd_appendixname { $app_title . $_[0] }
13691 sub do_cmd_abstractname { $abs_title . $_[0] }
13692 sub do_cmd_keywordsname { $key_title . $_[0] }
13693 sub do_cmd_subjclassname { $sbj_title . $_[0] }
13694 sub do_cmd_indexname { $idx_title . $_[0] }
13695 sub do_cmd_contentsname { $toc_title . $_[0] }
13696 sub do_cmd_datename { $date_name . $_[0] }
13697 sub do_cmd_refname { $ref_title . $_[0] }
13698 sub do_cmd_bibname { $bib_title . $_[0] }
13699 sub do_cmd_figurename { $fig_name . $_[0] }
13700 sub do_cmd_listfigurename { $lof_title . $_[0] }
13701 sub do_cmd_tablename { $tab_name . $_[0] }
13702 sub do_cmd_listtablename { $lot_title . $_[0] }
13703 sub do_cmd_partname { $part_name . $_[0] }
13704 sub do_cmd_chaptername { $chapter_name . $_[0] }
13705 sub do_cmd_sectionname { $section_name . $_[0] }
13706 sub do_cmd_subsectionname { $subsection_name . $_[0] }
13707 sub do_cmd_subsubsectionname { $subsubsection_name . $_[0] }
13708 sub do_cmd_paragraphname { $paragraph_name . $_[0] }
13709 sub do_cmd_thmname { $thm_title . $_[0] }
13710 sub do_cmd_proofname { $prf_name . $_[0] }
13711 sub do_cmd_footnotename { $foot_title . $_[0] }
13712 sub do_cmd_childlinksname { '<STRONG>'.$child_name.'</STRONG>'. $_[0] }
13713 sub do_cmd_infopagename { $info_title . $_[0] }
13716 sub do_cmd_ref {
13717     local($_) = @_;
13718     &process_ref($cross_ref_mark,$cross_ref_mark);
13721 sub do_cmd_eqref {
13722     local($_) = @_;
13723     join('','(',&process_ref($cross_ref_mark,$cross_ref_mark,'',')'));
13726 sub do_cmd_pageref {
13727     local($_) = @_;
13728     &process_ref($cross_ref_mark,$cross_ref_visible_mark);
13731 # This is used by external style files ...
13732 sub process_ref {
13733     local($ref_mark, $visible_mark, $use_label, $after_label) = @_;
13734     $use_label = &balance_inner_tags($use_label) 
13735         if $use_label =~ (/<\/([A-Z]+)>($math_verbatim_rx.*)<\1>/);
13736     $use_label = &translate_environments($use_label);
13737     $use_label = &simplify(&translate_commands($use_label))
13738         if ($use_label =~ /\\/ );
13739     local($label,$id);
13740     local($pretag) = &get_next_optional_argument;
13741     $pretag = &translate_commands($pretag) if ($pretag =~ /\\/);    
13742     $label = &missing_braces unless (
13743         (s/$next_pair_pr_rx/($id, $label) = ($1, $2);''/eo)
13744         ||(s/$next_pair_rx/($id, $label) = ($1, $2);''/eo));
13745     if ($label) {
13746         $label =~ s/<[^>]*>//go ; #RRM: Remove any HTML tags
13747         $label =~ s/$label_rx/_/g;      # replace non alphanumeric characters
13749         $symbolic_labels{"$pretag$label$id"} = $use_label if ($use_label);
13750         if (($symbolic_labels{$pretag.$label})&&!($use_label)) {
13751             $use_label = $symbolic_labels{$pretag.$label}
13752         }
13753 #       if (!($use_label eq $label)) {
13754 #           $symbolic_labels{"$label$id"} = $use_label;
13755 #       };
13756         # if $use_label is empty then $label is used as the cross_ref_mark
13757         # elseif $use_label is a string then $use_label is used
13758         # else the usual mark will be used
13759         $use_label = ( (!$use_label && $label) || $use_label);
13761         print "\nLINK: $ref_mark\#$label\#$id  :$use_label:" if ($VERBOSITY > 3);
13762         # The quotes around the HREF are inserted later
13763         join('',"<A HREF=$ref_mark#$label#$id>$visible_mark<\/A>",$after_label, $_);
13764     }
13765     else {
13766         print "Cannot find label argument after <$last_word>\n" if $last_word;
13767         $after_label . $_;
13768     }
13771 #RRM:  This removes unbalanced tags, due to closures for math inside 
13772 #      the label-text for an <A> anchor.
13773 sub balance_inner_tags {
13774     local($text) = @_;
13775     return($text) unless ($text =~ /<\/([A-Z]+)>(\s*$math_verbatim_rx.*)(<\1( [^>]*)?>)/);
13776     local($beforeT,$afterT,$tag,$math_verb,$stag) = ($`,$',$1,$2,$3);
13777     if (!($beforeT =~ /<$tag>/)) { 
13778         $text = join('', $beforeT, $math_verb, $afterT);
13779         return (&balance_inner_tags($text));
13780     }
13781     local(@pieces) = split (/<$tag>/, $beforeT );
13782     $beforeT = shift (@pieces);
13783     local($cnt,$this) = (0,'');
13784     while (@pieces) {
13785         $this = shift @pieces;
13786         $cnt++;
13787         $beforeT .= "<$tag>".$this;
13788         $cnt = $cnt - ($this =~ /<\/$tag>/g);
13789     }
13790     if ($cnt) { 
13791         $beforeT .= "<\/$tag>" . $math_verb . $stag;
13792         $text = $beforeT . $afterT;
13793     } else {
13794         $beforeT .= $math_verb;
13795         $text = join('', $beforeT, $math_verb, $afterT);
13796         return (&balance_inner_tags($text));
13797     }
13798     $text;
13801 # Uses $CURRENT_FILE defined in translate
13802 sub do_cmd_label {
13803     local($_) = @_;
13804     local($label);
13805     $label = &missing_braces unless (
13806         (s/$next_pair_pr_rx\n?/$label = $2;''/eo)
13807         ||(s/$next_pair_rx\n?/$label = $2;''/eo));
13808     &anchor_label($label,$CURRENT_FILE,$_);
13811 # This subroutine is also used to process labels in undefined environments
13812 sub anchor_label { &real_anchor_label(@_) }
13813 sub real_anchor_label {
13814     # Modifies entries in %ref_files defined in translate
13815     local($label,$filename,$context) = @_;
13816     $label =~ s/<[^>]*>//go;    #RRM: Remove any HTML tags
13817     $label =~ s/$label_rx/_/g;  # replace non alphanumeric characters
13818     # Associate the label with the current file
13819     if ($ref_files{$label} ne $filename) {
13820         $ref_files{$label} = $filename;
13821         $noresave{$label} = 0; $changed = 1; }
13822     print "<LABEL: $label>" if ($VERBOSITY > 3);
13823     join('',"<A NAME=\"$label\">$anchor_mark</A>",$context);
13826 sub do_cmd_cite {
13827     local($_) = @_;
13828     &process_cite('','');
13832 # This just creates a link from a label (yet to be determined) to the
13833 # cite_key in the citation file.
13834 sub process_cite { &process_real_cite(@_) }
13835 sub process_real_cite {
13836     local($mode,$text) = @_;
13837     my $has_text = (($text)? 1 : 0);
13838 #    local($target) = 'contents';print "\nCITE:$text";
13839     # process the text from \htmlcite or \hypercite
13840     if ($has_text) {
13841         $text = &balance_inner_tags($text) 
13842             if $use_label =~ (/<\/([A-Z]+)>($math_verbatim_rx.*)<\1>/);
13843         $text = &translate_environments($text);
13844         $text = &simplify(&translate_commands($text))
13845             if ($use_label =~ /\\/ );
13846     }
13848     my $label, $cite_key, $pretag, @cite_keys;
13849     local($optional_text,$dummy) =  &get_next_optional_argument;
13850     if ($mode =~ /external/) {
13851 #       $target = '';
13852         $pretag = $optional_text; $optional_text = '';
13853         $pretag = &translate_commands($pretag) if ($pretag =~ /\\/);
13854     } else {
13855         $optional_text = ", $optional_text" if $optional_text;
13856     }
13857     s/^\s*\\space//o;           # Hack - \space is inserted in .aux
13858     s/$next_pair_pr_rx//o||s/$next_pair_rx//o;
13859     if (!($cite_key = $2)) {
13860         print "\n *** Cannot find citation argument\n";
13861         return ($_);
13862     }
13863     @cite_keys = (split(/,/,$cite_key));
13864     my ($citations, $join) = ('',',');
13865     $join  = '' if ($text);
13866     foreach $cite_key (@cite_keys) {
13867         $cite_key =~ s/(^\s+|\s+$)//g;
13868         $cite_key =~ s/(^\s+|\s+$)//g;
13869     # RRM:  if the URL and printable-key are known already, then use them...
13870         $cite_key =~ s/$label_rx/_/g;
13871         $label = $cite_key;
13872         if ($mode eq "nocite") {
13873             # nothing more to do, no citations
13874         } elsif ( ($SEGMENT) && ($cite_info{$cite_key})
13875                 && ($ref_files{"cite_$cite_key"}) ) {
13876             $join  = "," unless ($text);
13877             $text = $cite_info{$cite_key} unless ($text);
13878             $citations .= join('', $join
13879                 , &make_named_href($label,$ref_files{'cite_'."$cite_key"},$text));
13880         } elsif (($mode eq "external")&&($external_labels{$pretag."cite_$cite_key"})) {
13881             $join  = "," unless ($text);
13882             $text = $cross_ref_visible_mark unless ($text);
13883             $citations .= join('', $join
13884                 , &make_named_href($label
13885                     , $external_labels{$pretag.'cite_'."$cite_key"}."\#$label"
13886                     , $text)
13887                 );
13888         } elsif ($mode eq 'external') {
13889             $join  = "," unless ($text);
13890             &write_warnings("\nExternal reference missing for citation: $pretag$cite_key");
13891             $citations .= "$text$join#!$pretag$cite_key!#";
13892         } else {
13893             $join  = "," unless ($text);
13894             #Replace the key...
13895             $citations .= "$join#$cite_key#$cite_mark#$bbl_nr#$text#$cite_mark#";
13896         }
13897         $text = '';
13898     }
13899     $citations =~ s/^\s*,\s*//;
13900     if ($has_text) { join('', $citations,  $optional_text, $_) }
13901     else { join('', "[", $citations,  $optional_text, "]", $_) }
13904 sub do_cmd_index { &do_real_index(@_) }
13905 sub do_real_index {
13906     local($_) = @_;
13907     local($br_id, $str);
13908     local($idx_option) = &get_next_optional_argument;
13909     $str = &missing_braces unless (
13910         (s/$next_pair_pr_rx/($br_id, $str) = ($1, $2);''/eo)
13911         ||(s/$next_pair_rx/($br_id, $str) = ($1, $2);''/eo));
13912     join('',&make_index_entry($br_id,$str),$_);
13914 sub do_cmd_indexstar { &do_cmd_index(@_) }
13916 # RRM: \bibcite supplies info via the .aux file; necessary with segmented docs.
13917 sub do_cmd_bibcite {
13918     local($_) = @_;
13919     local($br_id, $cite_key,$print_key);
13920     $cite_key = &missing_braces unless (
13921         (s/$next_pair_pr_rx/($br_id, $cite_key) = ($1, $2);''/eo)
13922         ||(s/$next_pair_rx/($br_id, $cite_key) = ($1, $2);''/eo));
13923     $print_key = &missing_braces unless (
13924         (s/$next_pair_pr_rx/($br_id, $print_key) = ($1, $2);''/eo)
13925         ||(s/$next_pair_rx/($br_id, $print_key) = ($1, $2);''/eo));
13926     $cite_key =~ s/$label_rx/_/g;
13927     $cite_info{$cite_key} = $print_key;
13928     $_;
13931 # This command will only be encountered inside a thebibliography environment.
13932 sub do_cmd_bibitem { &do_real_bibitem($CURRENT_FILE, @_) }
13933 sub do_real_bibitem {
13934     local($thisfile, $_) = @_;
13935     # The square brackets may contain the label to be printed
13936     local($label, $dummy) = &get_next_optional_argument;
13937     # Support for the "named" bibliography style
13938     if ($label) {
13939         $label =~ s/\\protect//g;
13940         $label = &translate_commands($label) if ($label =~ /\\/);
13941     }
13942     local($cite_key);
13943     $cite_key = &missing_braces unless (
13944         ( s/$next_pair_pr_rx/$cite_key=$2;''/e )
13945         ||( s/$next_pair_rx/$cite_key=$2;''/e ));
13947     $cite_key =~ s/$label_rx/_/g;
13948     $label = $cite_info{$cite_key} unless $label; # read from .aux file
13949     $label = ++$bibitem_counter unless $label; # Numerical labels
13951     if ($cite_key) {
13952         # Associate the cite_key with the printed label.
13953         # The printed label will be substituted back into the document later.
13954         $cite_info{$cite_key} = &translate_commands($label);
13955         if (!($ref_files{'cite_'."$cite_key"} eq $thisfile)) {
13956             $ref_files{'cite_'."$cite_key"} = $thisfile;
13957             $changed = 1; }
13959         #RRM: apply any special styles, as defined below
13960         $label = &bibitem_style($label) if (defined &bibitem_style);
13961         # Create an anchor around the citation
13962         join('',"<P></P><DT><A NAME=\"$cite_key\">$label</A>\n<DD>", $_);
13964     } else {
13965         print "Cannot find bibitem labels: $label\n";
13967         #RRM: apply any special styles, as defined below
13968         $label = &bibitem_style($label) if (defined &bibitem_style);
13969         join('',"<P></P><DT>$label\n<DD>", $_); # AFEB added this line
13970     }
13973 #RRM: override this with a personal style, defined in  .latex2html-init
13974 #sub bibitem_style { join('','<STRONG>',$_[0],'</STRONG>') }
13975 sub bibitem_style {
13976     return ($_[0]) unless $BIBITEM_STYLE;
13977     local($text) = join(''
13978         ,"${O}0$C",$BIBITEM_STYLE,"${O}1$C", @_, "${O}1$C","${O}0$C");
13979     $text = &translate_environments($text);
13980     &translate_commands($text);
13983 sub do_cmd_newblock {
13984     "<BR>".$_[0]
13987 # This just reads in the $FILE.bbl file if it is available and appends
13988 # it to the items that are still to be processed.
13989 # The $FILE.bbl should contain a thebibliography environment which will
13990 # cause its contents to be processed later in the appropriate way.
13991 # (Note that it might be possible for both the \bibliography command and
13992 # the thebibliography environment to be present as the former may have been
13993 # added by the translator as a sectioning command. In this case (both present)
13994 # the $citefile would have already been set by the thebibliography environment)
13996 sub do_cmd_bibliography { &do_real_bibliography($CURRENT_FILE, @_) }
13997 sub do_real_bibliography {
13998     local($thisfile, $after) = @_;
13999     if ((defined &do_cmd_bibname)||$new_command{'bibname'}) {
14000         local($br_id)=++$global{'max_id'};
14001         $TITLE = &translate_environments("$O$br_id$C\\bibname$O$br_id$C");
14002     } else { $TITLE = $bib_title }
14003     $toc_sec_title = $TITLE;
14004     return($_[0]) if ($making_name);
14005     local($bibfile);
14006     $bibfile = &missing_braces unless (
14007         ($after =~ s/$next_pair_rx/$bibfile=$2;''/eo)||
14008         ($after =~ s/$next_pair_rx_rx/$bibfile=$2;''/eo));
14010     do {
14011         unless ($citefile) {
14012             $citefile = $thisfile;
14013             if (&process_ext_file("bbl")) { # *** BINDS $_ as a side effect ***
14014                 $after = join('',$_,$after);}
14015             else {
14016                 print "\nCannot open $FILE.bbl $!\n";
14017                 &write_warnings("\nThe bibliography file was not found.");
14018                 $after = join('',"\n<H2>No References!</H2>", $after);
14019             }
14020         }
14021     print "\n";
14022     } if $bibfile;
14023     $after;
14026 # allow for customised info-pages, for different languages
14027 sub do_cmd_textohtmlinfopage {
14028     local($_) = @_;
14029     local($linfo) = $TITLES_LANGUAGE . '_infopage';
14030     if (defined &$linfo) { eval "&$linfo"; }
14031     else { &default_textohtmlinfopage }
14034 sub default_textohtmlinfopage {
14035     local($_) = @_;
14036     local($argv) = $argv;
14037     if (-f "../$argv") { $argv = &make_href ("../$argv", $argv, ); }
14038     $_ = ($INFO && $INFO =~ /^\d+$/
14039       ? join('', $close_all
14040         , "<STRONG>$t_title</STRONG><P>\nThis document was generated using the\n"
14041         , "<A HREF=\"$TEX2HTMLADDRESS\"><STRONG>LaTeX</STRONG>2<tt>HTML</tt></A>"
14042         , " translator Version $TEX2HTMLVERSION\n"
14043         , "<P>Copyright &#169; 1993, 1994, 1995, 1996,\n"
14044         , "<A HREF=\"$AUTHORADDRESS\">Nikos Drakos</A>, \n"
14045         , "Computer Based Learning Unit, University of Leeds.\n"
14046         , "<BR>Copyright &#169; 1997, 1998, 1999,\n"
14047         , "<A HREF=\"$AUTHORADDRESS2\">Ross Moore</A>, \n"
14048         , "Mathematics Department, Macquarie University, Sydney.\n"
14049         , "<P>The command line arguments were: <BR>\n "
14050         , "<STRONG>latex2html</STRONG> <TT>$argv</TT>\n"
14051         , (($SHOW_INIT_FILE && ($INIT_FILE ne ''))?
14052            "\n<P>with initialization from: <TT>$INIT_FILE</TT>\n$init_file_mark\n" :'')
14053         , "<P>The translation was initiated by $address_data[0] on $address_data[1]"
14054         , $open_all, $_)
14055       : join('', $close_all, "$INFO\n", $open_all, $_));
14056     $_;
14060 # Try to translate LaTeX vertical space in a number of <BR>'s.
14061 # Eg. 1cm results in one + two extra <BR>'s.
14062 # To help the browser rendering is quite ugly, but why not.
14064 sub get_vspace {
14065     local($_) = @_;
14066     local($vh) = 0;
14068     return("<BR>") if /-/;
14070     $vh = int($1 * $vspace_12pt{$2} + 0.5)
14071         if (/([0-9.]+)\s*([a-z]+)/);
14072     join('',"<BR>","\n<BR>" x $vh);
14075 sub do_cmd_vskip {
14076     local($_) = @_;
14077     &ignore_numeric_argument;
14078     join('',&get_vspace($1),$_);
14081 sub do_cmd_break {
14082     local($_) = @_;
14083     join('',"<BR>",$_);
14086 sub do_cmd_vspace {
14087     local($_) = @_;
14088     local($how_much);
14089     $how_much = &missing_braces unless (
14090         (s/$next_pair_pr_rx/$how_much = $2;''/e)
14091         ||(s/$next_pair_rx/$how_much = $2;''/e));
14092     join('',&get_vspace($how_much),$_);
14095 sub do_cmd_vspacestar {
14096     &do_cmd_vspace;
14099 sub do_cmd_d_backslash {
14100     local($_) = @_;
14102     # Eat space from &pre_process.
14103     # We could also modifiy $single_cmd_rx and %normalize, but why not here.
14104     s/^ \*?//;
14105     local($spc,$dum)=&get_next_optional_argument;
14106     # If the [...] occurs on the next line, then it is *not* an argument to \\ .
14107     # MRO: replaced $* with /m
14108     if ($dum =~ /\n/m) { 
14109         $spc = $`;
14110         $spc =~ s/\s//gm;
14111         $_ = $'.$_ 
14112     }
14113     join('',(($spc)? &get_vspace($spc): "\n<BR>"),$_);
14117 ################## Commands used in the $FILE.aux file #######################
14119 sub do_cmd_jobname { $FILE . $_[0] }
14121 # This is used in $FILE.aux
14122 sub do_cmd_newlabel {
14123     local($_) = @_;
14124     local($label,$val,$tmp);
14125     $label = &missing_braces unless (
14126         (s/$next_pair_pr_rx/$label = $2;''/eo)
14127         ||(s/$next_pair_rx/$label = $2;''/eo));
14128     $tmp = &missing_braces unless (
14129         (s/$next_pair_pr_rx/$tmp=$2;''/eo)
14130         ||(s/$next_pair_rx/$tmp=$2;''/eo));
14131     $val = &missing_braces unless (
14132         ($tmp =~ s/$next_pair_pr_rx/$val=$2;''/eo)
14133         ||($tmp =~ s/$next_pair_rx/$val=$2;''/eo));
14134     $val =~ s/(^\s+|\s+$)//gs;
14135     $label =~ s/$label_rx/_/g;  # Replace non alphanumeric characters
14136     $latex_labels{$label} = $val;
14137     &do_labels_helper($label);
14138     $_;
14140 sub do_cmd_oldnewlabel { &do_cmd_newlabel(@_) }
14143 # Sets %encoded_(section|figure|table)_number, which maps encoded
14144 # section titles to LaTeX numbers
14145 # .= \$number . \"$;\"";
14146 sub do_cmd_oldcontentsline { &do_cmd_contentsline(@_) }
14147 sub do_cmd_contentsline {
14148     local($_) = @_;
14149     local($arg,$after,$title,$number,$hash,$stype,$page);
14150     # The form of the expression is:
14151     # \contentsline{SECTION} {... {SECTION_NUMBER} TITLE}{PAGE}
14152     $stype = &missing_braces unless (
14153         (s/$next_pair_pr_rx/$stype = $2;''/e)
14154         ||(s/$next_pair_rx/$stype = $2;''/e));
14155     $arg = &missing_braces unless (
14156         (s/$next_pair_pr_rx/$arg = $2;''/e)
14157         ||(s/$next_pair_rx/$arg = $2;''/e));
14158     $page = &missing_braces unless (
14159         (s/$next_pair_pr_rx/$page = $2;''/e)
14160         ||(s/$next_pair_rx/$page = $2;''/e));
14162 #    s/$any_next_pair_pr_rx/$stype = $2;''/eo; # Chop off {SECTION}
14163 #    s/$any_next_pair_pr_rx/$arg   = $2;''/eo; # Get {... {SECTION_NUMBER} TITLE}
14164 #    s/$any_next_pair_pr_rx/$page  = $2;''/eo; # Get page number
14165     $hash = $stype if (($stype =~ /^(figure|table)$/)||($SHOW_SECTION_NUMBERS));
14166     $hash =~ s/(sub)*(section|chapter|part)/section/;
14167     $after = $_;
14168     if ($hash) {
14169         if ($arg =~ /^$OP/) {
14170             $number = &missing_braces unless (
14171                 ($arg =~ s/$next_pair_pr_rx/$number = $2;''/eo)
14172                 ||($arg =~ s/$next_pair_rx/$number = $2;''/eo));
14173         }       
14174         if ($stype eq "part") {
14175             while ($arg =~ s/$next_pair_pr_rx//o) {};
14176             $number =~ tr/a-z/A-Z/;
14177             $number = "Part $number:"}
14178         # This cause problem when picking figure numbers...
14179         # while ($tmp =~ s/$next_pair_pr_rx//o) {};
14180         $number = -1 unless $number;
14181 #JCL(jcl-tcl)
14182 ##      $_ = $arg;
14183 #       $title = &sanitize($arg);
14184 ##      &text_cleanup;
14185 ##      $title = &encode_title($_);
14187         #remove surrounding brace-numbering
14188         $arg =~ s/^($O|$OP)\d+($C|$CP)|($O|$OP)\d+($C|$CP)$//g;
14189         $arg =~ s/\\footnote(mark|text)?//g;
14190         # \caption arguments should have had environments translated already
14191         $arg = &translate_environments($arg) if ($arg =~ /\\begin/);
14192         #replace image-markers by the image params
14193         $arg =~ s/$image_mark\#([^\#]+)\#/&purify_caption($1)/e;
14195         #RRM: resolve any embedded cross-references first
14196         local($checking_caption) = 1;
14197         $title = &simplify($arg);
14198         $title = &sanitize($title);
14199         $checking_caption = '';
14200         eval "\$encoded_${hash}_number{\$title} .= \$number . \"$;\"";
14201     }
14202     $after;
14206 #  Before normalizing this was \@input.  Used in .aux files.
14208 sub do_cmd__at_input {
14209     local ($_) = @_;
14210     local ($file, $after);
14211     $file = &missing_braces unless (
14212         (s/$next_pair_pr_rx/$file=$2;''/eo)
14213         ||(s/$next_pair_rx/$file=$2;''/eo));
14214     local($prefix, $suffix) = split(/\./, $file);
14215     $after = $_;
14216     local($EXTERNAL_FILE) = $prefix;
14217     &process_ext_file($suffix);
14218     $after;
14222 ########################### Counter Commands #################################
14223 # Removes the definition from the input string, adds to the preamble
14224 # and stores the body in %new_counter;
14225 sub get_body_newcounter {
14226 #    local(*_) = @_;
14227     local($after_R) = @_;
14228     local($_) = $$after_R;
14229     local($within,$ctr,$cmd,$tmp,$body,$pat);
14230     local($new_ctr) = 'counter';
14231     ($ctr,$pat) = &get_next(1); # Get counter name
14232     &write_warnings ("\n*** LaTeX Error: backslash found in counter-name: $ctr")
14233         if ($pat =~ s/\\//);
14234     $ctr =~ s/^\s*\\//; 
14235     $new_ctr .= $pat;
14237     ($within,$pat) = &get_next(0);      # Get optional within, currently ignored
14238     &addto_dependents($within,$ctr);
14239     $new_ctr .= $pat;
14240     do {
14241 ###     local($_) = "\\arabic<<1>>$ctr<<1>>";
14242         $body = "\\arabic<<1>>$ctr<<1>>";
14243         &make_unique($body);
14244         $cmd = "the$ctr";
14245         $tmp = "do_cmd_$cmd";
14246         $new_command{$cmd} = join(':!:',0,$body,'}') unless (defined &$tmp);
14247             &write_mydb("new_command", $cmd, $new_command{$cmd});
14248         undef $body;
14249     };
14250     &do_body_newcounter($ctr);
14252     $$after_R = $_;
14253     if (!$PREAMBLE) {
14254         my $new_cmd = join(''
14255             , "counter{$ctr}", ($within ? "[$within]" : '') );
14256         &add_to_preamble('counter','\\new'.$new_cmd);
14257         return ();
14258     }
14259     'newed'.$new_ctr;
14262 sub do_body_newcounter {
14263     local($ctr) = @_;
14264     $latex_body .= &revert_to_raw_tex("\\newcounter{$ctr}\n")
14265         unless ($preamble =~ /\\new(counter|theorem){$ctr}/);
14266     $global{$ctr} = 0;
14267     &process_commands_wrap_deferred("the$ctr ");
14268     $_;
14272 #RRM: This doesn't work properly yet.
14273 #     The new booleans need to be stored for use in all partitions.
14274 #     \if... \else  \fi  is not yet implemented.
14276 sub get_body_newboolean {
14277 #    local(*_) = @_;
14278     local($after_R) = @_;
14279     local($_) = $$after_R;
14280     my $bool;
14281     $bool = &missing_braces unless (
14282         (s/$next_pair_pr_rx/$bool=$2;''/e)
14283         ||(s/$next_pair_rx/$bool=$2;''/e));
14284     $bool =  &process_body_newif('',$bool);
14285     $$after_R = $_;
14286     'newed'.$bool;
14289 sub get_body_newif {
14290 #    local(*_) = @_;
14291     local($after_R) = @_;
14292     local($_) = $$after_R;
14293     local($bool);
14294     if (!(s/^\s*\\if([a-zA-Z]+)//)) {
14295         $$after_R = $_;
14296         return();
14297     }
14298     $bool = $1;
14299     $$after_R = $_;
14300     join('','newed', &process_body_newif('', $bool));
14304 sub process_body_newif {
14305     local($texif, $bool) = @_;
14306     local($body,$ifbool,$cmd,$tmp,$pat);
14307    
14308 #    ($bool,$pat) = &get_next(1);       # Get boolean name
14310 #    # change the brace-type around the command-name
14311 #    $pat =~ s/$O/$OP/; $pat =~ s/$C/$CP/; $new_cmd .= $pat;
14313     $ifbool = "if".$bool;
14314     $global{$ifbool} = 0;
14316     do {
14317         $body = "\$global{'$ifbool'} = 1;";
14318         $cmd = $bool."true";
14319         $code = "sub do_cmd_$cmd { ".$body." \$_[0];}";
14320         eval $code;
14321         print STDERR "\n*** sub do_cmd_$cmd failed:\n$@\n" if ($@);
14322         $raw_arg_cmds{$cmd} = 1;
14324         $body = "\$global{$ifbool} = 0;";
14325         $cmd = $bool."false";
14326         $code = "sub do_cmd_$cmd { ".$body." \$_[0];}";
14327         eval $code;
14328         print STDERR "\n*** sub do_cmd_$cmd failed:\n$@\n" if ($@);
14329         $raw_arg_cmds{$cmd} = 1;
14331         undef $body;
14332     };
14333     &process_commands_wrap_deferred("${bool}true\n${bool}false\nif$bool\n");
14335 #    $latex_body .= &revert_to_raw_tex("\\newif\\$ifbool\n")
14336 #       unless ($preamble =~ /\\newif\s*\\$ifbool/);
14338     if (!$PREAMBLE) {
14339         local($new_cmd) = "boolean{\\$bool}";
14340         &add_to_preamble ('newif', "\\new$new_cmd" );
14341         return ();
14342     }
14343     local($br_id) = ++$global{'max_id'};
14344     'boolean'."$O$br_id$C$bool$O$br_id$C";
14348 sub do_cmd_value {
14349     local($_) = @_;
14350     local($ctr,$val);
14351     $ctr = &missing_braces
14352         unless ((s/$next_pair_pr_rx/$ctr = $2;''/eo)
14353               ||(s/$next_pair_rx/$ctr = $2;''/eo));
14354     $val = &get_counter_value($ctr);
14355     if ($val) { $val.$_ }
14356     else { join(''," 0",$_) }
14359 sub do_cmd_boolean {
14360     local($_) = @_;
14361     local($bool,$val);
14362     $bool = &missing_braces
14363         unless ((s/$next_pair_pr_rx/$bool = $2;''/eo)
14364               ||(s/$next_pair_rx/$bool = $2;''/eo));
14365     $val = &get_boolean_value($bool);
14366     if ($val) { $val.$_ }
14367     else { "0".$_ }
14370 sub get_counter_value {
14371     local($ctr) = @_;
14372     local($val,$index);
14373     $ctr = 'eqn_number' if ($ctr eq "equation");
14374     $index = $section_commands{$ctr};
14376     if (defined $global{$ctr}) { $val= $global{$ctr}; }
14377     elsif (($SEGMENT)&&($index)) { 
14378         $val = $segment_sec_id[$index]
14379 #    if ($index) { 
14380 #       if ($SEGMENT) { $val = $segment_sec_id[$index] }
14381 #       else { $val = $curr_sec_id[$index] }
14382     } else {
14383         &write_warnings ("\ncounter $ctr not defined");
14384         $val= 0;
14385     }
14386     print "\nVAL:$ctr: $val " if ($VERBOSITY > 3);
14387     $val;
14390 sub get_boolean_value {
14391     local($bool) = @_;
14392     local($val,$index);
14393     if (defined $global{$bool}) { $val= $global{$bool} }
14394     else {
14395         &write_warnings ("boolean $bool not defined\n");
14396         $val="0";
14397     }
14398     print "\nBOOL:$bool: $val " if ($VERBOSITY > 3);
14399     $val;
14402 sub do_cmd_addtocounter {
14403     local($_) = @_;
14404     local($ctr,$num,$index);
14405     $ctr = &missing_braces
14406         unless ((s/$next_pair_rx/$ctr = $2;''/eo)
14407               ||(s/$next_pair_pr_rx/$ctr = $2;''/eo));
14408     $num = &missing_braces
14409         unless ((s/$next_pair_rx/$num = $2;''/eo)
14410               ||(s/$next_pair_pr_rx/$num = $2;''/eo));
14412     $num = &translate_commands($num) if ($num =~ /\\/);
14413     if ($num !~ /^\s*(\+|-)?\d+\s*$/) {
14414         print STDERR "\n*** cannot set counter $ctr to $num ***\n";
14415         return($_);
14416     }
14418     $latex_body .= &revert_to_raw_tex("\\addtocounter{$ctr}{$num}\n");
14419     $index = $section_commands{$ctr};
14421     if (defined $global{$ctr}) { $global{$ctr} += $num }
14422     elsif ($index) { 
14423         if ($SEGMENT) { $segment_sec_id[$index] += $num }
14424         else { $curr_sec_id[$index] += $num }
14425         $global{$ctr} += $num;
14426     } elsif ($ctr eq "equation") {
14427         $global{'eqn_number'} += $num
14428     } else { $global{$ctr} += $num };
14429     print "\nADD:$ctr:+$num= ". $global{$ctr}." " if ($VERBOSITY > 3);
14430 #    &reset_dependents($ctr) if ($dependent{$ctr});
14431     $_;
14434 sub do_cmd_setcounter {
14435     local($_) = @_;
14436     local($ctr,$num,$index,$sctr);
14437     $ctr = &missing_braces
14438         unless ((s/$next_pair_rx/$ctr = $2;''/eo)
14439               ||(s/$next_pair_pr_rx/$ctr = $2;''/eo));
14440     $num = &missing_braces
14441         unless ((s/$next_pair_rx/$num = $2;''/eo)
14442               ||(s/$next_pair_pr_rx/$num = $2;''/eo));
14444     $num = &translate_commands($num) if ($num =~ /\\/);
14445     if ($num !~ /^\s*(\+|-)?\d+\s*$/) {
14446         print STDERR "\n*** cannot set counter $ctr to $num ***\n";
14447         return($_);
14448     }
14449     if ($ctr =~ /^l/) {
14450         $sctr = $';
14451         $ctr = $sctr if $section_commands{$sctr};
14452     }
14453     if (! $AUX_FILE && !($ctr =~ /page/ )) {
14454         $latex_body .= &revert_to_raw_tex("\\setcounter{$ctr}{$num}\n");
14455         $index = $section_commands{$ctr};
14456         if ($index) { 
14457             if ($curr_sec_id[$index] <= $num ) {
14458                 $curr_sec_id[$index] = $num
14459             } else {
14460                 print "\nignoring \\setcounter{$ctr}{$num} currently at ",$curr_sec_id[$index] ;
14461                 &write_warnings(join('',"\n\\setcounter{$ctr}{$num} ignored,"
14462                         ," cannot reduce from ",$curr_sec_id[$index]));
14463             }
14464             $global{$ctr} = $num;
14465         } elsif ($ctr eq "equation") {$global{'eqn_number'} = $num }
14466         else { $global{$ctr} = $num };
14467     }
14468     print "\nSET:$ctr: = $num" if ($VERBOSITY > 3);
14469 #    &reset_dependents($ctr) if ($dependent{$ctr});
14470     $_;
14473 sub do_cmd_setlength {
14474     local($_) = @_;
14475     local($dimen,$value,$index,$sctr);
14476     $dimen = &missing_braces
14477         unless ((s/$next_pair_rx/$dimen = $2;''/eo)
14478               ||(s/$next_pair_pr_rx/$dimen = $2;''/eo));
14479     $value = &missing_braces
14480         unless ((s/$next_pair_rx/$value = $2;''/eo)
14481               ||(s/$next_pair_pr_rx/$value = $2;''/eo));
14483     # recognise specific length-parameters
14484     if ($dimen =~ /captionwidth/) {
14485         local($pxs,$len) = &convert_length($value, $MATH_SCALE_FACTOR);
14486         $cap_width = $pxs if ($pxs &&($dimen =~ /captionwidth/));
14487     }
14488     if ((! $AUX_FILE)&&(! $PREAMBLE)) {
14489         $latex_body .= &revert_to_raw_tex("\\setlength{$dimen}{$value}\n");
14490         print "\nSETLENGTH:$dimen = $value" if ($VERBOSITY > 3);
14491     }
14492     $_;
14495 sub do_cmd_setboolean {
14496     local($_) = @_;
14497     local($bool,$val);
14498     $bool = &missing_braces
14499         unless ((s/$next_pair_rx/$bool = $2;''/eo)
14500               ||(s/$next_pair_pr_rx/$bool = $2;''/eo));
14501     $val = &missing_braces
14502         unless ((s/$next_pair_rx/$val = $2;''/eo)
14503               ||(s/$next_pair_pr_rx/$val = $2;''/eo));
14504     if (! $AUX_FILE) {
14505         $latex_body .= &revert_to_raw_tex("\\setboolean{$bool}{$val}\n");
14506         $global{"if$bool"} = (($val = ~/true/) ? 1 : 0);
14507         print "\nSETBOOL:$bool = $val" if ($VERBOSITY > 3);
14508     }
14509     $_;
14512 sub do_cmd_endsegment {
14513     local($_) = @_;
14514     local($ctr,$dum) = &get_next_optional_argument;
14515     local($index,$steps) = ('',1);
14516 #    $steps = &missing_braces unless (
14517 #       (s/$next_pair_pr_rx/$steps = $2;''/e)
14518 #       ||(s/$next_pair_rx/$steps = $2;''/e));
14519     $index = $section_commands{$ctr} if $ctr;
14520 #    if ($index) { $curr_sec_id[$index] += $steps }
14521 #    if ($index) { ($after_segment,$after_seg_num) = ($index,$steps) }
14522     if ($index) { ($after_segment,$after_seg_num) = ($index,1) }
14523     $_;
14526 sub do_cmd_stepcounter {
14527     local($_) = @_;
14528     local($ctr,$index);
14529     $ctr = &missing_braces
14530         unless ((s/$next_pair_rx/$ctr = $2;''/eo)
14531               ||(s/$next_pair_pr_rx/$ctr = $2;''/eo));
14532     if (! $AUX_FILE) {
14533         $latex_body .= &revert_to_raw_tex("\\stepcounter{$ctr}\n");
14534         $index = $section_commands{$ctr};
14535         if ($index) {
14536 #           if ($SEGMENT) { $segment_sec_id[$index] += 1 }
14537 #           else { $curr_sec_id[$index] += 1 }
14538             $global{$ctr} += 1;
14539         } elsif ($ctr eq "equation") { $global{'eqn_number'} += 1 }
14540         else { $global{$ctr} += 1 };
14541     }
14542     print "\nSTP:$ctr:+1" if ($VERBOSITY > 3);
14543     &reset_dependents($ctr) if ($dependent{$ctr});
14544     $_;
14547 #RRM:   dependent counters are stored as a comma-separated list
14548 #       in the %dependent hash.
14549 sub reset_dependents {
14550     local($ctr) = @_;
14551     local($dep,$subdep,%dependents);
14552     @dependents = (split($delim, $dependent{$ctr}));
14553     print "\n" if (($VERBOSITY > 3)&&(@dependents));
14554     while (@dependents) {
14555         $dep = pop(@dependents);
14556         print "RESET $dep to 0\n" if ($VERBOSITY > 3);
14557         if ($global{$dep}) { $global{$dep} = 0 }
14558         elsif ($dep =~ /equation/) { $global{'eqn_number'} = 0 }
14559         if ($dependent{$dep}) {
14560             push(@dependents,split($delim,$dependent{$dep}));
14561         }
14562     }
14565 sub do_cmd_numberwithin {
14566     local($_) = @_;
14567     local($ctr,$within);
14568     $ctr = &missing_braces
14569         unless ((s/$next_pair_rx/$ctr = $2;''/eo)
14570               ||(s/$next_pair_pr_rx/$ctr = $2;''/eo));
14571     $within = &missing_braces
14572         unless ((s/$next_pair_rx/$within = $2;''/eo)
14573               ||(s/$next_pair_pr_rx/$within = $2;''/eo));
14575     # record the counter dependency
14576     &addto_dependents($within,$ctr) if ($within);
14577     local($newsub) = "sub do_cmd_the$ctr {"
14578         . "\$global{'max_id'}++;\n"
14579 #        . "local(\$super)=\&do_cmd_the$within();\n"
14580         . "local(\$super)=\&translate_commands('\\the$within');\n"
14581         . "\$super .= '.' unless (\$super =~/\\.\$/);\n"
14582         . "\$super .\&do_cmd_value('<<'.\$global{'max_id'}.'>>"
14583         . $ctr . "<<'.\$global{'max_id'}.'>>')}\n";
14584     eval $newsub;
14585     print " *** sub do_cmd_the$ctr unchanged *** $@ " if ($@);
14586     $_;
14589 sub do_cmd_refstepcounter {
14590     local($_) = @_;
14591     local($ctr);
14592     $ctr = &missing_braces
14593         unless ((s/$next_pair_rx/$ctr = $2;''/eo)
14594               ||(s/$next_pair_pr_rx/$ctr = $2;''/eo));
14595     if (! $AUX_FILE) {
14596         $latex_body .= &revert_to_raw_tex("\\refstepcounter{$ctr}\n");
14597         $index = $section_commands{$ctr};
14598         if (defined $global{$ctr}) { $global{$ctr} += 1 }
14599         elsif ($index) {
14600             if ($SEGMENT) { $segment_sec_id[$index] += 1 }
14601             else { $curr_sec_id[$index] += 1 }
14602         } elsif ($ctr eq "equation") { $global{'eqn_number'} += 1 }
14603         else { $global{$ctr} += 1 };
14604     }
14605     print "\nSTP: $ctr : +1" if ($VERBOSITY > 3);
14606     &reset_dependents($ctr) if ($dependent{$ctr});
14607     $_;
14610 sub read_counter_value {
14611     local($_) = @_;
14612     local($ctr,$br_id,$val);
14613     $ctr = &missing_braces
14614         unless ((s/$next_pair_pr_rx/$br_id = $1; $ctr = $2;''/eo)
14615               ||(s/$next_pair_rx/$br_id = $1; $ctr = $2;''/eo));
14616     $val = &get_counter_value($ctr);
14617     ($ctr, $val, $br_id, $_)
14620 sub styled_number_text {
14621     local($num_style, $val, $txtID) = @_;
14622     if ($USING_STYLES) {
14623         $txt_style{$num_style} = " " unless ($txt_style{$num_style});
14624         join('',"<SPAN CLASS=\"$num_style\">", $val, "</SPAN>", $_);
14625     } else { $val.$_ }
14628 sub do_cmd_arabic {
14629     local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14630     $val = ($val ? &farabic($val) : "0");
14631     &styled_number_text('arabic', $val, $id);
14633     
14634 sub do_cmd_roman {
14635     local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14636     if ($val < 0 ) { $val = join('',"-",&froman(-$val)); }
14637     elsif ($val) { $val = &froman($val) }
14638     else { $val = "0"; }
14639     &styled_number_text('roman', $val, $id);
14642 sub do_cmd_Roman {
14643     local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14644     if ($val < 0 ) { $val = join('',"-",&fRoman(-$val)); }
14645     elsif ($val) { $val = &fRoman($val) }
14646     else { $val = "0"; }
14647     &styled_number_text('Roman', $val, $id);
14650 sub do_cmd_alph {
14651     local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14652     if ($val < 0 ) { $val = join('',"-",&falph(-$val)); }
14653     elsif ($val) { $val = &falph($val) }
14654     else { $val = "0"; }
14655     &styled_number_text('alph', $val, $id);
14658 sub do_cmd_Alph {
14659     local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14660     if ($val < 0 ) { $val = join('',"-",&fAlph(-$val)); }
14661     elsif ($val) { $val = &fAlph($val) }
14662     else { $val = "0"; }
14663     &styled_number_text('Alph', $val, $id);
14667 sub do_cmd_fnsymbol {
14668     local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14669     $val = &process_in_latex_helper($ctr, $val, "fnsymbol{$ctr}");
14670     &styled_number_text('Alph', $val, $id);
14675 # This is a general command for getting counter values;
14676 # e.g. for section-numbers.
14678 sub do_cmd_thecounter {
14679     local($_) = @_;
14680     # Uses $counter bound by the caller
14681     local($val) = &get_counter_value($counter);
14682     $val = &process_in_latex_helper($counter,$val,"the$counter");
14683     &styled_number_text($counter, $val, '');
14684 #   join('',&process_in_latex_helper($counter,$val,"the$counter"),$_[0]);
14688 ################# Special Naming Macros ##################################
14690 sub do_cmd_LaTeX {
14691     local($_) = @_;
14692     if ($USING_STYLES) {
14693         $env_style{'LaTeX'} = ' ' unless ($env_style{'LaTeX'});
14694         $env_style{'logo-LaTeX'} = ' ' unless ($env_style{'logo-LaTeX'});
14695         join('',"<SPAN CLASS=\"logo,LaTeX\">",$Laname, $TeXname,"</SPAN>",$_);
14696     } else { join('',$Laname, $TeXname, $_); }
14699 sub do_cmd_LaTeXe {
14700     local($_) = @_;
14701     if ($USING_STYLES) {
14702         $env_style{'LaTeX2e'} = ' ' unless ($env_style{'LaTeX2e'});
14703         $env_style{'logo-LaTeX2e'} = ' ' unless ($env_style{'logo-LaTeX2e'});
14704         join('',"<SPAN CLASS=\"logo,LaTeX2e\">"
14705                 ,$Laname, $TeXname,'2<SUB>e</SUB>',"</SPAN>",$_);
14706     } else { join('',$Laname,$TeXname
14707                 ,(($HTML_VERSION >= 3.0)? '2<SUB>e</SUB>':'2e'),$_);
14708     }
14711 sub do_cmd_latextohtml {
14712     local($_) = @_;
14713     if ($USING_STYLES) {
14714         $env_style{'LaTeX2HTML'} = ' ' unless ($env_style{'LaTeX2HTML'});
14715         $env_style{'logo-LaTeX2HTML'} = ' ' unless ($env_style{'logo-LaTeX2HTML'});
14716         join('',"<SPAN CLASS=\"logo,LaTeX2HTML\">"
14717                 ,$Laname, $TeXname,"2<TT>HTML</TT>","</SPAN>",$_);
14718     } else { join('',$Laname,$TeXname,"2<TT>HTML</TT>",$_);}
14721 sub do_cmd_TeX {
14722     local($_) = @_;
14723     if ($USING_STYLES) {
14724         $env_style{'logo-TeX'} = ' ' unless ($env_style{'logo-TeX'});
14725         join('',"<SPAN CLASS=\"logo-TeX\">",$TeXname,"</SPAN>",$_);
14726     } else { join('',$TeXname, $_);}
14729 sub do_cmd_MF {
14730     local($_) = @_;
14731     if ($USING_STYLES) {
14732         $env_style{'logo-Metafont'} = ' ' unless ($env_style{'logo-Metafont'});
14733         join('',"<SPAN CLASS=\"logo-Metafont\">",$MFname,"</SPAN>",$_);
14734     } else { join('', $MFname, $_);}
14737 sub do_cmd_Xy {
14738     local($_) = @_;
14739     if ($USING_STYLES) {
14740         $env_style{'logo-Xy-pic'} = ' ' unless ($env_style{'logo-Xy-pic'});
14741         join('',"<SPAN CLASS=\"logo-Xy-pic\">",$Xyname,"</SPAN>",$_);
14742     } else { join('',$Xyname, $_);}
14745 sub do_cmd_AmS {
14746     local($_) = @_;
14747     if ($USING_STYLES) {
14748         $env_style{'logo-AMS'} = ' ' unless ($env_style{'logo-AMS'});
14749         join('',"<SPAN CLASS=\"logo-AMS\">",$AmSname,"</SPAN>",$_);
14750     } else { join('',$AmSname, $_);}
14753 sub do_cmd_AmSTeX {
14754     local($_) = @_;
14755     if ($USING_STYLES) {
14756         $env_style{'logo-AMS'} = ' ' unless ($env_style{'logo-AMS'});
14757         join('',"<SPAN CLASS=\"logo-AMS\">",$AmSname,"-$TeXname","</SPAN>",$_);
14758     } else { join('',$AmSname, "-", $TeXname, $_);}
14761 sub do_cmd_char {
14762     local($_) = @_;
14763 # some special characters are already turned into l2h internal
14764 # representation.
14765 # Get its represention from the table and use it like as regexp form.
14766     local($spmquot) = &escape_rx_chars($html_specials{'"'});
14767 # Get all internal special char representations as implied during
14768 # preprocessing.
14769     local($spmrx) = join("\000",values %html_specials);
14770 # escape regexp special chars (not really necessary yet, but why not)
14771     $spmrx = &escape_rx_chars($spmrx); #~ s:([\\(){}[\]\^\$*+?.|]):\\$1:g;
14772     $spmrx =~ s/\000/|/g;
14773     $spmrx = "(.)" unless $spmrx =~ s/(.+)/($1|.)/;
14775     s/^[ \t]*(\d{1,3})[ \t]*/&#$1;/ &&
14776         return($_);
14778     s/^[ \t]*\'(\d{1,3})[ \t]*/"&#".oct($1).";"/e &&
14779         return($_);
14781     s/^[ \t]*$spmquot(\d{1,2})[ \t]*/"&#".hex($1).";"/e &&
14782         return($_);
14784 # This is a kludge to work together with german.perl. Brrr.
14785     s/^[ \t]*\'\'(\d{1,2})[ \t]*/"&#".hex($1).";"/e &&
14786         return($_);
14787 # If l2h's special char marker represents more than one character,
14788 # it's already in the &#xxx; form. Else convert the single character
14789 # into &#xxx; with the ord() command.
14790     s/^[ \t]*\`\\?$spmrx[ \t]*/
14791         (length($html_specials_inv{$1}) > 1 ?
14792          $html_specials_inv{$1} : "&#".ord($html_specials_inv{$1}||$1).";")/e &&
14793              return($_);
14794     &write_warnings(join('',
14795                          "Could not find character number in \\char",
14796                          (/\n/ ? $` : $_), " etc.\n"));
14797     $_;
14801 sub do_cmd_symbol {
14802     local($_) = @_;
14803     local($char);
14804     $char = &missing_braces
14805         unless ((s/$next_pair_pr_rx/$char = $2;''/eo)
14806                 ||(s/$next_pair_rx/$char = $2;''/eo));
14807     join('',&do_cmd_char($char),$_);
14810 ################# Accent and Special Symbols ##################################
14812 # Generate code for the accents handling commands that are never
14813 # applied to i or j.
14814 # MEH: Now all accents are safe for dotless i or j
14815 # MEH: Math accents supported as well
14816 sub generate_accent_commands {
14817     local($accent,$accent_cmd);
14818     local(%accents) = ("c", "cedil", "pc", "cedil", "d", "bdot", "b", "b",
14819                        "tilde", "tilde", "dot", "dot", "bar", "macr",
14820                        "hat", "circ", "u", "breve", "v", "caron",
14821                        "H", "dblac", "t", "t", "grave", "grave",
14822                        "acute", "acute", "ddot", "uml", "check", "caron",
14823                        "breve", "breve", "vec", "vec",
14824                        "k", "ogon", "r", "ring");
14825     foreach $accent (keys(%accents))  {
14826         $accent_cmd = "sub do_cmd_$accent {" . 'local($_) = @_;'  .
14827             "&accent_safe_for_ij('$accents{$accent}','$accent');" . '$_}';
14828         eval $accent_cmd;
14829         $accent_cmd = "do_cmd_$accent";
14830         print STDERR "\n*** sub do_cmd_$accent failed:\nPERL: $@\n" if ($@);
14831     }
14834 # These handle accents, taking care of the dotless i's and j's that
14835 # may follow (even though accented j's are not part of any alphabet
14836 # that I know).
14838 # Note that many forms of accents over dotless i's and j's are
14839 # handled:
14840 #   "\^\i rest"
14841 #   "\^\i
14842 #    rest"
14843 #   "\^{\i}rest"
14844 #   "\^\i{}rest"
14845 # They all produce "&#238;rest".
14846 # MEH: now also handles
14847 #   "\^{}rest"
14848 #   "\^,rest"
14849 # and many more
14851 sub accent_safe_for_ij {
14852     local($type,$acc_cmd) = @_;
14853     local($arg, $first_char,$ij_cmd);
14854     #print STDOUT "\nACCENT: $type <$_>\n" ;
14855     s/^[ \t]*\n?[ \t]*(\S)/$1/; # Remove whitespace
14856     if (s/^\\([ij])([^a-zA-Z]|$)/$2/) {
14857         # Accent of this form: "\^\i rest" or "\^\i{}rest"
14858         ($arg) =  $1; $ij_cmd = "\\$1";
14859         s/^[ \t]+//o;           # Get rid of whitespaces after \i
14860         if (substr($_, 0, 2) =~ /[\n\r][^\n\r]/) {
14861             $_ = substr($_, 1); # Get rid of 1 newline after \i
14862         }
14863     } else {
14864         # Accent of this form: "\^{\i}rest" or not an accent on i nor j
14865         ($arg) =  &get_next_pair_or_char_pr;
14866     }
14867     $arg =~ s/([^\s\\<])/$first_char = $1; ''/eo;
14868 #   print STDOUT "\nACCENT1 type:$type arg:|${arg}| first_char: |$first_char| $ij_cmd 
14869 #       , $ACCENT_IMAGES\n";
14871     local($aafter) = $_;
14872     local($iso) = &iso_map($first_char,$type); 
14873     if ($iso) { $_ = join('', $iso, $arg, $aafter) }
14874     elsif ((!($ACCENT_IMAGES))&&(!($ij_cmd))) {
14875         local($err_string) = 
14876             "\nNo available accent for $first_char$type , using just \"$first_char$arg\"";
14877         print $err_string if ($DEBUG||$VERBOSITY > 1);
14878         &write_warnings("\n ...set \$ACCENT_IMAGES  to get an image ");
14879         $_ = join('', $first_char, $arg, $aafter) }
14880     else { 
14881         print ", making image of accent: $first_char$type " if ($VERBOSITY > 1);
14882         $_ = join('', &mbox_accent($acc_cmd, $first_char, $ij_cmd) , $arg, $aafter)
14883     }
14886 sub mbox_accent {
14887     local($type, $char, $ij_cmd) = @_;
14888     if (length($type) > 1 ) {
14889         if ($text_accent{$type}) {
14890             $type = $text_accent{$type};
14891         } elsif ($type =~ /^(math)?accent/) {
14892         } else {
14893             print "\n unrecognised accent $type for `$char' ";
14894             return $char;
14895         }
14896     }
14897     local(@styles);
14898     local($cmd,$style,$bstyle,$estyle) = ('','','','');
14899     local(@styles) = split(',',$ACCENT_IMAGES);
14900     foreach $style (@styles) {
14901         $style =~ s/(^\s*\\|\s*)//g; 
14902         $cmd = "do_cmd_$style";
14903         if (defined &$cmd) { 
14904             $bstyle .= "\\$style\{" ;
14905             $estyle .= "\}";
14906         } else {
14907             &write_warnings("\nunrecognized style \\$style for accented characters");
14908         }
14909     }
14910     if (!($bstyle)) {
14911         $bstyle = "\{";
14912         $estyle = "\}";
14913     } elsif ($bstyle =~ /textit|itshape/) {
14914         $bstyle = '\raise.5pt\hbox{' . $bstyle ;        
14915         $estyle .= "\}";
14916     }
14917     $char = $ij_cmd if ($ij_cmd);
14918     print STDOUT "\nACCENT: $type, $char" if ($VERBOSITY > 2);
14919     local($afterkern); # serifs extend too far on some letters...
14920     $afterkern = "\\kern.05em" if (($char =~ /m|n/)||($type=~/[Hv]/));
14921     # ...or the accent is wider than the letter, so pad it out a bit
14922     $afterkern = "\\kern.15em" if ($char =~ /i|l/); #||($type=~/v/));
14924     &process_undefined_environment("tex2html_accent_inline"
14925         , ++$global{'max_id'}, "${bstyle}\\${type}\{$char\\/\}$estyle$afterkern");
14928 # MEH: Actually tries to find a dotless i or j
14929 sub do_cmd_i { join('',&iso_map('i', 'nodot') || 'i', $_[0]) }
14930 sub do_cmd_j { join('',&iso_map('j', 'nodot') || 'j', $_[0]) }
14932 sub do_cmd_accent {
14933     local($_) = @_;
14934     local($number);
14935     if (s/\s*(\d+)\s*//o) {$number = $1}
14936     elsif (s/\s*&SMPquot;(\d)(\d)\s*//o) { $number = $1*16 + $2 }
14937     elsif (s/\s*\'(\d)(\d)(\d)\s*//o) { $number = $1*64 + $2*8 + $3 }
14938     else { s/\s*(\W\w+)([\s\W])/$2/o;  $number = $1 }
14939     local($type) = $accent_type{uc($number)};
14940     #print STDOUT "\ndo_cmd_accent: $number ($type) |$_|\n";
14941     if (! $type) {
14942         &write_warnings("Accent number $number is unknown.\n");
14943         return $_;
14944     }
14945     &accent_safe_for_ij($type , 'accent$number' );
14946     $_;
14949 sub do_cmd_ae { join('', &iso_map("ae", "lig"), $_[0]);}
14950 sub do_cmd_AE { join('', &iso_map("AE", "lig"), $_[0]);}
14951 sub do_cmd_aa { join('', &iso_map("a", "ring"), $_[0]);}
14952 sub do_cmd_AA { join('', &iso_map("A", "ring"), $_[0]);}
14953 sub do_cmd_o { join('', &iso_map("o", "slash"), $_[0]);}
14954 sub do_cmd_O { join('', &iso_map("O", "slash"), $_[0]);}
14955 sub do_cmd_ss { join('', &iso_map("sz", "lig"), $_[0]);}
14956 sub do_cmd_DH { join('', &iso_map("ETH", ""), $_[0]);}
14957 sub do_cmd_dh { join('', &iso_map("eth", ""), $_[0]);}
14958 sub do_cmd_TH { join('', &iso_map("THORN", ""), $_[0]);}
14959 sub do_cmd_th { join('', &iso_map("thorn", ""), $_[0]);}
14961 sub do_cmd_pounds { join('', &iso_map("pounds", ""), $_[0]);}
14962 sub do_cmd_S { join('', &iso_map("S", ""), $_[0]);}
14963 sub do_cmd_copyright { join('', &iso_map("copyright", ""), $_[0]);}
14964 sub do_cmd_P { join('', &iso_map("P", ""), $_[0]);}
14967 sub brackets { ($OP, $CP);}
14969 sub get_date {
14970     local($format,$order) = @_;
14971     local(@lt) = localtime;
14972     local($d,$m,$y) = @lt[3,4,5];
14973     if ($format =~ /ISO/) {
14974         sprintf("%4d-%02d-%02d", 1900+$y, $m+1, $d);
14975     } elsif ($format) {
14976         if ($order) { eval "sprintf(".$format.",".$order.")"; }
14977         else { sprintf($format, $d, $m+1, 1900+$y); }
14978     } else { sprintf("%d/%d/%d", $m+1, $d, 1900+$y); }
14981 sub address_data {
14982     local($user, $date, $_);
14983     local($format,$order) = @_;
14984     # Get author, (email address) and current date.
14985     ($user = L2hos->fullname()) =~ s/,.*//;
14986     ($user, &get_date($format,$order));
14990 #################################### LaTeX2e ##################################
14992 sub missing_braces {
14993 #    local($cmd) = @_;
14994     local($next, $revert, $thisline);
14995     local($this_cmd) = $cmd;
14996     $this_cmd =~ s/^\\// unless ($cmd eq "\\");
14997     &write_warnings("\n? brace missing for \\$this_cmd");
14998     if (/^[\s%]*([^\n]*)\n/ ) {
14999         $thisline = &revert_to_raw_tex($1)
15000     } else { 
15001         $thisline = &revert_to_raw_tex($_); 
15002     }
15003     print "\n\n*** no brace for \\$this_cmd , before:\n$thisline";
15004     s/^\s*//;
15005     if ($_ =~ s/$next_token_rx//) { $next = $& };
15006     $next =~ s/$comment_mark(\d+\n?)?//g;
15007 #    $next = &translate_commands($next) if ($next =~ /^\\/);
15008     if ($next =~ /^\\(\W|\d|[a-zA-z]*\b)/) {
15009         $revert = $next = "\\".$1;
15010     } elsif ($next =~ /\W/) {
15011         $revert = &revert_to_raw_tex($next);
15012     } else { $revert = $next };
15013     print "\n*** using \"$revert\" as the argument instead; is this correct?  ***\n\n";
15014     $next;
15017 #RRM:
15018 #     &styled_text_chunk  provides an interface for pieces of styled text,
15019 # within a single paragraph. The visual markup can be obtained through either
15020 # 1. link to a stylesheet (CSS)
15021 # 2. direct markup placed into the output
15022 # 3. calling another function to process the text
15023
15024 # parameters (in order):
15025 #  $def_tag   : markup tag to be used, unless $USING_STYLES or no $property given,
15026 #               attributes can be included, only 1st word is used for closing-tag;
15027 #  $prefix    : prefix for the Unique ID identifier, defaults to 'txt'
15028 #           OR  contains  CLASS= identifier  when $property is empty(see below);
15029 #  $type      : general type of the style-sheet information
15030 #  $class     : specific type of the style-sheet information
15031 #  $property  : value to be set, applicable to the $type & $class
15032 #  $alt_proc  : name of procedure to use, if $USING_STYLES == 0, and no $def_tag
15033 #  $_         : current data-stream
15034 #  $open_tags_R : current open-tags (not used in this procedure)
15036 sub styled_text_chunk {
15037     local($def_tag, $prefix, $type, $class, $property, $alt_proc, $_,
15038         $ot) = @_;
15039     local($open_tags_R) = defined $ot ? $ot : $open_tags_R;
15040     local($text, $env_id, $def_end);
15041     local($span_tag) = 'SPAN';
15042     $text = &missing_braces
15043         unless ((s/$next_pair_pr_rx/$text = $2; $env_id = $1;''/eo)
15044             || (s/$next_pair_rx/$text = $2; $env_id = $1;''/eo));
15045     $text = &balance_inner_tags($text);
15047     #start from no open tags
15048     local(@save_open_tags) = ();
15049     local($open_tags_R) = [];
15051 #    local($decl); 
15052 #    if ($prefix =~ /CLASS="(\w+)"/ ) {
15053 #       $decl=$1;
15054 #       push (@$open_tags_R, $decl);
15055 #    }
15056 #    push (@$open_tags_R, $color_env) if $color_env;
15057     if (!$inside_math) {
15058         $text = &translate_environments($text);
15059         $text = &translate_commands($text) if ($text =~ /\\/);
15060         $text .= &balance_tags;
15061     }
15062     
15063     if (($USING_STYLES)&&($env_id =~ /^\d+$/)&&($property)) { 
15064         $prefix = 'txt' unless ($prefix);
15065         $env_id = $prefix.$env_id;
15066         $styleID{$env_id} = join('',"$type", ($class ? "-$class" : '')
15067                                  ,": ", $property,"; ");
15068         return(join('',"<$span_tag ID=\"$env_id\">",$text,"<\/$span_tag>", $_));
15069     }
15071     if (($USING_STYLES)&&($prefix =~ /($span_tag )?CLASS=\"(\w+)\"/o)) {
15072         local($span_class) = $2;
15073         $def_tag = (($1)? $1 : $span_tag." ");
15074         $txt_style{$span_class} = "$type: $class "
15075             unless ($txt_style{$span_class});
15076         return(join('',"<$def_tag CLASS=\"$span_class\">"
15077                 , $text,"<\/$span_tag>", $_));
15078     }
15080     if (($def_tag) && (!$USING_STYLES)) {
15081         $def_tag =~ s/^($span_tag)?CLASS=\"(\w+)\"$// ;
15082     }
15084     if ($def_tag =~ /^(\w+)/) {
15085         $def_end = $1;
15086         return(join('',"<$def_tag>",$text,"<\/$def_end>", $_));
15087     }
15089     return (join('', eval ("&$alt_proc(\$text)") , $_)) if (defined "&$alt_proc");
15091     &write_warnings(
15092         "\ncannot honour request for $type-$class:$property style at br$env_id");
15093     join('', $text, $_);
15096 sub multi_styled_text_chunk {
15097     local($def_tag, $prefix, $type, $class, $property, $_, $ot) = @_;
15098     local($open_tags_R) = defined $ot ? $ot : $open_tags_R;
15099     $prefix = 'txt' unless ($prefix);
15100     my(@def_tags) = split(',',$def_tag);
15101     my(@types) = split(',',$type);
15102     my(@classes) = split(',',$class);
15103     my(@properties) = split(',',$property);
15104     $text = &missing_braces
15105         unless ((s/$next_pair_pr_rx/$text = $2; $env_id = $1;''/eo)
15106             || (s/$next_pair_rx/$text = $2; $env_id = $1;''/eo));
15107     if (($USING_STYLES)&&($env_id =~ /^\d+$/)&&($property)) { 
15108         # $1 contains the bracket-id
15109         $env_id = $prefix.$env_id;
15110         while (@properties) {
15111             $class = shift @classes;
15112             $property = shift @properties;
15113             $styleID{$env_id} .= join(''
15114                 , shift @types,
15115                 , ($class ? "-".$class : '')
15116                 , ($property ? " : $property" : ''), " ; ");
15117             $styleID{$env_id} .= "\n\t\t  " if (@properties);
15118         }
15119     }
15120     join('',"<SPAN ID=\"$env_id\">",$text,"<\/SPAN>", $_);
15123 #RRM: 
15124 #   This one takes care of commands with argument that really should be
15125 #   environments; e.g.  \centerline, \rightline, etc.
15126 #   Note that styles are inherited also from the existing @$open_tags_R.
15128 sub styled_text_block {
15129     local($def_tag, $attrib, $value, $class, $_, $ot) = @_;
15130     local($open_tags_R) = defined $ot ? $ot : $open_tags_R;
15131     local($text, $env_id, $attribs);
15132     if ($attribs =~ /,/ ) {
15133         local(@attribs) = split(',',$attrib);
15134         local(@values) = split(',',$value);
15135         while (@attribs) { 
15136             $attribs .= join('', " " , shift @attribs 
15137                 ,"=\"" , shift @values, "\"") }
15138     } elsif($value) { 
15139         $attribs = join(''," ",$attrib,"=\"",$value,"\"")
15140     } else { $attribs = " " . $attrib }
15142     local(@save_open_tags) = @$open_tags_R;
15143     local($closures) = &close_all_tags();
15144     local($reopens)=&balance_tags();
15145     $text = &missing_braces
15146         unless ((s/$next_pair_pr_rx/$text = $2; $env_id = $1;''/eo)
15147             || (s/$next_pair_rx/$text = $2; $env_id = $1;''/eo));
15148     if (($USING_STYLES)&&($env_id =~ /^\d+$/)) {
15149         $env_id = ++$global{'max_id'};
15150         $env_id = "par".$env_id;
15151         $styleID{$env_id} = " ";
15152         $env_style{$class} = " " if (($class)&&!($env_style{$class}));
15153         $class = " CLASS=\"$class\"" if ($class);
15154         $env_id = " ID=\"$env_id\"";
15155     } else { $class = ''; $env_id = '' };
15157     $text = &translate_environments($text);
15158     $text = &translate_commands($text);
15160     local($closuresA)=&close_all_tags();
15161     local($reopensA) = &balance_tags();
15162     $text =~ s/^\n?/\n/o; 
15163     join('', $closures
15164         , "<$def_tag$class$env_id$attribs>"
15165         , $reopens, $text, $closuresA
15166         , "</$def_tag>\n", $reopensA,  $_);
15170 # this gives a separate ID for each instance
15171 #sub do_cmd_textbf { &styled_text_chunk('B','','font','weight'
15172 #                   ,'bold', '', @_); }
15174 # this uses a single CLASS for all instances
15175 sub do_cmd_textbf { &styled_text_chunk('B','CLASS="textbf"'
15176                     ,'font-weight','bold', '', '', @_); }
15179 # this gives a separate ID for each instance
15180 sub do_cmd_texttt { &styled_text_chunk('TT','','font','','', '', @_); }
15182 # this uses a single CLASS for all instances
15183 #sub do_cmd_textit { &styled_text_chunk('TT','CLASS="textit"'
15184 #                   ,'font-family','monospace', '', '', @_); }
15186 # this gives a separate ID for each instance
15187 #sub do_cmd_textit { &styled_text_chunk('I','','font','style'
15188 #                   ,'italic', '', @_); }
15190 # this uses a single CLASS for all instances
15191 sub do_cmd_textit { &styled_text_chunk('I','CLASS="textit"'
15192                     ,'font-style','italic', '', '', @_); }
15196 # this gives a separate ID for each instance
15197 #sub do_cmd_textsl { &styled_text_chunk('I','','font','style'
15198 #                   ,'oblique', '', @_); }
15200 # this uses a single CLASS for all instances
15201 #sub do_cmd_textsl { &styled_text_chunk('I','CLASS="textsl"'
15202 #                   ,'font-style','oblique', '', '', @_); }
15204 # ... NS4 implements Italic, not oblique
15205 sub do_cmd_textsl { &styled_text_chunk('I','CLASS="textsl"'
15206                     ,'font-style','italic', '', '', @_); }
15209 # this gives a separate ID for each instance
15210 #sub do_cmd_textsf { &styled_text_chunk('I','','font','family'
15211 #                   ,'sans-serif', '', @_); }
15213 # this uses a single CLASS for all instances
15214 #sub do_cmd_textsf { &styled_text_chunk('I','CLASS="textsf"'
15215 #                   ,'font-family','sans-serif', '', '', @_); }
15217 # ... NS4 doesn't implement sans-serif
15218 sub do_cmd_textsf { &styled_text_chunk('I','CLASS="textsf"'
15219                     ,'font-style','italic', '', '', @_); }
15222 #sub do_cmd_textsc {
15223 #    local($_) = @_;
15224 #    local($text, $next, $scstr, $before, $special);
15225 #    $text = &missing_braces
15226 #        unless ((s/$next_pair_pr_rx/$text = $2;''/eo)
15227 #           || (s/$next_pair_rx/$text = $2;''/eo));
15228 #    join('', &process_smallcaps($text), $_);
15231 sub lowercase_entity {
15232     local($char) = @_;
15233     local($exent);
15234     if ($exent = $low_entities{$char}) { "\&#$exent;" }
15235     elsif ($exent = $extra_small_caps{$char}) { $exent }
15236     else { "\&#$char;" }
15239 sub process_smallcaps {
15240     local($text) = @_;
15241     local($next, $scstr, $scbef, $special, $char);
15242     # is this enough for \sc and \scshape ?
15243     $text = &translate_environments($text);
15245     # MRO: replaced $* with /m
15246     while ($text =~ /(\\[a-zA-Z]+|[&;]SPM\w+;|<[^>]+>)+/m ) {
15247         $scbef = $`; $special = $&; $text = $';
15248         while ( $scbef =~ /(&#\d+;|[a-z$sclower])+[a-z\W\d$sclower]*/m) {
15249             $scstr .= $`; $scbef = $';
15250             $next = $&; 
15251             $next =~ s/&#(\d+);/&lowercase_entity($1)/egm;
15252             eval "\$next =~ $scextra" if ($scextra);
15253             eval "\$next =~ tr/a-z$sclower/A-Z$scupper/";
15254             $scstr .= "<SMALL>" . $next ."<\/SMALL>";
15255         }
15256         $scstr .= $scbef . $special;
15257     }
15258     if ($text) {
15259         while ( $text =~ /(&#\d+;|[a-z$sclower])+[a-z\W\d$sclower]*/m) {
15260             $scstr .= $`; $text = $';
15261             $next = $&;
15262             $next =~ s/&#(\d+);/&lowercase_entity($1)/egm;
15263             eval "\$next =~ $scextra" if ($scextra);
15264             eval "\$next =~ tr/a-z$sclower/A-Z$scupper/";
15265             $scstr .= "<SMALL>" . $next ."<\/SMALL>";
15266         }
15267         $scstr .= $text;
15268     }
15269     $scstr;
15272 # this gives a separate ID for each instance
15273 #sub do_cmd_textsc { &styled_text_chunk('','','font','variant'
15274 #                   ,'small-caps', 'process_smallcaps', @_); }
15276 # this uses a single CLASS for all instances
15277 #sub do_cmd_textsc { &styled_text_chunk('', 'CLASS="textsc"'
15278 #                   ,'font-variant','small-caps','', 'process_smallcaps', @_); }
15280 # ...but NS 4.03 doesn't implement  small-caps !!!
15281 sub do_cmd_textsc { &styled_text_chunk('',''
15282                     ,'font-variant','small-caps','', 'process_smallcaps', @_); }
15285 #sub do_cmd_emph { &styled_text_chunk('EM','em','font','variant','','', @_); }
15288 # this gives a separate ID for each instance
15289 #sub do_cmd_underline { &styled_text_chunk('U','','text','decoration','underline','', @_); }
15291 # this uses a single CLASS for all instances
15292 sub do_cmd_underline { &styled_text_chunk('U','CLASS="underline"'
15293                        ,'text-decoration','underline','','', @_); }
15294 sub do_cmd_underbar { &do_cmd_underline(@_) }
15297 # this gives a separate ID for each instance
15298 #sub do_cmd_strikeout { &styled_text_chunk('STRIKE',''
15299 #                      ,'text','decoration','line-through','', @_); }
15301 # this uses a single CLASS for all instances
15302 sub do_cmd_strikeout { &styled_text_chunk('STRIKE','CLASS="strikeout"',
15303                        'text-decoration','line-through','','', @_); }
15306 sub do_cmd_uppercase {
15307     local($_) = @_;
15308     local($text,$next,$done,$special,$after);
15309     $text = &missing_braces unless (
15310             (s/$next_pair_pr_rx/$text = $2;''/eo)
15311             ||(s/$next_pair_rx/$text = $2;''/eo));
15312     $after = $_;
15313     while ($text =~ /(\\[a-zA-Z]+|[&;]SPM\w+;)/ ) {
15314         $next = $`;
15315         $special = $&;
15316         $text = $';
15317         $next =~ tr /a-z/A-Z/ if ($next);
15318         $done .= $next . $special;
15319     }
15320     $text =~ tr /a-z/A-Z/ if ($text);
15321     $done .= $text;
15322     $done = &convert_iso_latin_chars($done) if ($done);
15323     join('',$done,$after);
15326 sub do_cmd_lowercase {
15327     local($_) = @_;
15328     local($text,$next,$done,$special,$after);
15329     $text = &missing_braces
15330         unless ((s/$next_pair_pr_rx/$text = $2;''/seo)
15331             || (s/$next_pair_rx/$text = $2;''/seo));
15332     $after = $_;
15333     while ($text =~ /(\\[a-zA-Z]+|[&;]SPM\w+;)/ ) {
15334         $next = $`;
15335         $special = $&;
15336         $text = $';
15337         $next =~ tr /A-Z/a-z/ if ($next);
15338         $done .= $next . $special;
15339     }
15340     $text =~ tr /A-Z/a-z/ if ($text);
15341     $done .= $text;
15342     $done = &convert_iso_latin_chars($done) if ($done);
15343     join('',$done,$after);
15346 sub do_cmd_MakeUppercase { &do_cmd_uppercase(@_) }
15347 sub do_cmd_MakeLowercase { &do_cmd_lowercase(@_) }
15351 sub do_cmd_ensuremath {
15352     local($_) = @_;
15353     local ($id, $value);
15354     $value = &missing_braces unless (
15355         (s/$next_pair_pr_rx/$value=$2;''/eo)
15356         ||(s/$next_pair_rx/$value=$2;''/eo));
15357     join('', &simple_math_env($value), $');
15361 #  This is mainly for \special{header=PostScript_Prologue},
15362 #       and \graphicspath{path} which occur OUTSIDE of an environment
15363 #       passed to TeX.  \special's INSIDE such environments are, of
15364 #       course, left alone.
15366 sub do_cmd_special {
15367     local($_) = @_;
15368     local ($id, $value);
15369     $value = &missing_braces unless (
15370         (s/$next_pair_pr_rx/$value=$2;''/eo)
15371         ||(s/$next_pair_rx/$value=$2;''/eo));
15372     local($special_cmd) = &revert_to_raw_tex($value);
15373     &add_to_preamble($cmd,"\\$cmd\{$special_cmd\}");
15374     $_;
15378 ########################## Input and Include commands #########################
15380 sub do_cmd_input {
15381     local($_) = @_;
15382     local($file,$output);
15383     (s/\s*(.*)\s*\n/$file =$1;''/s) unless (
15384         (s/$next_pair_pr_rx/$file=$2;''/eo)
15385         ||(s/$next_pair_rx/$file=$2;''/eo));
15386     local($after) = $_;
15387     $file = &revert_to_raw_tex("\\input{$file}\n") if $file;
15388     if ($PREAMBLE) { &add_to_preamble('include',$file)}
15389     elsif (!($file=~/^\s*$/)) {
15390         $output = &process_undefined_environment('center'
15391                 , ++$global{'max_id'},"\\vbox{$file}");
15392     }
15393     $output.$after;
15396 sub do_cmd_include {
15397     local($_) = @_;
15398     local($file,$output);
15399     $file = &missing_braces unless (
15400         (s/$next_pair_pr_rx/$file=$2;''/eo)
15401         ||(s/$next_pair_rx/$file=$2;''/eo));
15402     local($after) = $_;
15403     $file = &revert_to_raw_tex("\\include{$file}\n") if $file;
15404     if ($PREAMBLE) { &add_to_preamble('include',$file)}
15405     else {
15406         $output = &process_undefined_environment('figure'
15407                 , ++$global{'max_id'},"\\vbox{$file}");
15408     }
15409     $output.$after;
15412 ########################## Messages #########################
15414 sub do_cmd_message {
15415     local($_) = @_;
15416     local($message);
15417     $message = &missing_braces unless (
15418         (s/$next_pair_pr_rx/$message=$2;''/eo)
15419         ||(s/$next_pair_rx/$message=$2;''/eo));
15420     local($after) = $_;
15421     $message = &translate_commands($message);
15422     $message =~ s/$comment_mark(\d+)//og;
15423     print STDOUT "\n*** $message ***\n";
15424     $after;
15427 sub do_cmd_typeout {
15428     print STDOUT "\n";
15429     local($_) = &do_cmd_message(@_);
15430     print STDOUT "\n";
15431     $_;
15434 sub do_cmd_expandafter {
15435     local($_) = @_;
15436     print "\nEXPANDAFTER: " if ($VERBOSITY >3);
15437     return($_) unless (s/^\s*(\\\w+)\s*\\//o);
15438     print " delaying $1 " if ($VERBOSITY >3);
15439     local($delay,$cmd) = ($1,'');
15440     s/^(\w+|\W)/$cmd=$1;''/eo;
15441     local($nextcmd) = "do_cmd_$cmd";
15442     if (defined &$nextcmd) { $_ = &$nextcmd($_) }
15443     elsif ($new_command{$cmd}) { 
15444         local($argn, $body, $opt) = split(/:!:/, $new_command{$cmd});
15445         do { ### local($_) = $body;
15446             &make_unique($body);
15447         } if ($body =~ /$O/);
15448         if ($argn) {
15449             do {
15450                 local($before) = '';
15451                 local($after) = "\\$cmd ".$_;
15452                 $after = &substitute_newcmd;   # may change $after
15453                 $after =~ s/\\\@#\@\@/\\/o unless ($after);
15454             };
15455         } else { $_ = $body . $_; }
15456     } else { print "\nUNKNOWN COMMAND: $cmd "; }
15458     # now put the delayed function back for processing
15459     join('',$delay, " ", $_);
15462 sub do_cmd_tracingall {
15463     print "\nTRACING:\n$ref_contents\n$after\n";
15464     $VERBOSITY = 8; ""; }
15466 sub do_cmd_htmltracenv { &do_cmd_htmltracing }
15468 sub do_cmd_htmltracing {
15469     local($_) = @_;
15470     local($value);
15471     $value = &missing_braces
15472         unless ((s/$next_pair_rx/$value = $2;''/eo)
15473             ||(s/$next_pair_pr_rx/$value = $2;''/eo));
15474     if ($value =~ /^\s*(\d+)\s*$/) { 
15475         $VERBOSITY = $1;
15476         if ($VERBOSITY) { 
15477             print "\n\n *** setting trace-level to $VERBOSITY ***\n";
15478         } else {
15479             print "\n\n *** cancelling all tracing ***\n\n";
15480         }
15481     } else {
15482         &write_warnings("argument to \\htmltracing must be a number");
15483      }
15484     $_ ;
15488 ############################ Initialization ####################################
15490 sub initialise {
15491     ############################ Global variables ###############################
15492     $PREAMBLE = 2;              # 1 while translating preamble, 0 while translating body 
15493     $NESTING_LEVEL = undef;     #counter for TeX group nesting level
15494     $OUT_NODE = 0;              # Used in making filenames of HTML nodes unique
15495     $eqno_prefix = '';          # default prefix on equation numbers
15496     ($O , $C, $OP, $CP) = ('<<' , '>>', '<#', '#>'); # Open/Close Markers
15497     $href_name = 0;             # Used in the HREF NAME= field
15498     $wrap_toggle = 'end';
15499     $delim = '%:%';             # Delimits items of sectioning information
15500                                 # stored in a string
15502     $LATEX2HTML_META = '<META NAME="Generator" CONTENT="LaTeX2HTML v'.$TEX2HTMLV_SHORT.'">'
15503         . "\n<META HTTP-EQUIV=\"Content-Style-Type\" CONTENT=\"text/css\">"
15504               unless ($LATEX2HTML_META);
15506     $TeXname = (($HTML_VERSION ge "3.0")? "T<SMALL>E</SMALL>X" : "TeX");
15507     $Laname = (($HTML_VERSION ge "3.0")? "L<SUP><SMALL>A</SMALL></SUP>" : "La");
15508     $MFname = (($HTML_VERSION ge "3.0")? "M<SMALL>ETAFONT</SMALL>" : "Metafont");
15509     $Xyname = (($HTML_VERSION ge "3.0")? "X<SUB><BIG>Y</BIG></SUB>" : "Xy");
15510     $AmSname = (($HTML_VERSION ge "3.0")? "A<SUB><BIG>M</BIG></SUB>S" : "AmS");
15512     $EQN_TAGS = "R" unless ($EQN_TAGS);
15513     $EQNO_START = "(";
15514     $EQNO_END   = ")";
15516     $AtBeginDocument_hook  = "\$AtBeginDocument_hook\=\'\'; "
15517         unless $AtBeginDocument_hook;
15518     $cross_ref_mark = '<tex2html_cr_mark>';
15519     $external_ref_mark = '<tex2html_ext_cr_mark>';
15520     $cite_mark = '<tex2html_cite_mark>';
15521     $hash_mark = '<tex2html_hash_mark>';
15522     $protected_hash = '<tex2html_protected_hash>';
15523     $param_mark = '<tex2html_param_mark>';
15524     $bbl_mark = '<tex2html_bbl_mark>';
15525     $toc_mark = '<tex2html_toc_mark>';
15526     $lof_mark = '<tex2html_lof_mark>';
15527     $lot_mark = '<tex2html_lot_mark>';
15528     $info_page_mark = '<tex2html_info_page_mark>';
15529     $info_title_mark = '<tex2html_info_title_mark>';
15530     $init_file_mark = '<tex2html_init_file_mark>';
15531     $childlinks_on_mark = '<tex2html_childlinks_mark>';
15532     $childlinks_null_mark = '<tex2html_childlinks_null_mark>';
15533     $childlinks_mark = $childlinks_on_mark;
15534     $more_links_mark = '<tex2html_morelinks_mark>';
15535     $idx_mark = '<tex2html_idx_mark>';
15536     $verbatim_mark = '<tex2html_verbatim_mark>';
15537     $unfinished_mark = '<tex2html_unfinished_mark>';
15538     $verb_mark = '<tex2html_verb_mark>';
15539     $verbstar_mark = '<tex2html_verbstar_mark>';
15540     $image_mark = '<tex2html_image_mark>';
15541     $mydb_mark =  '<tex2html_mydb_mark>';
15542     $percent_mark = '<tex2html_percent_mark>';
15543     $ampersand_mark = '<tex2html_ampersand_mark>';
15544     $dol_mark = '<tex2html_lone_dollar>';
15545     $comment_mark = '<tex2html_comment_mark>';
15546     $caption_mark = '<tex2html_caption_mark>';
15547     $array_col_mark = '<tex2html_col_mark>';
15548     $array_row_mark = '<tex2html_row_mark>';
15549     $array_text_mark = '<tex2html_text_mark>';
15550     $array_mbox_mark = '<tex2html_mbox_mark>';
15552     $bibitem_counter = 0;
15553     $undef_mark = '<tex2html_undef_mark>';
15554     $file_mark = '<tex2html_file>';
15555     $endfile_mark = '<tex2html_endfile>';
15557     # This defines textual markers for all the icons
15558     # e.g. $up_visible_mark = '<tex2html_up_visible_mark>';
15559     # They will be replaced with the real icons at the very end.
15560     foreach $icon (keys %icons) {eval "\$$icon = '<tex2html_$icon>'"};
15562     # Make sure $HTML_VERSION is in the right range and in the right format.
15563 #    $HTML_VERSION =~ /[\d.]*/;
15564 #    $HTML_VERSION = 0.0 + $&;
15565 #    $HTML_VERSION = 2 if ( $HTML_VERSION < 2 );
15566 #    $HTML_VERSION = 9 if ( $HTML_VERSION > 9 );
15567 #    $HTML_VERSION = sprintf("%3.1f",$HTML_VERSION);
15569     &banner();
15570     print "Revised and extended by:"
15571         . "\n Marcus Hennecke, Ross Moore, Herb Swan and others\n";
15573     # Collect HTML options and figure out HTML version
15574     $HTML_OPTIONS = '' unless ($HTML_OPTIONS);
15575     $HTML_VERSION =~ s/^html|\s+//g;
15576     local(@HTML_VERSION) = split(/,/, $HTML_VERSION);
15577     foreach ( @HTML_VERSION ) {
15578         if (/^[\d\.]+$/) {
15579             # Make sure $HTML_VERSION is in the right range and in the right format.
15580             $HTML_VERSION = 0.0 + $_;
15581             $HTML_VERSION = 2 if ( $HTML_VERSION < 2 );
15582             $HTML_VERSION = 9 if ( $HTML_VERSION > 9 );
15583             $HTML_VERSION = sprintf("%3.1f",$HTML_VERSION);
15584         } else {
15585             $HTML_OPTIONS .= "$_,";
15586         }
15587     }
15588     $HTML_OPTIONS =~ s/\W$//;  # remove any trailing punctuation
15590     print "...producing markup for HTML version $HTML_VERSION  ";
15591     print ($HTML_OPTIONS ? "with $HTML_OPTIONS extensions\n\n\n" : "\n\n\n");
15593     # load the character defs for latin-1, but don't set the charset yet
15594     &do_require_extension('latin1');
15595     $charset = $CHARSET = $PREV_CHARSET = '';
15597     if ($HTML_VERSION =~ /(2.0|3.0|3.2|4.0|4.1)/) {
15598         # Require the version specific file 
15599         do { $_ = "$LATEX2HTMLVERSIONS${dd}html$1.pl";
15600              if (!(-f $_)) {  s/(\d).(\d.pl)$/$1_$2/ };
15601              if (!(-f $_)) {  s/(\d)_(\d.pl)$/$1-$2/ };
15602              require $_ || die "\n*** Could not load $_ ***\n";
15603              print "\nHTML version: loading $_\n";
15604         } unless ($HTML_VERSION =~ /2.0/);
15605         $DOCTYPE = "-//".(($HTML_VERSION eq "2.0")? "IETF" : "W3C")
15606             . "//DTD HTML $HTML_VERSION"
15607             .(($HTML_VERSION eq "3.2")? " Final" : "")
15608             .(($HTML_VERSION eq "4.0")? " Transitional" : "");
15610         if ($HTML_OPTIONS) {
15611             local($ext);
15612             local($loading_extensions) = 1;
15613             # Require the option specific files 
15614             @HTML_VERSION = split(/,/, $HTML_OPTIONS);
15615             foreach $ext ( @HTML_VERSION ) {
15616                 &do_require_extension($ext);
15617 #               do {
15618 #                   print "\nLoading $LATEX2HTMLVERSIONS$dd$ext.pl";
15619 #                   require "$LATEX2HTMLVERSIONS$dd$ext.pl";
15620 #               } if (-f "$LATEX2HTMLVERSIONS$dd$ext.pl");
15621             }
15622             undef $loading_extensions;
15623         }
15624     } else {
15625         print "\n You specified an invalid version: $HTML_VERSION\n"
15626             . "In future please request extensions by name:\n"
15627             . "  i18n  table  math  frame  latin1  unicode  etc.\n";
15629     # Require all necessary version specific files
15630         foreach ( sort <$LATEX2HTMLVERSIONS${dd}html[1-9].[0-9].pl> ) {
15631             last if ( $_ gt "$LATEX2HTMLVERSIONS${dd}html$HTML_VERSION.pl" );
15632             do { print "\nloading $_" if ($DEBUG);
15633                  require $_; } unless (
15634                 ($NO_SIMPLE_MATH)&&($_ eq "$LATEX2HTMLVERSIONS${dd}html3.1.pl"));
15635         };
15636         $STRICT_HTML = 0;
15637     }
15639     # packages automatically implemented, or clearly irrelevant
15640     %styles_loaded = 
15641      ( 'theorem' , 1 , 'enumerate', 1 , 'a4paper' , 1 , 'b5paper' , 1
15642      , '10pt' , 1 , '11pt' , 1 , '12pt' , 1
15643      , %styles_loaded );
15646     %declarations =
15647     ('em' , '<EM></EM>',
15648      'it' , '<I></I>',
15649      'bf' , '<B></B>',
15650      'tt' , '<TT></TT>',
15651      'sl' , '<I></I>',          # Oops!
15652      'sf' , '<I></I>',          # Oops!
15653      'rm' ,  '<></>',
15654      'rmfamily'   ,'<></>',     # see $fontchange_rx
15655      'normalfont' ,'<></>',     # see $fontweight_rx and $fontchange_rx
15656      'mdseries'   ,'<></>',     # see $fontweight_rx
15657      'upshape'    ,'<></>',     # see $fontchange_rx
15658      'itshape' ,  '<I></I>',
15659      'bfseries' , '<B></B>',
15660      'ttfamily' , '<TT></TT>',
15661      'slshape' ,  '<I></I>',    # Oops!
15662      'sffamily' , '<I></I>',    # Oops!
15663 ##     'scshape' ,  '<I></I>',  # Oops!
15664 #     'boldmath' , '<B></B>',
15665 #     'quote', '<BLOCKQUOTE></BLOCKQUOTE>',
15666 #     'quotation', '<BLOCKQUOTE></BLOCKQUOTE>',
15667      %declarations      # Just in case someone extends it in the init file
15668      );
15671 %declarations = (
15672      'tiny', '<FONT SIZE="-2"></FONT>',
15673      'Tiny', '<FONT SIZE="-2"></FONT>',
15674      'scriptsize', '<FONT SIZE="-2"></FONT>',
15675      'small', '<FONT SIZE="-1"></FONT>',
15676      'Small', '<FONT SIZE="-1"></FONT>',
15677      'SMALL', '<FONT SIZE="-1"></FONT>',
15678      'smaller', '<SMALL></SMALL>',
15679      'footnotesize', '<FONT SIZE="-1"></FONT>',
15680      'larger', '<BIG></BIG>',
15681      'large', '<FONT SIZE="+1"></FONT>',
15682      'Large', '<FONT SIZE="+2"></FONT>',
15683      'LARGE', '<FONT SIZE="+2"></FONT>',
15684      'huge', '<FONT SIZE="+3"></FONT>',
15685      'Huge', '<FONT SIZE="+4"></FONT>',
15686 #     'centering', '<DIV ALIGN="CENTER"></DIV>',
15687 #     'center', '<DIV ALIGN="CENTER"></DIV>',
15688 #     'flushleft', '<DIV ALIGN="LEFT"></DIV>',
15689 #     'raggedright', '<DIV ALIGN="LEFT"></DIV>',
15690 #     'flushright', '<DIV ALIGN="RIGHT"></DIV>',
15691 #     'raggedleft', '<DIV ALIGN="RIGHT"></DIV>',
15692      %declarations
15693     ) if ($HTML_VERSION > 2.0 );
15695 #  no alignment in HTML 2.0
15696 #%declarations = (
15697 #     'centering', '<P ALIGN="CENTER"></P>',
15698 #     'center', '<P ALIGN="CENTER"></P>',
15699 #     'flushleft', '<P ALIGN="LEFT"></P>',
15700 #     'raggedright', '<P ALIGN="LEFT"></P>',
15701 #     'flushright', '<P ALIGN="RIGHT"></P>',
15702 #     'raggedleft', '<P ALIGN="RIGHT"></P>',
15704 %declarations = (
15705 #     'centering', '<P></P>',
15706      'center', '<P></P>',
15707      'flushleft', '<P></P>',
15708      'raggedright', '<P></P>',
15709      'flushright', '<P></P>',
15710      'raggedleft', '<P></P>',
15711      'quote', '<BLOCKQUOTE></BLOCKQUOTE>',
15712      'quotation', '<BLOCKQUOTE></BLOCKQUOTE>',
15713      'verse', '<BLOCKQUOTE></BLOCKQUOTE>',
15714      'preform', '<PRE></PRE>',
15715      'unord', '<UL></UL>',
15716      'ord', '<OL></OL>',
15717      'desc', '<DL></DL>',
15718      'list', '',
15719      'par', '<P></P>'
15720     ) if ($HTML_VERSION == 2.0 );
15722     &generate_declaration_subs; # Generate code to handle declarations
15724     # ...but these block-level divisions must be handled differently...
15725 %declarations = (
15726      'quote', '<BLOCKQUOTE></BLOCKQUOTE>',
15727      'quotation', '<BLOCKQUOTE></BLOCKQUOTE>',
15728      'verse', '<BLOCKQUOTE></BLOCKQUOTE>',
15729      'preform', '<PRE></PRE>',
15730      'unord', '<UL></UL>',
15731      'ord', '<OL></OL>',
15732      'desc', '<DL></DL>',
15733 #     'list', '<DIV></DIV>',
15734      'par', '<P></P>',
15735      'samepage', '',
15736 #     'centering', '<DIV ALIGN="CENTER"></DIV>',
15737      'center', '<DIV ALIGN="CENTER"></DIV>',
15738      'flushleft', '<DIV ALIGN="LEFT"></DIV>',
15739      'raggedright', '<DIV ALIGN="LEFT"></DIV>',
15740      'flushright', '<DIV ALIGN="RIGHT"></DIV>',
15741      'raggedleft', '<DIV ALIGN="RIGHT"></DIV>',
15742      %declarations
15743     ) if ($HTML_VERSION > 2.0 );
15746     %section_commands =
15747         ('partstar' , '1' , 'chapterstar', '2', 'sectionstar', '3'
15748         , 'subsectionstar', '4', 'subsubsectionstar', '5', 'paragraphstar'
15749         , '6', 'subparagraphstar', '7'
15750         , 'part' , '1' , 'chapter', '2', 'section', '3','subsection', '4'
15751         , 'subsubsection', '5', 'paragraph', '6', 'subparagraph', '7'
15752         , 'slidehead', '3', %section_commands);
15753     # The tableofcontents, listoffigures, listoftables, bibliography and
15754     # textohtmlindex are set after determining what is the outermost level
15755     # in sub set_depth_levels. Appendix is implemented as a command.
15757     %standard_section_headings =
15758         ('part' , 'H1' , 'chapter' , 'H1', 'section', 'H1', 'subsection', 'H2'
15759         , 'subsubsection', 'H3', 'paragraph', 'H4', 'subparagraph', 'H5'
15760         , %standard_section_headings );
15762     # Generates code to handle sectioning commands
15763     # for those sections which take an argument.
15764     &generate_sectioning_subs;
15766     %section_headings =
15767         ('partstar' , 'H1' , 'chapterstar' , 'H1', 'sectionstar', 'H1'
15768         , 'subsectionstar', 'H2', 'subsubsectionstar', 'H3', 'paragraphstar'
15769         , 'H4', 'subparagraphstar', 'H5', %section_headings);
15771     # These need their own custom code but are treated as sectioning commands
15772     %section_headings =
15773         ('tableofcontents', 'H2', 'listoffigures', 'H2', 'listoftables', 'H2'
15774         , 'bibliography', 'H2', 'textohtmlindex', 'H2'
15775         , %standard_section_headings
15776         , %section_headings);
15778     &generate_accent_commands;  # Code to handle accent commands
15780     # These are replaced as soon as the text is read in.
15781     %html_specials = (  '<', ';SPMlt;'
15782                 ,  '>', ';SPMgt;'
15783                 ,  '&', ';SPMamp;'
15784 #               ,  '``', '\lq\lq '  # probably not a good idea
15785 #               ,  "''", '\rq\rq ',  # probably not a good idea
15786                 ,  '"', ';SPMquot;'
15787                 );
15789     %html_specials = ( %html_specials
15790                 , '``', ';SPMldquo;', "''", ';SPMrdquo;'
15791                 ) if ($HTML_VERSION >= 5 );
15793     # This mapping is needed in sub revert_to_raw_tex
15794     # before passing stuff to latex for processing.
15795     %html_specials_inv = (
15796                  ';SPMlt;' ,'<'
15797                 , ';SPMgt;','>'
15798                 , ';SPMamp;','&'
15799                 , ';SPMquot;','"'
15800                 , ';SPMldquo;','``'
15801                 , ';SPMrdquo;',"''"
15802                 , ';SPMdollar;', '$'    # for alltt
15803                 , ';SPMpct;', '%'
15804                 , ';SPMtilde;', '&#126;'
15805                 );
15807     # normalsize vertical dimension factors for 12pt (1.0 <=> <BR>)
15808     %vspace_12pt = ('ex', 1.0, 'em', 1.0, 'pt', 0.1, 'pc', 1.0,
15809         'in', 6.0, 'bp', 0.1, 'cm', 2.3, 'mm', 0.2, 'dd', 0.1,
15810         'cc', 1.0, 'sp', 0.0);
15812     # For some commands such as \\, \, etc it is not possible to define
15813     # perl subroutines because perl does not allow some non-ascii characters
15814     # in subroutine names. So we define a table and a subroutine to relate
15815     # such commands to ascii names.
15816     %normalize = ('\\', 'd_backslash'
15817                   , '/', 'esc_slash', "`", 'grave'
15818                   , "'", 'acute', "^", 'hat', '"', 'ddot'
15819                   , '~', 'tilde', '.', 'dot', '=', 'bar'
15820                   , '{', 'lbrace' , '}', 'rbrace', '|', 'Vert'
15821                   , '#', 'esc_hash', '$', 'esc_dollar'
15822                  );
15824     %text_accent = (  'cedil','c', 'bdot','d', 'b','b' , 'tilde','~'
15825                     , 'circ' ,'^', 'hat','^', 'check','v' , 'caron','v'
15826                     , 'acute','\'' , 'grave','`' , 'dot','.' , 'breve','u'
15827                     , 'ddot','"' , 'uml','"' , 'bar','=','macr','='
15828                     , 'dblacc','H' , 't','t' , 'ogon','k' , 'ring','r'
15829                   );
15831     # %languages_translations holds for each known language the
15832     # appropriate translation function. The function is called in
15833     # slurp_input.
15834     # The translation functions subtitute LaTeX macros
15835     # with ISO-LATIN-1 character references
15836     %language_translations = (
15837            'english',   'english_translation'
15838          , 'USenglish', 'english_translation'
15839          , 'original',  'english_translation'
15840          , 'german',    'german_translation'
15841          , 'austrian',  'german_translation'
15842          , 'finnish',   'finnish_translation'
15843          , 'french',    'french_translation'
15844          , 'spanish',   'spanish_translation'
15845          , 'swedish',   'swedish_translation'
15846          , 'turkish',   'turkish_translation'
15847         );
15849 # Reiner: 
15850 #    $standard_label_rx = 
15851 #       "\\s*[[]\\s*(((\$any_next_pair_rx4)|([[][^]]*[]])|[^]])*)[]]";
15852 #    $enum_label_rx = "^((({[^{}]*})|([^{}]))*)([aAiI1])(.*)";
15853 #    $enum_level = 0;   # level for enumerate (1-4, i-iv)
15854     %enum = ( 
15855                 'enumi',        0,                      # counter for level 1
15856                 'enumii',       0,                      # counter for level 2
15857                 'enumiii',      0,
15858                 'enumiv',       0,
15859                 'theenumi',     "&arabic('enumi')",     # eval($enum{"theenumi"})
15860                 'theenumii',    "&alph('enumii')",
15861                 'theenumiii',   "&roman('enumiii')",
15862                 'theenumiv',    "&Alph('enumiv')",
15863                         # e.g. eval("$enum{'labelenumi'}")
15864                 'labelenumi',   'eval($enum{"theenumi"}) . "."', 
15865                 'labelenumii',  '"(" . eval($enum{"theenumii"}) . ")"', 
15866                 'labelenumiii', 'eval($enum{"theenumiii"}) . "."',
15867                 'labelenumiv',  'eval($enum{"theenumiv"}) . "."'
15868                 );
15870     %RomanI = ( '1',"I",'2',"II",'3',"III",'4',"IV"
15871                     ,'5',"V",'6',"VI",'7',"VII", '8',"VIII",'9',"IX");
15872     %RomanX = ( '1',"X",'2',"XX",'3',"XXX",'4',"XL"
15873                     ,'5',"L",'6',"LX",'7',"LXX", '8',"LXXX",'9',"XC");
15874     %RomanC = ( '1',"C",'2',"CC",'3',"CCC",'4',"CD"
15875                     ,'5',"D",'6',"DC",'7',"DCC", '8',"DCCC",'9',"CM");
15876     %RomanM = ( '1',"M",'2',"MM",'3',"MMM",'4',"MH"
15877                     ,'5',"H",'6',"HM",'7',"HMM",'8',"HMMM");
15879     %enum_label_funcs = ( 
15880         "a", "alph", "A", "Alph", "i", "roman", "I", "Roman", "1", "arabic" );
15882 sub farabic{
15883     local($_)=@_;
15884     $_;
15886 sub arabic{
15887     local($_)=@_;
15888     eval($enum{$_});
15891 sub falph{
15892     local($num)=@_;
15893 #    chr($num+64);
15894     substr(" abcdefghijklmnopqrstuvwxyz",$num,1)
15896 sub alph{
15897     local($num)=@_;
15898     &falph(eval($enum{$num}));
15900 sub fAlph{
15901     local($num)=@_;
15902 #    chr($num+32);
15903     substr(" ABCDEFGHIJKLMNOPQRSTUVWXYZ",$num,1)
15905 sub Alph{
15906     local($num)=@_;
15907     &falph(eval($enum{$num}));
15910 sub Roman{
15911     local($num)=@_;
15912     &fRoman(eval($enum{$num}));
15914 sub fRoman{
15915     local($num)=@_;
15916     local($RmI)= $num%10; ($RmI) = (($RmI) ? $RomanI{"$RmI"} : '' );
15917     $num = $num/10; local($RmX)= $num%10; ($RmX) = (($RmX) ? $RomanX{"$RmX"} : '' );
15918     $num = $num/10; local($RmC)= $num%10; ($RmC) = (($RmC) ? $RomanC{"$RmC"} : '' );
15919     $num = $num/10; local($RmM)= $num%10; ($RmM) = (($RmM) ? $RomanM{"$RmM"} : '' );
15920     "$RmM" . "$RmC" . "$RmX" . "$RmI";
15922 sub froman{
15923     local($_)=@_;
15924     $_ = &fRoman($_);
15925     $_ =~ tr/A-Z/a-z/;
15926     $_;
15928 sub roman{
15929     local($num)=@_;
15930     &froman(eval($enum{$num}));
15934     %unitscale = ("in",72,"pt",72.27/72,"pc",12,"mm",72/25.4,"cm",72/2.54
15935                   ,"\\hsize",100,"\\vsize",100
15936                   ,"\\textwidth",100,"\\textheight",100
15937                   ,"\\pagewidth",100,"\\linewidth",100
15938                   );
15939     %units = ("in","in","pt","pt","pc","pi","mm","mm","cm","cm"
15940               ,"\\hsize","%","\\vsize","%","\\textwidth","%","\\textheight","%");
15942 sub convert_length { # clean
15943     my ($this,$scale) = @_;
15944     $scale = 1 unless $scale;
15945     my ($pxs,$len,$full);
15946     if ( $this =~ /([\d.]*)\s*(in|pt|pc|mm|cm|\\[hv]size|\\\w+(width|height))?/ ) {
15947         $len = ($1 ? $1 : 1); $full = $2;
15948         if ($full &&($full =~ /\\([hv]size|\w+(width|height))/)) { $scale = 1;};
15949         $pxs = (($full) ? int($len * $unitscale{$full}*$scale + 0.5)
15950                  : int($len*$scale + .5) );
15951         if ( $full =~ /\\([hv]size|\w+(width|height))/) { $pxs .= '%';};
15952     };
15953     ($pxs,$len);
15959     # Inclusion in this list will cause a command or an environment to be ignored.
15960     # This is suitable for commands without arguments and for environments.
15961     # If however a do_env|cmd_<env|cmd> exists then it will be used.
15962     %ignore = ('sloppypar', 1,  'document', 1, 'newblock', 1,
15963                ',', 1,  '@', 1, ' ', 1,  '-', 1,
15964                'sloppy', 1,
15965                'hyphen', 1, 'titlepage', 1, 'htmlonly', 1,
15966                'flushleft', 1, 'flushright', 1, 'slide', 1,
15967                'tiny', 1, 'Tiny', 1, 'scriptsize', 1, 'footnotesize', 1,
15968                'small', 1, 'normalsize', 1, 'large', 1, 'Large', 1,
15969                'LARGE', 1, 'huge', 1, 'Huge', 1,
15970                %ignore);
15972     # Specify commands with arguments that should be ignored.
15973     # Arbitrary code can be placed between the arguments
15974     # to be executed while processing the command.
15975     #
15976 # Note that some commands MAY HAVE ARGUMENTS WHICH SHOULD BE LEFT AS TEXT
15977     # EVEN THOUGH THE COMMAND IS IGNORED (e.g. hbox, center, etc)
15979 &ignore_commands( <<_IGNORED_CMDS_);
15980 NeedsTeXFormat # {} # []
15981 ProvidesClass # {} # []
15982 ProvidesFile # {} # []
15983 ProvidesPackage # {} # []
15984 abovedisplayskip # &ignore_numeric_argument
15985 abovedisplayshortskip # &ignore_numeric_argument
15986 addcontentsline # {} # {} # {}
15987 addtocontents # {} # {}
15988 addvspace # {} # &ignore_numeric_argument
15989 and
15990 and # \$_ = join(''," - ",\$_)
15991 backmatter
15992 baselineskip # &ignore_numeric_argument
15993 belowdisplayskip # &ignore_numeric_argument
15994 belowdisplayshortskip # &ignore_numeric_argument
15995 bibdata
15996 bibliographystyle # {}
15997 bibstyle # {}
15998 bigskipamount # &ignore_numeric_argument
15999 smallskipamount # &ignore_numeric_argument
16000 medskipamount # &ignore_numeric_argument
16001 center
16002 citation # {}
16003 citeauthoryear
16004 clearpage
16005 cline # {}
16006 #documentclass # [] # {}
16007 #documentstyle # [] # {}
16008 #end # {}
16009 enlargethispage # {}
16010 evensidemargin # &ignore_numeric_argument
16011 filecontents
16012 filbreak
16013 fil
16014 fill
16015 flushbottom
16016 fontsize # {} # {}
16017 footheight # &ignore_numeric_argument
16018 footskip  # &ignore_numeric_argument
16019 frontmatter
16020 fussy
16021 global
16022 goodbreak
16023 hbox
16024 headheight # &ignore_numeric_argument
16025 headsep # &ignore_numeric_argument
16026 hfil
16027 hfill
16028 hfuzz # &ignore_numeric_argument
16029 hline
16030 hspace # {} # \$_ = join(''," ",\$_)
16031 hspacestar # {} # \$_ = join(''," ",\$_)
16032 html
16033 ifcase
16034 ignorespaces
16035 indent
16036 itemindent # &ignore_numeric_argument
16037 itemsep # &ignore_numeric_argument
16038 labelsep # &ignore_numeric_argument
16039 labelwidth # &ignore_numeric_argument
16040 leavevmode
16041 leftmargin # &ignore_numeric_argument
16042 listparindent # &ignore_numeric_argument
16043 lower # &ignore_numeric_argument
16044 long
16045 mainmatter
16046 makebox # [] # []
16047 makeindex
16048 marginpar # {}
16049 marginparsep # &ignore_numeric_argument
16050 marginparwidth # &ignore_numeric_argument
16051 markboth # {} # {}
16052 markright # {}
16053 mathord
16054 mathbin
16055 mathindent # &ignore_numeric_argument
16056 mathrel
16057 mathop
16058 mathtt
16059 #mdseries
16060 newpage
16061 #newedboolean # {}
16062 #newedcommand # {} # [] # [] # {}
16063 #newedcounter # {} # []
16064 #newedenvironment # {} # [] # [] # {} # {}
16065 #newedtheorem # {} # [] # {} # []
16066 #providedcommand # {} # [] # [] # {}
16067 #renewedcommand # {} # [] # [] # {}
16068 #renewedenvironment # {} # [] # [] # {} # {}
16069 nobreakspace # \$_ = join('',";SPMnbsp;",\$_)
16070 nonbreakingspace # \$_ = join('',";SPMnbsp;",\$_)
16071 noalign
16072 nobreak
16073 nocite # {}
16074 noindent
16075 nolinebreak# []
16076 nopagebreak #[]
16077 normalmarginpar
16078 numberline
16079 oddsidemargin # &ignore_numeric_argument
16080 omit
16081 onecolumn
16082 outer
16083 pagenumbering #{}
16084 pagestyle # {}
16085 parindent # &ignore_numeric_argument
16086 parsep # &ignore_numeric_argument
16087 parskip # &ignore_numeric_argument
16088 partopsep # &ignore_numeric_argument
16089 penalty # &ignore_numeric_argument
16090 phantom # {}
16091 protect
16092 raggedright
16093 raggedbottom
16094 raise # &ignore_numeric_argument
16095 raisebox # {} # [] # []
16096 relax
16097 reversemarginpar
16098 rightmargin # &ignore_numeric_argument
16099 #rmfamily
16100 rule # [] # {} # {}
16101 samepage
16102 selectfont
16103 startdocument # \$SEGMENT=1;\$SEGMENTED=1; \$_
16104 strut
16105 suppressfloats # []
16106 textheight # &ignore_numeric_argument
16107 textwidth # &ignore_numeric_argument
16108 textnormal
16109 #textrm
16110 textup
16111 theorempreskipamount # &ignore_numeric_argument
16112 theorempostskipamount # &ignore_numeric_argument
16113 thispagestyle # {}
16114 topmargin # &ignore_numeric_argument
16115 topsep # &ignore_numeric_argument
16116 topskip # &ignore_numeric_argument
16117 twocolumn
16118 unskip
16119 #upshape
16120 vfil
16121 vfill
16122 vfilll
16123 vline
16124 _IGNORED_CMDS_
16126     # Commands which need to be passed, ALONG WITH THEIR ARGUMENTS, to TeX.
16127     # Note that this means that the arguments should *not* be translated,
16128     # This is handled by wrapping the commands in the dummy tex2html_wrap
16129     # environment before translation begins ...
16131     # Also it can be used to specify environments which may be defined
16132     # using do_env_* but whose contents will be passed to LaTeX and
16133     # therefore should not be translated.
16134     # Note that this code squeezes spaces out of the args of psfig;
16137     # Images are cropped to the minimum bounding-box for these...
16139 &process_commands_in_tex (<<_RAW_ARG_CMDS_);
16140 psfig # {} # \$args =~ s/ //g;
16141 usebox # {}
16142 framebox # [] # [] # {}
16143 _RAW_ARG_CMDS_
16145     # ... but these are set in a box to measure height/depth 
16146     # so that white space can be preserved in the images.
16148 &process_commands_inline_in_tex (<<_RAW_ARG_CMDS_);
16149 #etalchar # {} \$args =~ s/(.*)/\$\^\{\$1\}\\\$/o; 
16150 fbox # {}
16151 #frac # [] # {} # {}
16152 dag
16153 ddag
16158 textexclamdown
16159 textquestiondown
16160 textregistered
16161 textperiodcentered
16162 #textcircled # {}
16163 #raisebox # {} # [] # [] # {}
16164 _RAW_ARG_CMDS_
16168 # These are handled by wrapping the commands in the dummy tex2html_nowrap
16169 # environment before translation begins. This environment will be
16170 # stripped off later, when the commands are put into  images.tex  ...
16172 &process_commands_nowrap_in_tex (<<_RAW_ARG_NOWRAP_CMDS_);
16173 #begingroup
16174 #endgroup
16175 #bgroup
16176 #egroup
16177 errorstopmode
16178 nonstopmode
16179 scrollmode
16180 batchmode
16181 psfigurepath # {}
16182 pssilent
16183 psdraft
16184 psfull
16185 thinlines
16186 thicklines
16187 linethickness # {}
16188 hyphenation # {}
16189 hyphenchar # \\ # &get_numeric_argument
16190 hyphenpenalty # &get_numeric_argument
16191 #let # \\ # <<\\(\\W|\\w+)>>
16192 newedboolean # {}
16193 newedcommand # {} # [] # [] # {}
16194 newedcounter # {} # []
16195 newedenvironment # {} # [] # [] # {} # {}
16196 newedtheorem # {} # [] # {} # []
16197 #providedcommand # {} # [] # [] # {}
16198 #renewedcommand # {} # [] # [] # {}
16199 #renewedenvironment # {} # [] # [] # {} # {}
16200 DeclareMathAlphabet # {} # {} # {} # {} # {}
16201 SetMathAlphabet # {} # {} # {} # {} # {} # {}
16202 DeclareMathSizes # {} # {} # {} # {}
16203 DeclareMathVersion # {}
16204 DeclareSymbolFont # {} # {} # {} # {} # {}
16205 DeclareSymbolFontAlphabet # {} # {}
16206 DeclareMathSymbol # {} # {} # {} # {}
16207 SetSymbolFont # {} # {} # {} # {} # {} # {}
16208 DeclareFontShape # {} # {} # {} # {} # {} # {}
16209 DeclareFontFamily # {} # {} # {}
16210 DeclareFontEncoding # {} # {} # {}
16211 DeclareFontSubstitution # {} # {} # {} # {}
16212 mathversion # {}
16213 #newfont # {} # {}
16214 #normalfont
16215 #rmfamily
16216 #mdseries
16217 newlength # {}
16218 setlength # {} # {}
16219 addtolength # {} # {}
16220 settowidth # {}# {}
16221 settoheight # {} # {}
16222 settodepth # {} # {}
16223 newsavebox # {}
16224 savebox # {} # [] # {}
16225 sbox # {} # {}
16226 setbox # {}
16227 TagsOnLeft  # \$EQN_TAGS = \"L\" if \$PREAMBLE;
16228 TagsOnRight # \$EQN_TAGS = \"R\" if \$PREAMBLE;
16229 _RAW_ARG_NOWRAP_CMDS_
16232 &process_commands_wrap_deferred (<<_RAW_ARG_DEFERRED_CMDS_);
16233 alph # {}
16234 Alph # {}
16235 arabic # {}
16236 author # [] # {}
16237 boldmath
16238 unboldmath
16239 captionstar # [] # {}
16240 caption # [] # {}
16241 #endsegment # []
16242 #segment # [] # {} # {} # {}
16243 fnsymbol # {}
16244 footnote # [] # {}
16245 footnotemark # []
16246 footnotetext # [] # {}
16247 #thanks # {}
16248 roman # {}
16249 Roman # {}
16250 #mbox # {}
16251 parbox # [] # [] # [] # {} # {}
16252 #selectlanguage # [] # {}
16253 setcounter # {} # {}
16254 addtocounter # {} # {}
16255 stepcounter # {}
16256 refstepcounter # {}
16257 value # {}
16258 par
16259 hrule # &ignore_numeric_argument
16260 linebreak # []
16261 pagebreak # []
16262 newfont # {} # {}
16263 smallskip
16264 medskip
16265 bigskip
16266 centering
16267 raggedright
16268 raggedleft
16269 itshape
16270 #textit # {}
16271 upshape
16272 slshape
16273 #scshape
16274 rmfamily
16275 sffamily
16276 ttfamily
16277 mdseries
16278 bfseries
16279 #textbf # {}
16281 normalfont
16288 Tiny
16289 tiny
16290 scriptsize
16291 footnotesize
16292 small
16293 Small
16294 SMALL
16295 normalsize
16296 large
16297 Large
16298 LARGE
16299 huge
16300 Huge
16301 lowercase # {}
16302 uppercase # {}
16303 MakeLowercase # {}
16304 MakeUppercase # {}
16305 htmlinfo # []
16306 htmlinfostar # []
16307 tableofchildlinks # []
16308 tableofchildlinksstar # []
16309 tableofcontents
16310 listoffigures
16311 listoftables
16312 thepart
16313 thepage
16314 thechapter
16315 thesection
16316 thesubsection
16317 thesubsubsection
16318 theparagraph
16319 thesubparagraph
16320 theequation
16321 htmltracenv # {}
16322 HTMLsetenv # [] # {} # {}
16323 #newedboolean # {}
16324 #newedcounter # {} # []
16325 #newedcommand # {} # [] # [] # {}
16326 #newedtheorem # {} # [] # {} # []
16327 #newedenvironment # {} # [] # [] # {} # {}
16328 providedcommand # {} # [] # [] # {}
16329 renewedcommand # {} # [] # [] # {}
16330 renewedenvironment # {} # [] # [] # {} # {}
16331 url # {}
16332 htmlurl # {}
16333 latextohtml
16334 TeX
16335 LaTeX
16336 LaTeXe
16337 LaTeXiii
16340 AmS
16341 AmSTeX
16342 textcircled # {}
16343 _RAW_ARG_DEFERRED_CMDS_
16346 #rrm
16347 # implement the XBit-Hack for Apache servers, to handle
16348 # Server-Side Includes (SSIs) with .html filename extension
16350 sub check_htaccess {
16351     my $access_file = '.htaccess';
16352     my $has_access = '';
16353     local $_;
16354     print "\nChecking for .htaccess  file";
16355     if (-f $access_file) {
16356         print STDOUT " ... found";
16357         open(HTACCESS, "<$access_file");
16358         while (<HTACCESS>) {
16359             if (/^\s*XBitHack\s*on\s*$/) {
16360                 print STDOUT " with XBitHack on";
16361                 $has_access =1; last;
16362             };
16363         }
16364         print STDOUT "\n";
16365         close HTACCESS;
16366         return() if $has_access;
16367         open (HTACCESS, ">>$access_file");
16368         &write_warnings("appended to .htaccess in $DESTDIR");
16369     } else {
16370         open (HTACCESS, ">$access_file");
16371         chmod 0644, $access_file;
16372         &write_warnings("created .htaccess file in $DESTDIR");
16373     }
16374     print HTACCESS "\nXBitHack on\n";
16375     close HTACCESS;
16378 # This maps the HTML mnemonic names for the ISO-LATIN-1 character references
16379 # to their numeric values. When converting latex specials characters to
16380 # ISO-LATIN-1 equivalents I use the numeric values because this makes any
16381 # conversion back to latex (using revert_raw_tex) more reliable (in case
16382 # the text contains "&mnemonic_name"). Errors may occur if an environment
16383 # passed to latex (e.g. a table) contains the numeric values of character
16384 # references.
16386 # RRM: removed this portion; load from  latin1.pl instead
16387 #&do_require_extension('latin1');
16389 sub make_isolatin1_rx {
16390     local($list) = &escape_rx_chars(join($CD,(values %iso_8859_1_character_map_inv)));
16391     $list =~ s/$CD/|/g;
16392     $isolatin1_rx = "($list)";
16396     ################### Frequently used regular expressions ###################
16397     # $1 : preamble
16399     $preamble_rx = "(^[\\s\\S]*)(\\\\begin\\s*$O\\d+$C\\s*document\\s*$O\\d+$C|\\\\startdocument)";
16401     # \d (number) should sometimes also be a delimiter but this causes
16402     # problems with command names  that are allowed to contain numbers (eg tex2html)
16403     # \d is a delimiter with commands which take numeric arguments?
16404     # JCL: I can't see that. \tex2html is also no valid LaTeX (or TeX).
16405     # It is parsed \tex 2html, and \tex may take 2html as argument, but this
16406     # is invalid LaTeX. \d must be treated as delimiter.
16408 # JCL(jcl-del) - Characters to be treated as letters, everything else
16409 # is a delimiter.
16410     # internal LaTeX command separator, shouldn't be equal to $;
16411     $CD = "\001";
16412     &make_cmd_spc_rx; # determines space to follow a letter command
16413 #old    $delimiters = '\'\\s[\\]\\\\<>(=).,#;:~\/!-';
16414     $letters = 'a-zA-Z';
16415     $delimiter_rx = "([^$letters])";
16418     # liberalized environment names (white space, optional arg, interpunctuation signs etc.)
16419     # $1 : br_id, $2 : <environment>
16420     $begin_env_rx="(\\\\protect)?\\\\begin\\s*(\\[([^\\]]*)])?$O(\\d+)$C\\s*([^'[\\]\\\\#~]+)\\s*$O\\4$C";
16421     $begin_env_pr_rx="(\\\\protect)?\\\\begin\\s*(\\[([^\\]]*)])?$OP(\\d+)$CP\\s*([^'[\\]\\\\#~]+)\\s*$OP\\4$CP";
16423     $mbox_rx = "\\\\mbox\\s*";
16425     $match_br_rx = "\\s*$O\\d+$C\\s*";
16427     $opt_arg_rx = "\\s*\\[([^\\]]*)\\]\\s*";    # Cannot handle nested []s!
16428     $optional_arg_rx = "^\\s*\\[([^]]*)\\]";    # Cannot handle nested []s!
16430     $block_close_rx = "^<\\/(DIV|P|BLOCKQUOTE)>\$";
16431     $all_close_rx = "^<\\/(BODY|PRE|OL|UL|DL|FORM|ADDRESS)>\$";
16433     # Matches a pair of matching brackets
16434     # $1 : br_id
16435     # $2 : contents
16436     $next_pair_rx = "^[\\s%]*$O(\\d+)$C([\\s\\S]*)$O\\1$C($comment_mark\\d*\\n?)?";
16438     # will comments be a problem after these ???
16439     $any_next_pair_rx = "$O(\\d+)$C([\\s\\S]*)$O\\1$C";
16440     $any_next_pair_rx4 = "$O(\\d+)$C([\\s\\S]*)$O\\4$C";
16441     $any_next_pair_pr_rx4 = "$OP(\\d+)$CP([\\s\\S]*)$OP\\4$CP";
16442     $any_next_pair_rx5 = "$O(\\d+)$C([\\s\\S]*)$O\\5$C";
16443     $any_next_pair_rx6 = "$O(\\d+)$C([\\s\\S]*)$O\\6$C";
16445     # used for labels in {enumerate} environments
16446     $standard_label_rx = 
16447         "\\s*[[]\\s*((($any_next_pair_rx4)|([[][^]]*[]])|[^]])*)[]]";
16448     $enum_label_rx = "^((({[^{}]*})|([^{}]))*)([aAiI1])(.*)";
16449     $enum_level = 0;    # level for enumerate (1-4, i-iv)
16452     # Matches the \ensuremath command
16453     $enspair = "\\\\ensuremath\\s*" . $any_next_pair_rx;
16454 #    $enspair = "\\\\ensuremath\\s*$O(\\d+)$C([\\s\\S]*[\\\\\$&]+[\\s\\S]*)$O\\1$C";
16456     # Matches math comments, from  math.pl
16457     $math_verbatim_rx = "$verbatim_mark#math(\\d+)#";
16458     $mathend_verbatim_rx = "$verbatim_mark#mathend([^#]*)#";
16460     # Matches math array environments
16461     $array_env_rx = "array|cases|\\w*matrix";
16463     # initially empty; has a value in HTML 3.2 and 4.0
16464     $math_class = '' unless ($math_class);
16465     $eqno_class = '' unless ($eqno_class);
16467     # Matches to end-of-line and subsequent spaces
16468     $EOL = "[ \\t]*\\n?";
16470     # Matches wrapped \par command
16471     $par_rx = "\\n?\\\\begin(($O|$OP)\\d+($C|$CP))tex2html_deferred\\1\\\\par\\s\*"
16472         . "\\\\end(($O|$OP)\\d+($C|$CP))tex2html_deferred\\4\\n?";
16474     # $1 : br_id
16475     $begin_cmd_rx = "$O(\\d+)$C";
16477     # $1 : image filename prefix
16478     $img_rx = "(\\w*T?img\\d+)";
16480     # $1 : largest argument number
16481     $tex_def_arg_rx = "^[#0-9]*#([0-9])($O|$OP)";
16483     #   only some non-alphanumerics are allowed in labels,  Why?
16484     $label_rx = "[^\\w\.\\\-\\\+\\\:]";
16486 #JCL(jcl-del) - new face, see also &do_cmd_makeatletter et.al.
16487 #    $cmd_delims = q|-#,.~/\'`^"=\$%&_{}@|; # Commands which are also delimiters!
16488 #    $single_cmd_atletter_rx = "\\\\([a-zA-Z\\\@]+\\*?|[$cmd_delims]|\\\\)";
16489 #    $single_cmd_atother_rx = "\\\\([a-zA-Z]+\\*?|[$cmd_delims]|\\\\)";
16490     # $1 : declaration or command or newline (\\)
16491     &make_single_cmd_rx;
16494     # $1 : description in a list environment
16495     $item_description_rx =
16496 #       "\\\\item\\s*[[]\\s*((($any_next_pair_rx4)|([[][^]]*[]])|[^]])*)[]]";
16497         "\\\\item\\s*[[]\\s*((($any_next_pair_pr_rx4)|([[][^]]*[]])|[^]])*)[]]";
16499     $fontchange_rx = 'rm|em|it|sl|sf|tt|sc|upshape|normalfont';
16500     $fontweight_rx = 'bf|mdseries|normalfont';
16501     $colorchange_rx = "(text)?color\\s*(\#\\w{6})?";
16502     $sizechange_rx = 'tiny|Tiny|scriptsize|footnotesize|small|Small|SMALL' .
16503         '|normalsize|large|Large|LARGE|huge|Huge';
16505 #    $image_switch_rx = "makeimage";
16506     $image_switch_rx = "makeimage|scshape|sc";
16507     $env_switch_rx = "writetolatex";
16508     $raw_arg_cmds{'font'} = 1;
16510     # Matches the \caption command
16511     # $1 : br_id
16512     # $2 : contents
16513      $caption_suffixes = "lof|lot";
16514 #    $caption_rx = "\\\\caption\\s*([[]\\s*((($any_next_pair_rx5)|([[][^]]*[]])|[^]])*)[]])?$O(\\d+)$C([\\s\\S]*)$O\\8$C$EOL";
16516     $caption_rx = "\\\\(top|bottom|table)?caption\\s*\\\*?\\s*([[]\\s*((($any_next_pair_rx6)|([[][^]]*[]])|[^]])*)[]])?$O(\\d+)$C([\\s\\S]*)$O\\9$C$EOL";
16517     $caption_width_rx = "\\\\setlength\\s*(($O|$OP)\\d+($C|$CP))\\\\captionwidth\\1\\s*(($O|$OP)\\d+($C|$CP))([^>]*)\\4";
16519     # Matches the \htmlimage command
16520     # $1 : br_id
16521     # $2 : contents
16522     $htmlimage_rx = "\\\\htmlimage\\s*$O(\\d+)$C([\\s\\S]*)$O\\1$C$EOL";
16523     $htmlimage_pr_rx = "\\\\htmlimage\\s*$OP(\\d+)$CP([\\s\\S]*)$OP\\1$CP$EOL";
16525     # Matches the \htmlborder command
16526     # $1 : optional argument...
16527     # $2 : ...contents  i.e. extra attributes
16528     # $3 : br_id
16529     # $4 : contents i.e. width
16530     $htmlborder_rx = "\\\\htmlborder\\s*(\\[([^]]*)\\])?\\s*$O(\\d+)$C(\\d*)$O\\3$C$EOL";
16531     $htmlborder_pr_rx = "\\\\htmlborder\\s*(\\[([^]]*)\\])?\\s*$OP(\\d+)$CP(\\d*)$OP\\3$CP$EOL";
16533     # Matches a pair of matching brackets
16534     # USING PROCESSED DELIMITERS;
16535     # (the delimiters are processed during command translation)
16536     # $1 : br_id
16537     # $2 : contents
16538 #    $next_pair_pr_rx = "^[\\s%]*$OP(\\d+)$CP([\\s\\S]*)$OP\\1$CP";
16539     $next_pair_pr_rx = "^[\\s%]*$OP(\\d+)$CP([\\s\\S]*)$OP\\1$CP($comment_mark\\d*\\n?)?";
16540     $any_next_pair_pr_rx = "$OP(\\d+)$CP([\\s\\S]*)$OP\\1$CP($comment_mark\\d*\\n?)?";
16541     $next_token_rx = "^[\\s%]*(\\\\[A-Za-z]+|\\\\[^a-zA-Z]|.)";
16543     $HTTP_start = 'http:';
16545     # This will be used to recognise escaped special characters as such
16546     # and not as commands
16547     $latex_specials_rx = '[\$]|&|%|#|{|}|_';
16548     $html_escape_chars = '<>&';
16550     # This is used in sub revert_to_raw_tex before handing text to be processed
16551     # by latex.
16552     $html_specials_inv_rx = join("|", keys %html_specials_inv);
16554     # These are used for direct replacements in/from  ALT=... strings
16555     %html_special_entities = ('<','lt','>','gt','"','quot','&','amp');
16556     %html_spec_entities_inv = ('lt','<','gt','>','quot','"','amp','&');
16558     # This is also used in sub revert_to_raw_tex
16559     $character_entity_rx = '(&#(\d+);)';
16560     $named_entity_rx = '&(\w+);';
16562     #commands for altering theorem-styles
16563     $theorem_cmd_rx = 'theorem(style|(header|body)font)';
16566     # Matches a \begin or \end {tex2html_wrap}. Also used by revert_to_raw_tex
16567     $tex2html_wrap_rx = '\\\\(begin|end)\\s*\{\\s*(tex2html_(wrap|nowrap|deferred|nomath|preform|\\w*_inline)[_a-z]*|makeimage)\\s*\}'."($EOL)";
16568     $tex2html_deferred_rx = '\\\\(begin|end)(<<\\d+>>)tex2html_deferred\\2';
16569     $tex2html_deferred_rx2 = '\\\\(begin|end)(<<\\d+>>)tex2html_deferred\\4';
16570     $tex2html_envs_rx = "\\\\(begin|end)\\s*(($O|$OP)\\d+($C|$CP))\\s*(tex2html_(wrap|nowrap|deferred|nomath|preform|\w+_inline)[_a-z]*||makeimage)\\s*\\2";
16572     # The first empty parenthese pair is for non-letter commands.
16573     # $2: meta command, $4: delimiter (may be empty)  ignore the *-version distinction
16574 #    $meta_cmd_rx = "()\\\\(providecommand|renewcommand|renewenvironment|newcommand|newenvironment|newtheorem|newcounter|newboolean|newif|let)(([^$letters$cmd_spc])|$cmd_spcs_rx)";
16575     $meta_cmd_rx = "()\\\\(providecommand|renewcommand|renewenvironment|newcommand|newenvironment|newtheorem|newcounter|newboolean|newif|DeclareRobustCommand|DeclareMathOperator\\*?)\\\*?(([^$letters$cmd_spc])|$cmd_spcs_rx)";
16577     &make_counters_rx;
16579     # Matches a label command and its argument
16580     $labels_rx = "\\\\label\\s*$O(\\d+)$C([\\s\\S]*)$O\\1$C$EOL";
16581     $labels_rx8 = "\\\\label\\s*$O(\\d+)$C([\\s\\S]*)$O\\8$C$EOL";
16583     # Matches environments that should not be touched during the translation
16584 #   $verbatim_env_rx = "\\s*{(verbatim|rawhtml|LVerbatim)[*]?}";
16585     $verbatim_env_rx = "\\s*(\\w*[Vv]erbatim|rawhtml|imagesonly|tex2html_code)[*]?";
16586     $image_env_rx = "\\s*(picture|xy|diagram)[*]?";
16587     $keepcomments_rx = "\\s*(picture|makeimage|xy|diagram)[*]?";
16589     # names of different math environment types
16590     $display_env_rx = "displaymath|makeimage|eqnarray|equation";
16591     $inline_env_rx = "inline|indisplay|entity|xy|diagram";
16592     $sub_array_env_rx = "array|(small|\\w)\?matrix|tabular|cases";
16594     # Matches environments needing pre-processing for images
16595     $pre_processor_env_rx = "\\\\(begin|end)\\s*(($O|$OP|\{)\\d+($C|$CP|\}))pre_(\\w+)\\2";
16597     # Matches icon markers
16598     $icon_mark_rx = "<tex2html_(" . join("|", keys %icons) . ")>";
16600     $start_time = time;
16601     print STDOUT join(" ", "Starting at", $start_time, "seconds\n")
16602         if ($TIMING||$DEBUG||($VERBOSITY>2));
16604 }       # end of &initialise
16606 # Frequently used regular expressions with arguments
16607 sub make_end_env_rx {
16608     local($env) = @_;
16609     $env = &escape_rx_chars($env);
16610     "\\\\end\\s*$O(\\d+)$C\\s*$env\\s*$O\\1$C".$EOL;
16613 sub make_begin_end_env_rx {
16614     local($env) = @_;
16615     $env = &escape_rx_chars($env);
16616     "\\\\(begin|end)\\s*$O(\\d+)$C\\s*$env\\s*$O\\3$C(\\s*\$)?";
16619 sub make_end_cmd_rx {
16620     local($br_id) = @_;
16621     "$O$br_id$C";
16624 #JCL(jcl-del) - see also &tokenize.
16625 # Arrange commands into a regexp for tokenisation.
16626 # Any letter command will gobble spaces, but avoids to match
16627 # on ensuing letters (\foo won't match on \foox).
16628 # Any non-letter command retains spaces and matches always
16629 # by itself (\| matches \|... regardless of ...).
16631 # This all is a huge kludge. The commands names should stay fix,
16632 # regardless of changing catcodes. If we have \makeatletter,
16633 # and LaTeX2HTML marks \@foo, then \@foo will be expanded
16634 # properly before \makeatother, but does weird things on \@foo
16635 # after \makeatother (\@foo in LaTeX is then \@ and foo, which
16636 # isn't recognized as such).
16637 # The reason is that the text to match the command \@foo
16638 # in LaTeX mustn't be \@foo at all, because any text in LaTeX
16639 # is also attributed with the category codes.
16641 # But at least we have proper parsing of letter and non-letter
16642 # commands as long as catcoding won't upset LaTeX2HTML too much.
16644 sub make_new_cmd_rx {
16645     return("") if $#_ < 0; # empty regexp if list is empty!
16647     # We have a subtle treatment of ambivalent commands like
16648     # \@foo in situations depicted above!
16649     # Get every command that contains no letters ...
16650     local($nonlettercmds) =
16651         &escape_rx_chars(join($CD, grep(!/[$letters]/,@_)));
16652     # and every command that contains a letter
16653     local($lettercmds) =
16654         &escape_rx_chars(join($CD, grep(/[$letters]/,@_)));
16656     if (%renew_command) {
16657         local($renew);
16658         foreach $renew (keys %renew_command) {
16659             $lettercmds =~ s/(^|$CD)$renew//; }
16660         $lettercmds =~ s/^$CD$//;
16661     }
16663     # replace the temporary $CD delimiter (this enables eg. \| command)
16664     $nonlettercmds =~ s/$CD/|/g;
16665     $lettercmds =~ s/$CD/|/g;
16667     # In case we have no non-letter commands, insert empty parentheses
16668     # to align match strings.
16669     #
16670     $nonlettercmds =~ s/^\||\|$//g;
16671     $lettercmds =~ s/^\||\|$//g;
16672     local($rx) = (length($nonlettercmds) ? "\\\\($nonlettercmds)" : "");
16673     if (length($lettercmds)) {
16674         $rx .= ( length($rx) ? "|" : "()" );
16675         $rx .= "\\\\($lettercmds)(([^$letters$cmd_spc])|$cmd_spcs_rx|\$)";
16676     }
16677     # $1: non-letter cmd, $2: letter cmd, $4: delimiter
16678     # Eg. \\(\@|...|\+)|\\(abc|...|xyz)(([^a-zA-Z \t])|[ \t]+)
16679     # $1 and $2 are guaranteed to alternate, $4 may be empty.
16680     $rx;
16683 # Build a simple regexp to use after tokenisation for
16684 # faster translation.
16685 sub make_new_cmd_no_delim_rx {
16686     return("") if $#_ < 0; # empty regexp if list is empty!
16687     # Get every command that contains no letters ...
16688     local($_) = &escape_rx_chars(join($CD, @_));
16689     s/$CD/|/g;
16691     join('',"\\\\(",$_,")");
16695 #JCL(jcl-del) - new face: w/o arg (was 'begin' only), escapes env names
16696 sub make_new_env_rx {
16697     local($envs) = &escape_rx_chars(join($CD, keys %new_environment));
16698     $envs =~ s/$CD/|/g;
16699     length($envs) ? "\\\\begin\\s*$O(\\d+)$C\\s*($envs)\\s*$O\\1$C\\s*" : "";
16702 sub make_new_end_env_rx {
16703     local($envs) = &escape_rx_chars(join($CD, keys %new_environment));
16704     $envs =~ s/$CD/|/g;
16705     length($envs) ? "\\\\end\\s*$O(\\d+)$C\\s*($envs)\\s*$O\\1$C\\s*" : "";
16708 #JCL(jcl-del) - $delimiter_rx -> ^$letters
16709 # don't care for $cmd_spc_rx; space after sectioning commands
16710 # is unlikely and I don't want to try too much new things
16712 sub make_sections_rx {
16713     local($section_alts) = &get_current_sections;
16714     # $section_alts includes the *-forms of sectioning commands
16715     $sections_rx = "()\\\\($section_alts)(([^$letters$cmd_spc])|$cmd_spcs_rx|\$)";
16716 #    $sections_rx = "()\\\\($section_alts)([^$letters])";
16719 sub make_order_sensitive_rx {
16720     local(@theorem_alts, $theorem_alts);
16721     @theorem_alts = ($preamble =~ /\\newtheorem\s*{([^\s}]+)}/og);
16722     $theorem_alts = join('|',@theorem_alts);
16724 #  HWS: Added kludge to require counters to be more than 2 characters long
16725 #       in order to be flagged as order-sensitive.  This will permit equations
16726 #       with \theta to remain order-insensitive.  Also permit \alpha and
16727 #       the eqnarray* environment to remain order-insensitive.
16729     $order_sensitive_rx =
16730 #        "(equation|eqnarray[^*]|\\\\caption|\\\\ref|\\\\the[a-z]{2,2}[a-z]|\\\\stepcounter" .
16731         "(\\\\caption|\\\\ref|\\\\the[a-z]{2,2}[a-z]|\\\\stepcounter" .
16732         "|\\\\arabic|\\\\roman|\\\\Roman|\\\\alph[^a]|\\\\Alph|\\\\fnsymbol)";
16733     $order_sensitive_rx =~ s/\)/|$theorem_alts)/ if $theorem_alts;
16736 sub make_language_rx {
16737     local($language_alts) = join("|", keys %language_translations);
16738 #    $setlanguage_rx = "\\\\se(lec)?tlanguage\\s*{\\\\?($language_alts)}";
16739     $setlanguage_rx = "\\\\setlanguage\\s*{\\\\?($language_alts)}";
16740     $language_rx = "\\\\($language_alts)TeX";
16741     $case_change_rx = "(\\\\(expandafter|noexpand)\s*)?\\\\((Make)?([Uu]pp|[Ll]ow)ercase)\s*";
16744 sub addto_languages {
16745     local($lang) = @_;
16746     local($trans) = "main'".$lang.'_translation';
16747     if (defined &$trans) {
16748         $language_translations {$lang} = $lang.'_translation';
16749     }
16752 # JCL(jcl-del) - new rexexp type
16753 sub make_raw_arg_cmd_rx {
16754     # $1 or $2 : commands to be processed in latex (with arguments untouched)
16755     # $4 : delimiter
16756     $raw_arg_cmd_rx = &make_new_cmd_rx(keys %raw_arg_cmds);
16757     $raw_arg_cmd_rx;
16760 # There are probably more.
16761 # Interferences not checked out yet, thus in makeat... only.
16762 sub make_letter_sensitive_rx {
16763     $delimiter_rx = "([^$letters])";
16764     &make_sections_rx;
16765     &make_single_cmd_rx;
16766     &make_counters_rx;
16769 #JCL(jcl-del) - this could eat one optional newline, too.
16770 # But this might result in large lines... anyway, it *should* be
16771 # handled. A possible solution would be to convert adjacent newlines
16772 # into \par's in preprocessing.
16773 sub make_cmd_spc_rx {
16774     $cmd_spc = " \\t";
16775     $cmd_spc_rx = "[ \\t]*"; # zero or more
16776     $cmd_spcs_rx = "[ \\t]+"; # one or more
16779 sub make_single_cmd_rx {
16780     $single_cmd_rx = "\\\\([^$letters])|\\\\([$letters]+\\*?)(([^$letters$cmd_spc])|$cmd_spcs_rx|\n|\$)";
16783 sub make_counters_rx {
16784     # Matches counter commands - these are caught early and are appended to the
16785     # file that is passed to latex.
16786 #JCL(jcl-del) - $delimiter_rx -> ^$letters
16787     $counters_rx = "()\\\\(newcounter|addtocounter|setcounter|refstepcounter|stepcounter|arabic|roman|Roman|alph|Alph|fnsymbol)(([^$letters$cmd_spc])|$cmd_spcs_rx|\$)";
16791 # Creates an anchor for its argument and saves the information in
16792 # the array %index;
16793 # In the index the word will use the beginning of the title of
16794 # the current section (instead of the usual pagenumber).
16795 # The argument to the \index command is IGNORED (as in latex)
16796 sub make_index_entry { &make_real_index_entry(@_) }
16797 sub make_real_index_entry {
16798     local($br_id,$str) = @_;
16799     local($this_file) = $CURRENT_FILE;
16800     $TITLE = $saved_title if (($saved_title)&&(!($TITLE)||($TITLE eq $default_title)));
16801     # Save the reference
16802     $str = "$str###" . ++$global{'max_id'}; # Make unique
16803     $index{$str} .= &make_half_href($this_file."#$br_id");
16804     "<A NAME=\"$br_id\">$anchor_invisible_mark<\/A>";
16807 sub image_message { # clean
16808     print <<"EOF";
16810 To resolve the image conversion problems please consult
16811 the "Troubleshooting" section of your local User Manual
16812 or read it online at
16813    http://www-texdev.ics.mq.edu.au/l2h/docs/manual/
16815 EOF
16818 sub image_cache_message { # clean
16819    print <<"EOF";
16821 If you are having problems displaying the correct images with Mosaic,
16822 try selecting "Flush Image Cache" from "Options" in the menu-bar
16823 and then reload the HTML file.
16824 EOF
16827 __DATA__
16829 # start of POD documentation
16831 =head1 NAME
16833 latex2html - Translate LaTeX files to HTML (HyperText Markup Language)
16835 =head1 SYNOPSIS
16837 B<latex2html> S<[ B<-help> | B<-h> ]> S<[ B<-version> | B<-V> ]>
16839 B<latex2html> S<[ B<-split> I<num> ]>
16840 S<[ B<-link> I<num> ]>
16841 S<[ B<-toc_depth> I<num> ]>
16842 S<[ B<->(B<no>)B<toc_stars> ]>
16843 S<[ B<->(B<no>)B<short_extn> ]>
16844 S<[ B<-iso_language> I<lang> ]>
16845 S<[ B<->(B<no>)B<validate> ]>
16846 S<[ B<->(B<no>)B<latex> ]>
16847 S<[ B<->(B<no>)B<djgpp> ]>
16848 S<[ B<->(B<no>)B<fork> ]>
16849 S<[ B<->(B<no>)B<external_images> ]>
16850 S<[ B<->(B<no>)B<ascii_mode> ]>
16851 S<[ B<->(B<no>)B<lcase_tags> ]>
16852 S<[ B<->(B<no>)B<ps_images> ]>
16853 S<[ B<-font_size> I<size> ]>
16854 S<[ B<->(B<no>)B<tex_defs> ]>
16855 S<[ B<->(B<no>)B<navigation> ]>
16856 S<[ B<->(B<no>)B<top_navigation> ]>
16857 S<[ B<->(B<no>)B<buttom_navigation> ]>
16858 S<[ B<->(B<no>)B<auto_navigation> ]>
16859 S<[ B<->(B<no>)B<index_in_navigation> ]>
16860 S<[ B<->(B<no>)B<contents_in_navigation> ]>
16861 S<[ B<->(B<no>)B<next_page_in_navigation> ]>
16862 S<[ B<->(B<no>)B<previous_page_in_navigation> ]>
16863 S<[ B<->(B<no>)B<footnode> ]>
16864 S<[ B<->(B<no>)B<numbered_footnotes> ]>
16865 S<[ B<-prefix> I<output_filename_prefix> ]>
16866 S<[ B<->(B<no>)B<auto_prefix> ]>
16867 S<[ B<-long_titles> I<num> ]>
16868 S<[ B<->(B<no>)B<custom_titles> ]>
16869 S<[ B<-title>|B<-t> I<top_page_title> ]>
16870 S<[ B<->(B<no>)B<rooted> ]>
16871 S<[ B<-rootdir> I<output_directory> ]>
16872 S<[ B<-dir> I<output_directory> ]>
16873 S<[ B<-mkdir> ]>
16874 S<[ B<-address> I<author_address> | B<-noaddress> ]>
16875 S<[ B<->(B<no>)B<subdir> ]>
16876 S<[ B<-info> I<0> | I<1> | I<string> ]>
16877 S<[ B<->(B<no>)B<auto_link> ]>
16878 S<[ B<-reuse> I<num> | B<-noreuse> ]>
16879 S<[ B<->(B<no>)B<antialias_text> ]>
16880 S<[ B<->(B<no>)B<antialias> ]>
16881 S<[ B<->(B<no>)B<transparent> ]>
16882 S<[ B<->(B<no>)B<white> ]>
16883 S<[ B<->(B<no>)B<discard> ]>
16884 S<[ B<-image_type> I<type> ]>
16885 S<[ B<->(B<no>)B<images> ]>
16886 S<[ B<-accent_images> I<type> | B<-noaccent_images> ]>
16887 S<[ B<-style> I<style> ]>
16888 S<[ B<->(B<no>)B<parbox_images> ]>
16889 S<[ B<->(B<no>)B<math> ]>
16890 S<[ B<->(B<no>)B<math_parsing> ]>
16891 S<[ B<->(B<no>)B<latin> ]>
16892 S<[ B<->(B<no>)B<entities> ]>
16893 S<[ B<->(B<no>)B<local_icons> ]>
16894 S<[ B<->(B<no>)B<scalable_fonts> ]>
16895 S<[ B<->(B<no>)B<images_only> ]>
16896 S<[ B<->(B<no>)B<show_section_numbers> ]>
16897 S<[ B<->(B<no>)B<show_init> ]>
16898 S<[ B<-init_file> I<Perl_file> ]>
16899 S<[ B<-up_url> I<up_URL> ]>
16900 S<[ B<-up_title> I<up_title> ]>
16901 S<[ B<-down_url> I<down_URL> ]>
16902 S<[ B<-down_title> I<down_title> ]>
16903 S<[ B<-prev_url> I<prev_URL> ]>
16904 S<[ B<-prev_title> I<prev_title> ]>
16905 S<[ B<-index> I<index_URL> ]>
16906 S<[ B<-biblio> I<biblio_URL> ]>
16907 S<[ B<-contents> I<toc_URL> ]>
16908 S<[ B<-external_file> I<external_aux_file> ]>
16909 S<[ B<->(B<no>)B<short_index> ]>
16910 S<[ B<->(B<no>)B<unsegment> ]>
16911 S<[ B<->(B<no>)B<debug> ]>
16912 S<[ B<-tmp> I<path> ]>
16913 S<[ B<->(B<no>)B<ldump> ]>
16914 S<[ B<->(B<no>)B<timing> ]>
16915 S<[ B<-verbosity> I<num> ]>
16916 S<[ B<-html_version> I<num> ]>
16917 S<[ B<->(B<no>)B<strict> ]>
16918 I<file.tex> S<[ I<file2.tex> ... ]>
16920 =head1 DESCRIPTION
16922 I<LaTeX2HTML> is a Perl program that translates LaTeX source files into
16923 HTML. For each source file given as an argument the translator will create
16924 a directory containing the corresponding HTML files.
16926 =head1 OPTIONS
16928 Many options can be specified in a true/false manner. This is indicated by
16929 I<(no)>, e.g. to enable passing unknown environments to LaTeX, say "-latex",
16930 to disable the feature say "-nolatex" or "-no_latex" (portability mode).
16932 =over 4
16934 =item B<-help> | B<-h>
16936 Print this online manual and exit.
16938 =item B<-version> | B<-V>
16940 Print the LaTeX2HTML release and version information and exit.
16942 =item B<-split> I<num>
16944 Stop making separate files at this depth (say "-split 0" for one huge HTML
16945 file).
16947 =item B<-link> I<num>
16949 Stop showing child nodes at this depth.
16951 =item B<-toc_depth> I<num>
16953 MISSING_DESCRIPTION
16955 =item B<->(B<no>)B<toc_stars>
16957 MISSING_DESCRIPTION
16959 =item B<->(B<no>)B<short_extn>
16961 If this is set all HTML file will have extension C<.htm> instead of
16962 C<.html>. This is helpful when shipping the document to PC systems.
16964 =item B<-iso_language> I<lang>
16966 MISSING_DESCRIPTION
16968 =item B<->(B<no>)B<validate>
16970 When this is set true, the HTML validator specified in F<l2hconf.pm>
16971 will run.
16973 =item B<->(B<no>)B<latex>
16975 Pass unknown environments to LaTeX. This is the default.
16977 =item B<->(B<no>)B<djgpp>
16979 Specify this switch if you are running DJGPP on DOS and need to avoid
16980 running out of filehandles.
16982 =item B<->(B<no>)B<fork>
16984 Enable/disable forking. The default is reasonable for this platform.
16986 =item B<->(B<no>)B<external_images>
16988 If set, leave the images outside the document.
16990 =item B<->(B<no>)B<ascii_mode>
16992 This is different from B<-noimages>.
16993 If this is set, B<LaTeX2HTML> will show textual tags rather than
16994 images, both in navigation panel and text (Eg. C<[Up]> instead the up
16995 icon).
16996 You could use this feature to create simple text from your
16997 document, eg. with 'Save as... Text' from B<Netscape> or with
16998 B<lynx -dump>.
17000 =item B<->(B<no>)B<lcase_tags>
17002 writes out HTML tag names using lowercase letters, rather than uppercase.
17004 =item B<->(B<no>)B<ps_images>
17006 If set, use links to external postscript images rather than inlined bitmaps.
17008 =item B<-font_size> I<size>
17010 To set the point size of LaTeX-generated GIF files, specify the desired
17011 value (i.e., C<10pt>, C<11pt>, C<12pt>, etc.).
17012 The default is to use the point size of the original LaTeX document.
17013 This value will be magnified by I<$FIGURE_SCALE_FACTOR> and
17014 I<$MATH_SCALE_FACTOR> defined in F<l2hconf.pm>.
17016 =item B<->(B<no>)B<tex_defs>
17018 Enable interpretation of raw TeX commands (default).
17019 Note: There are many variations of C<\def> that B<LaTeX2HTML> cannot process
17020 correctly!
17022 =item B<->(B<no>)B<navigation>
17024 Put a navigation panel at the top of each page (default).
17026 =item B<->(B<no>)B<top_navigation>
17028 Enables navigation links at the top of each page (default).
17030 =item B<->(B<no>)B<buttom_navigation>
17032 Enables navigation links at the buttom of each page.
17034 =item B<->(B<no>)B<auto_navigation>
17036 Put navigation links at the top of each page. If the page exceeds
17037 I<$WORDS_IN_PAGE> number of words then put one at the bottom of the page.
17039 =item B<->(B<no>)B<index_in_navigation>
17041 Put a link to the index page in the navigation panel.
17043 =item B<->(B<no>)B<contents_in_navigation>
17045 Put a link to the table of contents in the navigation panel.
17047 =item B<->(B<no>)B<next_page_in_navigation>
17049 Put a link to the next logical page in the navigation panel.
17051 =item B<->(B<no>)B<previous_page_in_navigation>
17053 Put a link to the previous logical page in the navigation panel.
17055 =item B<->(B<no>)B<footnode>
17057 Puts all footnotes onto a separate HTML page, called F<footnode.html>,
17058 rather than at the bottom of the page where they are referenced.
17060 =item B<->(B<no>)B<numbered_footnotes>
17062 If true, you will get every footnote applied with a subsequent number, else
17063 with a generic hyperlink icon.
17065 =item B<-prefix> I<output_filename_prefix>
17067 Set the output file prefix, prepended to all C<.html>, C<.gif> and C<.pl>
17068 files. See also B<-auto_prefix>.
17070 =item B<->(B<no>)B<auto_prefix>
17072 Set this to automatically insert the equivalent of B<-prefix >C<basename->",
17073 where "basename" is the base name of the file being translated.
17075 =item B<-long_titles> I<num>
17077 MISSING_DESCRIPTION
17079 =item B<->(B<no>)B<custom_titles>
17081 MISSING_DESCRIPTION
17083 =item B<-title>|B<-t> I<top_page_title>
17085 The title (displayed in the browser's title bar) the document shall get.
17087 =item B<->(B<no>)B<rooted>
17089 MISSING_DESCRIPTION
17091 =item B<-rootdir> I<output_directory>
17093 MISSING_DESCRIPTION
17095 =item B<-dir> I<output_directory>
17097 Put the result in this directory instead of parallel to the LaTeX file,
17098 provided the directory exists, or B<-mkdir> is specified.
17100 =item B<-mkdir>
17102 Allow directory specified with B<-dir> to be created if necessary.
17104 =item B<-address> I<author_address> | B<-noaddress>
17106 Supply your own string if you don't like the default 
17107 "E<lt>NameE<gt> E<lt>DateE<gt>". B<-noaddress> suppresses the
17108 generation of an address footer.
17110 =item B<->(B<no>)B<subdir>
17112 If set (default), B<LaTeX2HTML> creates (or reuses) another file directory.
17113 When false, the generated HTML files will be placed in the current
17114 directory.
17116 =item B<-info> I<0> | I<1> | I<string>
17118 =item B<-noinfo>
17120 If 0 is specified (or B<-noinfo> is used), do not generate an I<"About this
17121 document..."> section. If 1 is specified (default), the standard info page is
17122 generated. If a custom string is given, it is used as the info page.
17124 =item B<->(B<no>)B<auto_link>
17126 MISSING_DESCRIPTION
17128 =item B<-reuse> I<num> | B<-noreuse>
17130 If false, do not reuse or recycle identical images generated in previous
17131 runs. If the html subdirectory already exists, start the interactive session.
17132 If I<num> is nonzero, do recycle them and switch off the interactive session.
17133 If 1, only recycle images generated from previous runs.
17134 If 2, recycle images from the current and previous runs (default).
17136 =item B<->(B<no>)B<antialias_text>
17138 Use anti-aliasing in the generation of images of typeset material;
17139 e.g. mathematics and text, e.g. in tables and {makeimage} environments.
17141 =item B<->(B<no>)B<antialias>
17143 Use anti-aliasing in the generation of images of figures. This usually
17144 results in "sharper" bitmap images.
17146 =item B<->(B<no>)B<transparent>
17148 If this is set to false then any inlined images generated from "figure" 
17149 environments will NOT be transparent.
17151 =item B<->(B<no>)B<white>
17153 This sets the background of generated images to white for anti-aliasing.
17155 =item B<->(B<no>)B<discard>
17157 if true, the PostScript file created for each generated image
17158 is discarded immediately after its image has been rendered and saved in the
17159 required graphics format. This can lead to significant savings in disk-space,
17160 when there are a lot of images, since otherwise these files are not discarded 
17161 until the end of all processing.
17163 =item B<-image_type> I<type>
17165 Specify the type of bitmap images to be generated. Depending on your setup,
17166 B<LaTeX2HTML> can generate B<gif> or B<png> images. Note: Gif images have
17167 certain legal restrictions, as their generation involves an algorithm
17168 patented by Unisys.
17170 =item B<->(B<no>)B<images>
17172 If false, B<LaTeX2HTML> will not attempt to produce any inlined images.
17173 The missing images can be generated "off-line" by restarting B<LaTeX2HTML>
17174 with B<-images_only>.
17176 =item B<-accent_images> I<type> | B<-noaccent_images>
17178 MISSING_DESCRIPTION
17180 =item B<-style> I<style>
17182 MISSING_DESCRIPTION
17184 =item B<->(B<no>)B<parbox_images>
17186 MISSING_DESCRIPTION
17188 =item B<->(B<no>)B<math>
17190 By default the special MATH extensions are not used
17191 since they do not conform with the HTML 3.2 standard.
17193 =item B<->(B<no>)B<math_parsing>
17195 MISSING_DESCRIPTION
17197 =item B<->(B<no>)B<latin>
17199 MISSING_DESCRIPTION
17201 =item B<->(B<no>)B<entities>
17203 MISSING_DESCRIPTION
17205 =item B<->(B<no>)B<local_icons>
17207 Set this if you want to copy the navigation icons to each document directory
17208 so that the document directory is self-contained and can be dropped into
17209 another server tree without further actions.
17211 =item B<->(B<no>)B<scalable_fonts>
17213 MISSING_DESCRIPTION
17215 =item B<->(B<no>)B<images_only>
17217 When true, B<LaTeX2HTML> will only try to convert the inlined images in the
17218 file F<images.tex> which should have been generated automatically during
17219 previous runs. This is very useful for correcting "bad LaTeX" in this file.
17221 =item B<->(B<no>)B<show_section_numbers>
17223 When this is set true, the section numbers are shown. The section numbers
17224 should then match those that would have been produced by LaTeX.
17225 The correct section numbers are obtained from the $FILE.aux file generated 
17226 by LaTeX.
17227 Hiding the section numbers encourages use of particular sections 
17228 as standalone documents. In this case the cross reference to a section 
17229 is shown using the default symbol rather than the section number.
17231 =item B<->(B<no>)B<show_init>
17233 MISSING_DESCRIPTION
17235 =item B<-init_file> I<Perl_file>
17237 MISSING_DESCRIPTION
17239 =item B<-up_url> I<up_URL>, B<-up_title> I<up_title>
17241 =item B<-down_url> I<down_URL>, B<-down_title> I<down_title>
17243 =item B<-prev_url> I<prev_URL>, B<-prev_title> I<prev_title>
17245 =item B<-index> I<index_URL>,
17247 =item B<-contents> I<toc_URL>
17249 =item B<-biblio> I<biblio_URL>
17251 If both of the listed two options are set then the "Up" ("Previous" etc.)
17252 button of the navigation panel in the first node/page of a converted
17253 document will point to I<up_URL> etc. I<up_title> should be set
17254 to some text which describes this external link.
17255 Similarly you might use these options to link external documents
17256 to your navigation panel.
17258 =item B<-external_file> I<external_aux_file>
17260 MISSING_DESCRIPTION
17262 =item B<->(B<no>)B<short_index>
17264 If this is set then B<makeidx.perl> will construct codified names
17265 for the text of index references.
17267 =item B<->(B<no>)B<unsegment>
17269 Use this to translate a segmented document as if it were not
17270 segmented.
17272 =item B<->(B<no>)B<debug>
17274 If this is set then intermediate files are left for later inspection and
17275 a lot of diagnostic output is produced. This output may be useful when
17276 searching for problems and/or submitting bug reports to the developers.
17277 Temporary files include F<$$_images.tex> and F<$$_images.log> created during
17278 image conversion. Caution: Intermediate files can be I<enormous>!
17280 =item B<-tmp> I<path>
17282 Path for temporary files. This should be a local, fast filesystem because it is heavily used during image generation. The default is set in F<l2hconf.pm>.
17284 =item B<->(B<no>)B<ldump>
17286 This will cause LaTeX2HTML to produce a LaTeX dump of images.tex which is read
17287 in on subsequent runs and speeds up startup time of LaTeX on the images.tex
17288 translation. This actually consumes additional time on the first run, but pays
17289 off on subsequent runs. The dump file will need about 1 Meg of disk space.
17291 =item B<->(B<no>)B<timing>
17293 MISSING_DESCRIPTION
17295 =item B<-verbosity> I<num>
17297 The amount of message information printed to the screen during processing
17298 by B<LaTeX2HTML> is controlled by this setting.
17299 By increasing this value, more information is displayed.
17300 Here is the type of extra information that is shown at each level:
17302   0   no extra information
17303   1   section types and titles
17304   2   environment
17305   3   command names
17306   4   links, labels and internal sectioning codes
17308 =item B<-html_version> I<list>
17310 Which HTML version should be generated. Currently available are:
17311 C<2.0>, C<3.0>, C<3.2>, C<4.0>. Some additional options that may be
17312 added are: C<math> (parse mathematics), C<i18n> (?), 
17313 C<table> (generate tables), C<frame> (generate frames),
17314 C<latin1>...C<latin9> (use ISO-Latin-x encoding),
17315 C<unicode> (generate unicode characters). Separate the options with ',',
17316 e.g. C<4.0,math,frame>.
17318 =item B<->(B<no>)B<strict>
17320 MISSING_DESCRIPTION
17322 =back
17324 =head1 FILES
17326 =over 4
17328 =item F<$LATEX2HTMLPLATDIR/l2hconf.pm>
17330 This file holds the global defaults and configuration settings for
17331 B<LaTeX2HTML>.
17333 =item F<$HOME/.latex2html-init>
17335 =item F<./.latex2html-init>
17337 These files may contain settings that override the global defaults, just
17338 like specifying command line switches.
17340 =back
17342 =head1 ENVIRONMENT
17344 =over 4
17346 =item LATEX2HTMLDIR
17348 Path where LaTeX2HTML library files are found. On this installation
17349 LATEX2HTMLDIR is F</usr/share/latex2html>
17351 =item PERL5LIB
17353 Set by the B<latex2html> program to find perl modules.
17355 =item L2HCONFIG
17357 An alternative configuration filename. The standard configuration file
17358 is F<$LATEX2HTMLPLATDIR/l2hconf.pm>. You may specify a sole filename (searched
17359 for in F<$LATEX2HTMLPLATDIR> (and F<$PERL5LIB>) or a complete path.
17361 =item L2HINIT_NAME
17363 The standard user-specific configuration filename is F<.latex2html-init>.
17364 This environment variable will override this name.
17366 =item HOME
17368 Evaluated if the system does not know about "home" directories (like
17369 DOS, WinXX, OS/2, ...) to determine the path to F<$L2HINIT_NAME>.
17371 =item TEXE_DONT_INCLUDE, TEXE_DO_INCLUDE
17373 Used internally for communication with B<texexpand>.
17375 =item TEXINPUTS
17377 Used to find TeX includes of all sorts.
17379 =back
17381 =head1 PROBLEMS
17383 For information on various problems and remedies see the WWW online
17384 documentation or the documents available in the distribution.
17385 An online bug reporting form and various archives are available at
17386 F<http://www.latex2html.org/>
17388 There is a mailing list for discussing B<LaTeX2HTML>: C<latex2html@tug.org>
17390 =head1 AUTHOR
17392 Nikos Drakos,  Computer Based Learning Unit, University of Leeds
17393 E<lt>nikos@cbl.leeds.ac.ukE<gt>. Several people have contributed
17394 suggestions, ideas, solutions, support and encouragement.
17396 The B<pstoimg> script was written by Marek Rouchal 
17397 E<lt>marek@saftsack.fs.uni-bayreuth.deE<gt>
17398 as a generalisation of the B<pstogif> utility to allow graphic formats
17399 other than GIF to be created. Various options and enhancements have
17400 been added by Ross Moore.
17401 Some of the code is based upon the pstoppm.ps postscript program 
17402 originally written by Phillip Conrad (Perfect Byte, Inc.)
17403 and modified by L. Peter Deutsch (Aladdin Enterprises).
17405 =head1 SEE ALSO
17407 See the WWW online documentation or the F<$LATEX2HTMLDIR/doc/manual.ps>
17408 file for more detailed information and examples.
17410 L<pstoing>, L<texexpand>
17412 =cut