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>
11
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##########################################################################
58
59use 5.003; # refuse to work with old and buggy perl version
60#use strict;
61#use diagnostics;
62
63# include some perl packages; these come with the standard distribution
64use Getopt::Long;
65use Fcntl;
66use AnyDBM_File;
67
68# The following are global variables that also appear in some modules
69use vars qw($LATEX2HTMLDIR $LATEX2HTMLPLATDIR $SCRIPT
70            %Month %used_icons $inside_tabbing $TABLE_attribs
71            %mathentities $date_name $outer_math $TABLE__CELLPADDING_rx);
72
73BEGIN {
74  # print "scanning for l2hdir\n";
75  if($ENV{'LATEX2HTMLDIR'}) {
76    $LATEX2HTMLDIR = $ENV{'LATEX2HTMLDIR'};
77  } else {
78    $ENV{'LATEX2HTMLDIR'} = $LATEX2HTMLDIR = '/home/bsbuild/dev/org-release/bacula-docs-11.0.5/latex2html';
79  }
80
81  if($ENV{'LATEX2HTMLPLATDIR'}) {
82    $LATEX2HTMLPLATDIR = $ENV{'LATEX2HTMLPLATDIR'};
83  } else {
84    $LATEX2HTMLPLATDIR = '/home/bsbuild/dev/org-release/bacula-docs-11.0.5/latex2html'||$LATEX2HTMLDIR;
85    $ENV{'LATEX2HTMLPLATDIR'} = $LATEX2HTMLPLATDIR;
86  }
87  if(-d $LATEX2HTMLPLATDIR) {
88    push(@INC,$LATEX2HTMLPLATDIR);
89  }
90
91  if(-d $LATEX2HTMLDIR) {
92    push(@INC,$LATEX2HTMLDIR);
93  } else {
94    die qq{Fatal: Directory "$LATEX2HTMLDIR" does not exist.\n};
95  }
96}
97
98use L2hos; # Operating system dependent routines
99
100# $^W = 1; # turn on warnings
101
102my $RELEASE = '2016';
103my ($REVISION) = q$Revision: 1.71 $ =~ /:\s*(\S+)/;
104
105# The key, which delimts expressions defined in the environment
106# depends on the operating system.
107$envkey = L2hos->pathd();
108
109# $dd is the directory delimiter character
110$dd = L2hos->dd();
111
112# make sure the $LATEX2HTMLDIR is on the search-path for forked processes
113if($ENV{'PERL5LIB'}) {
114  $ENV{'PERL5LIB'} .= "$envkey$LATEX2HTMLDIR"
115    unless($ENV{'PERL5LIB'} =~ m|\Q$LATEX2HTMLDIR\E|o);
116} else {
117  $ENV{'PERL5LIB'} = $LATEX2HTMLDIR;
118}
119
120# Local configuration, read at runtime
121# Read the $CONFIG_FILE  (usually l2hconf.pm )
122if($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  }
130}
131
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 = "2016";
136#$TPATCHLEVEL = " beta";
137#$TPATCHLEVEL = " release";
138#$RELDATE = "(March 30, 1999)";
139#$TEX2HTMLV_SHORT = $TVERSION . $TPATCHLEVEL;
140
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/";
147
148# Set $HOME to what the system considers the home directory
149$HOME = L2hos->home();
150push(@INC,$HOME);
151
152# flush stdout with every print -- gives better feedback during
153# long computations
154$| = 1;
155
156# set Perl's subscript separator to LaTeX's illegal character.
157# (quite defensive but why not)
158$; = "\000";
159
160# No arguments!!
161unless(@ARGV) {
162  die "Error: No files to process!\n";
163}
164
165# Image prefix
166$IMAGE_PREFIX = '_image';
167
168# Partition prefix
169$PARTITION_PREFIX = 'part_' unless $PARTITION_PREFIX;
170
171# Author address
172@address_data = &address_data('ISO');
173$ADDRESS = "$address_data[0]\n$address_data[1]";
174
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);
179
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;
183
184# Read the $HOME/$INIT_FILE_NAME if one is found
185if (-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 '.');
193}
194
195# Read the $INIT_FILE_NAME file if one is found in current directory
196if ( 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";
200}
201die "Error: '.' is an incorrect setting for DESTDIR.\n" .
202    "Please check your $INIT_FILE_NAME file.\n"
203    if ($DESTDIR eq '.');
204
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;
209
210#absolutise the paths
211$LATEX2HTMLSTYLES = join($envkey,
212                        map(L2hos->Make_directory_absolute($_),
213                                split(/$envkey/o, $LATEX2HTMLSTYLES)));
214
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_
219
220if ($PK_GENERATION && ! $DVIPS_MODE) {
221    $ENV{HOME} =  $LATEX2HTMLDIR;
222    delete $ENV{PRINTER}; # Overrides .dvipsrc
223}
224
225# language of the DTD specified in the <DOCTYPE...> tag
226$ISO_LANGUAGE = 'EN' unless $ISO_LANGUAGE;
227
228# Save the command line arguments, quote where necessary
229$argv = join(' ', map {/[\s#*!\$%]/ ? "'$_'" : $_ } @ARGV);
230
231# Pre-process the command line for backward compatibility
232foreach(@ARGV) {
233  s/^--?no_/-no/; # replace e.g. no_fork by nofork
234  # s/^[+](\d+)$/$1/; # remove + in front of integers
235}
236
237# Process command line options
238my %opt;
239unless(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;
333}
334
335# interpret options, check option consistency
336if(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    }
344}
345if(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    }
353}
354unless ($ISO_LANGUAGE =~ /^[A-Z.]+$/) {
355    die "Error: Language (-iso_language) must be uppercase and dots only: $ISO_LANGUAGE\n";
356}
357if ($HTML_VALIDATE && !$HTML_VALIDATOR) {
358    die "Error: Need a HTML_VALIDATOR when -validate is specified.\n";
359}
360&set_if_false($NOLATEX,$opt{latex}); # negate the option...
361if ($ASCII_MODE || $PS_IMAGES) {
362    $EXTERNAL_IMAGES = 1;
363}
364if ($FONT_SIZE && $FONT_SIZE !~ /^\d+pt$/) {
365    die "Error: Font size (-font_size) must end with 'pt': $FONT_SIZE\n"
366}
367&set_if_false($NO_NAVIGATION,$opt{navigation});
368&set_if_false($NO_FOOTNODE,$opt{footnode});
369if (defined $TITLE && !length($TITLE)) {
370    die "Error: Empty title (-title).\n";
371}
372if ($opt{rootdir}) {
373    $ROOTED = 1;
374    $FIXEDDIR = $opt{rootdir};
375}
376if ($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    }
385}
386&set_if_false($NO_SUBDIR, $opt{subdir});
387&set_if_false($NO_AUTO_LINK, $opt{auto_link});
388if ($opt{noreuse}) {
389    $REUSE = 0;
390}
391unless(grep(/^\Q$IMAGE_TYPE\E$/o, @IMAGE_TYPES)) {
392    die <<"EOF";
393Error: No such image type '$IMAGE_TYPE'.
394       This installation supports (first is default): @IMAGE_TYPES
395EOF
396}
397&set_if_false($NO_IMAGES, $opt{images});
398if ($opt{noaccent_images}) {
399    $ACCENT_IMAGES = '';
400}
401if($opt{noaddress}) {
402    $ADDRESS = '';
403}
404if($opt{noinfo}) {
405    $INFO = 0;
406}
407if($ACCENT_IMAGES && $ACCENT_IMAGES !~ /^[a-zA-Z,]+$/) {
408    die "Error: Single word or comma-list of style words needed for -accent_images, not: $_\n";
409}
410&set_if_false($NO_PARBOX_IMAGES, $opt{parbox_images});
411&set_if_false($NO_SIMPLE_MATH, $opt{math});
412if (defined $opt{math_parsing}) {
413    $NO_MATH_PARSING = !$opt{math_parsing};
414    $NO_SIMPLE_MATH = !$opt{math_parsing} unless(defined $opt{math});
415}
416&set_if_false($NO_ISOLATIN, $opt{latin});
417if ($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    }
425}
426foreach($EXTERNAL_UP_LINK, $EXTERNAL_DOWN_LINK, $EXTERNAL_PREV_LINK,
427        $EXTERNAL_INDEX, $EXTERNAL_BIBLIO, $EXTERNAL_CONTENTS) {
428    $_ ||= ''; # initialize
429    s/~/&#126;/g; # protect `~'
430}
431if($TMP && !(-d $TMP && -w _)) {
432    die "Error: '$TMP' not usable as temporary directory.\n";
433}
434if ($opt{help}) {
435    L2hos->perldoc($SCRIPT);
436    exit 0;
437}
438if ($opt{version}) {
439    &banner();
440    exit 0;
441}
442if ($opt{test_mode}) {
443    $TITLE = 'LaTeX2HTML Test Document';
444    $TEXEXPAND = "$PERL /home/bsbuild/dev/org-release/bacula-docs-11.0.5/latex2html-2016${dd}texexpand";
445    $PSTOIMG   = "$PERL /home/bsbuild/dev/org-release/bacula-docs-11.0.5/latex2html-2016${dd}pstoimg";
446    $ICONSERVER = L2hos->path2URL("/home/bsbuild/dev/org-release/bacula-docs-11.0.5/latex2html-2016${dd}icons");
447    $TEST_MODE  = 1;
448    $RGBCOLORFILE = "/home/bsbuild/dev/org-release/bacula-docs-11.0.5/latex2html-2016${dd}styles${dd}rgb.txt";
449    $CRAYOLAFILE = "/home/bsbuild/dev/org-release/bacula-docs-11.0.5/latex2html-2016${dd}styles${dd}crayola.txt";
450}
451if($DEBUG) {
452    # make the OS-dependent functions more chatty, too
453    $L2hos::Verbose = 1;
454}
455
456undef %opt; # not needed any more
457
458
459$FIXEDDIR = $FIXEDDIR || $DESTDIR || '';  # for backward compatibility
460
461if ($EXTERNAL_UP_TITLE xor $EXTERNAL_UP_LINK) {
462    warn "Warning (-up_url, -up_title): Need to specify both a parent URL and a parent title!\n";
463    $EXTERNAL_UP_TITLE = $EXTERNAL_UP_LINK = "";
464}
465
466if ($EXTERNAL_DOWN_TITLE xor $EXTERNAL_DOWN_LINK) {
467    warn "Warning (-down_url, -down_title): Need to specify both a parent URL and a parent title!\n";
468    $EXTERNAL_DOWN_TITLE = $EXTERNAL_DOWN_LINK = "";
469}
470
471# $NO_NAVIGATION = 1 unless $MAX_SPLIT_DEPTH;	#  Martin Wilck
472
473if ($MAX_SPLIT_DEPTH && $MAX_SPLIT_DEPTH < 0) {
474    $MAX_SPLIT_DEPTH *= -1; $REL_DEPTH = 1;
475}
476if ($MAX_LINK_DEPTH && $MAX_LINK_DEPTH < 0) {
477    $MAX_LINK_DEPTH *= -1; $LEAF_LINKS = 1;
478}
479
480$FOOT_FILENAME = 'footnode' unless ($FOOT_FILENAME);
481$NO_FOOTNODE = 1 unless ($MAX_SPLIT_DEPTH || $NO_FOOTNODE);
482$NO_SPLIT = 1 unless $MAX_SPLIT_DEPTH; # _MRO_TODO_: is this needed at all?
483$SEGMENT = $SEGMENTED = 0;
484$NO_MATH_MARKUP = 1;
485
486# specify the filename extension to use with the generated HTML files
487if ($SHORTEXTN) { $EXTN = ".htm"; }	# for HTML files on CDROM
488elsif ($ALLOW_PHP) { $EXTN = ".php"; }  # has PHP dynamic includes
489	# with server-side includes (SSI) :
490elsif ($ALLOW_SSI && !$XBIT_HACK) { $EXTN = ".shtml"; }
491	# ordinary names, valid also for SSI with XBit hack :
492else { $EXTN = ".html"; }
493
494$NODE_NAME = 'node' unless (defined $NODE_NAME);
495
496# space for temporary files
497# different to the $TMPDIR for image-generation
498# MRO: No directory should end with $dd!
499$TMP_ = "TMP";
500
501$TMP_PREFIX = "l2h" unless ($TMP_PREFIX);
502
503# This can be set to 1 when using a version of dvips that is safe
504# from the "dot-in-name" bug.
505# _TODO_ this should be determined by configure
506$DVIPS_SAFE = 1;
507
508$CHARSET = $charset || 'iso-8859-1';
509
510####################################################################
511#
512# If possible, use icons of the same type as generated images
513#
514if ($IMAGE_TYPE && %{"icons_$IMAGE_TYPE"}) {
515    %icons = %{"icons_$IMAGE_TYPE"};
516}
517
518####################################################################
519#
520# Figure out what options we need to pass to DVIPS and store that in
521# the $DVIPSOPT variable.  Also, scaling is taken care of at the
522# dvips level if PK_GENERATION is set to 1, so adjust SCALE_FACTORs
523# accordingly.
524#
525if ($SCALABLE_FONTS) {
526    $PK_GENERATION = 0;
527    $DVIPS_MODE = '';
528}
529
530if ($PK_GENERATION) {
531    if ($MATH_SCALE_FACTOR <= 0) { $MATH_SCALE_FACTOR = 2; }
532    if ($FIGURE_SCALE_FACTOR <= 0) { $FIGURE_SCALE_FACTOR = 2; }
533    my $saveMSF = $MATH_SCALE_FACTOR;
534    my $saveFSF = $FIGURE_SCALE_FACTOR;
535    my $desired_dpi = int($MATH_SCALE_FACTOR*75);
536    $FIGURE_SCALE_FACTOR = ($METAFONT_DPI / 72) *
537	($FIGURE_SCALE_FACTOR / $MATH_SCALE_FACTOR) ;
538    $MATH_SCALE_FACTOR = $METAFONT_DPI / 72;
539    $dvi_mag = int(1000 * $desired_dpi / $METAFONT_DPI);
540    if ($dvi_mag > 1000) {
541	&write_warnings(
542	    "WARNING: Your SCALE FACTOR is too large for PK_GENERATION.\n" .
543	    "         See $CONFIG_FILE for more information.\n");
544    }
545
546    # RRM: over-sized scaling, using dvi-magnification
547    if ($EXTRA_IMAGE_SCALE) {
548	print "\n *** Images at $EXTRA_IMAGE_SCALE times resolution of displayed size ***\n";
549	$desired_dpi = int($EXTRA_IMAGE_SCALE * $desired_dpi+.5);
550	print "    desired_dpi = $desired_dpi  METAFONT_DPI = $METAFONT_DPI\n"
551            if $DEBUG;
552	$dvi_mag = int(1000 * $desired_dpi / $METAFONT_DPI);
553	$MATH_SCALE_FACTOR = $saveMSF;
554	$FIGURE_SCALE_FACTOR = $saveFSF;
555    }
556    # no space after "-y", "-D", "-e" --- required by DVIPS under DOS !
557    my $mode_switch = "-mode $DVIPS_MODE" if $DVIPS_MODE;
558    $DVIPSOPT .= " -y$dvi_mag -D$METAFONT_DPI $mode_switch -e5 ";
559} else { # no PK_GENERATION
560#    if ($EXTRA_IMAGE_SCALE) {
561#	&write_warnings(
562#	   "the \$EXTRA_IMAGE_SCALE feature requires either \$PK_GENERATION=1"
563#			. " or the '-scalable_fonts' option");
564#	$EXTRA_IMAGE_SCALE = '';
565#    }
566    # MRO: shifted to l2hconf
567    #$DVIPSOPT .= ' -M';
568} # end PK_GENERATION
569
570# The mapping from numbers to accents.
571# These are required to process the \accent command, which is found in
572# tables of contents whenever there is an accented character in a
573# caption or section title.  Processing the \accent command makes
574# $encoded_*_number work properly (see &extract_captions) with
575# captions that contain accented characters.
576# I got the numbers from the plain.tex file, version 3.141.
577
578# Missing entries should be looked up by a native speaker.
579# Have a look at generate_accent_commands and $iso_8859_1_character_map.
580
581# MEH: added more accent types
582# MRO: only uppercase needed!
583%accent_type = (
584   '18' => 'grave',		# \`
585   '19' => 'acute',		# `'
586   '20' => 'caron',		# \v
587   '21' => 'breve',		# \u
588   '22' => 'macr',		# \=
589   '23' => 'ring',		#
590   '24' => 'cedil',		# \c
591   '94' => 'circ',		# \^
592   '95' => 'dot',		# \.
593   '7D' => 'dblac',		# \H
594   '7E' => 'tilde',		# \~
595   '7F' => 'uml',		# \"
596);
597
598&driver;
599exit 0; # clean exit, no errors
600
601############################ Subroutines ##################################
602# Philippe Chauvat - 03-feb-2017
603sub extract_external_references {
604    local($bmanual) = @_ ;
605    #
606    # Philippe Chauvat - 08-mar-2017
607    # write the labels found into the current documents
608    #
609    my $bxrefile = join('','../../','html-external-references.sed') ;
610    my $birefile = join('','../../','html-internal-references.sed') ;
611    open EFH, ">" . $bxrefile or die "$!: Unable to create $bxrefile\n" ;
612    open IFH, ">" . $birefile or die "$!: Unable to create $birefile\n" ;
613    foreach my $k (keys %ref_files) {
614	print EFH join('','s|',$bmanual,'/__TO_BE_REPLACED_WITH_HTML_FILENAME__#',$k,'|',$bmanual,'/',$ref_files{$k},'#',$k,"|\n") ;
615	print IFH join('','s|__TO_BE_REPLACED_WITH_HTML_FILENAME__#',$k,'|',$ref_files{$k},'#',$k,"|\n") ;
616#	print FH join('','s|',$bmanual,'/__TO_BE_REPLACED_WITH_HTML_FILENAME__#',$k,'|',$bmanual,'/',$ref_files{$k},'#',$bmanual,'-',$k,"|\n") ;
617    }
618    close EFH ;
619    close IFH ;
620}
621
622sub pre_pre_process {
623    #
624    # We need this to handle acronyms
625    %bacronyms = () ;
626}
627
628#check that $TMP is writable, if so create a subdirectory
629sub make_tmp_dir {
630    &close_dbm_database if $DJGPP; # to save file-handles
631
632    # determine a suitable temporary path
633    #
634    $TMPDIR = '';
635    my @tmp_try = ();
636    push(@tmp_try, $TMP) if($TMP);
637    push(@tmp_try, "$DESTDIR$dd$TMP_") if($TMP_);
638    push(@tmp_try, $DESTDIR) if($DESTDIR);
639    push(@tmp_try, L2hos->Cwd());
640
641    my $try;
642    TempTry: foreach $try (@tmp_try) {
643      next unless(-d $try && -w _);
644      my $tmp = "$try$dd$TMP_PREFIX$$";
645      if(mkdir($tmp,0755)) {
646        $TMPDIR=$tmp;
647	last TempTry;
648      } else {
649        warn "Warning: Cannot create temporary directory '$tmp': $!\n";
650      }
651    }
652
653    $dvips_warning = <<"EOF";
654
655Warning: There is a '.' in \$TMPDIR, $DVIPS will probably fail.
656Set \$TMP to use a /tmp directory, or rename the working directory.
657EOF
658    die ($dvips_warning . "\n\$TMPDIR=$TMPDIR  ***\n\n")
659	if ($TMPDIR =~ /\./ && $DVIPS =~ /dvips/ && !$DVIPS_SAFE);
660
661    &open_dbm_database if $DJGPP;
662}
663
664# MRO: set first parameter to the opposite of the second if second parameter is defined
665sub set_if_false {
666    $_[0] = !$_[1] if(defined $_[1]);
667}
668
669sub check_for_dots {
670    local($file) = @_;
671    if ($file =~ /\.[^.]*\./ && !$DVIPS_SAFE) {
672	die "\n\n\n *** Fatal Error --- but easy to fix ***\n"
673	    . "\nCannot have '.' in file-name prefix, else dvips fails on images"
674	    . "\nChange the name from  $file  and try again.\n\n";
675    }
676}
677
678# Process each file ...
679sub driver {
680    local($FILE, $orig_cwd, %unknown_commands, %dependent, %depends_on
681	  , %styleID, %env_style, $bbl_cnt, $dbg, %numbered_section);
682    # MRO: $texfilepath has to be global!
683    local(%styles_loaded);
684    $orig_cwd = L2hos->Cwd();
685
686    print "\n *** initialise *** " if ($VERBOSITY > 1);
687    &initialise;		# Initialise some global variables
688
689    print "\n *** check modes *** " if ($VERBOSITY > 1);
690    &ascii_mode if $ASCII_MODE;	# Must come after initialization
691    &titles_language($TITLES_LANGUAGE);
692    &make_numbered_footnotes if ($NUMBERED_FOOTNOTES);
693    $dbg = $DEBUG ? "-debug" : "";
694    $dbg .= (($VERBOSITY>2) ? " -verbose" : "");
695
696    #use the same hashes for all files in a batch
697    local(%cached_env_img, %id_map, %symbolic_labels, %latex_labels)
698	if ($FIXEDDIR && $NO_SUBDIR);
699
700    local($MULTIPLE_FILES,$THIS_FILE);
701    $MULTIPLE_FILES = 1+$#ARGV if $ROOTED;
702    print "\n *** $MULTIPLE_FILES file".($MULTIPLE_FILES ? 's: ' : ': ')
703    	. join(',',@ARGV) . " *** " if ($VERBOSITY > 1);
704
705    local(%section_info, %toc_section_info, %cite_info, %ref_files);
706
707    foreach $FILE (@ARGV) {
708	&check_for_dots($FILE) unless $DVIPS_SAFE;
709	++$THIS_FILE if $MULTIPLE_FILES;
710	do {
711	    %section_info = ();
712	    %toc_section_info = ();
713	    %cite_info = ();
714	    %ref_files = ();
715	} unless $MULTIPLE_FILES;
716	local($bbl_nr) = 1;
717
718	# The number of reused images and those in images.tex
719	local($global_page_num) = (0) unless($FIXEDDIR && $NO_SUBDIR);
720	# The number of images in images.tex
721	local($new_page_num) = (0); # unless($FIXEDDIR && $NO_SUBDIR);
722	local($pid, $sections_rx,
723	    , $outermost_level, %latex_body, $latex_body
724	    , %encoded_section_number
725	    , %verbatim, %new_command, %new_environment
726	    , %provide_command, %renew_command, %new_theorem
727	    , $preamble, $aux_preamble, $prelatex, @preamble);
728
729	# must retain these when all files are in the same directory
730	# else the images.pl and labels.pl files get clobbered
731	unless ($FIXEDDIR && $NO_SUBDIR) {
732	    print "\nResetting image-cache" if ($#ARGV);
733	    local(%cached_env_img, %id_map, %symbolic_labels, %latex_labels)
734	}
735
736## AYS: Allow extension other than .tex and make it optional
737	($EXT = $FILE) =~ s/.*\.([^\.]*)$/$1/;
738	if ( $EXT eq $FILE ) {
739	    $EXT = "tex";
740	    $FILE =~ s/$/.tex/;
741	}
742
743	#RRM: allow user-customisation, dependent on file-name
744	# e.g. add directories to $TEXINPUTS named for the file
745	# --- idea due to Fred Drake <fdrake@acm.org>
746	&custom_driver_hook($FILE) if (defined &custom_driver_hook);
747
748# JCL(jcl-dir)
749# We need absolute paths for TEXINPUTS here, because
750# we change the directory
751	if ($orig_cwd eq $texfilepath) {
752	    &deal_with_texinputs($orig_cwd);
753	} else {
754	    &deal_with_texinputs($orig_cwd, $texfilepath);
755	}
756
757	($texfilepath, $FILE) = &get_full_path($FILE);
758	$texfilepath = '.' unless($texfilepath);
759
760	die "Cannot read $texfilepath$dd$FILE \n"
761	    unless (-f "$texfilepath$dd$FILE");
762
763
764# Tell texexpand which files we *don't* want to look at.
765	$ENV{'TEXE_DONT_INCLUDE'} = $DONT_INCLUDE if $DONT_INCLUDE;
766# Tell texexpand which files we *do* want to look at, e.g.
767# home-brew style files
768	$ENV{'TEXE_DO_INCLUDE'} = $DO_INCLUDE if $DO_INCLUDE;
769
770	$FILE =~ s/\.[^\.]*$//; ## AYS
771	$DESTDIR = ''; # start at empty
772	if ($FIXEDDIR) {
773	    $DESTDIR = $FIXEDDIR unless ($FIXEDDIR eq '.');
774	    if (($ROOTED)&&!($texfilepath eq $orig_cwd)) {
775		$DESTDIR .= $dd . $FILE unless $NO_SUBDIR;
776	    };
777	} elsif ($texfilepath eq $orig_cwd) {
778	    $DESTDIR = ($NO_SUBDIR ? '.' : $FILE);
779	} else {
780	    $DESTDIR = $ROOTED ? '.' : $texfilepath;
781	    $DESTDIR .= $dd . $FILE unless $NO_SUBDIR;
782	}
783	$PREFIX  = "$FILE-" if $AUTO_PREFIX;
784
785	print "\nOPENING $texfilepath$dd$FILE.$EXT \n"; ## AYS
786
787	next unless (&new_dir($DESTDIR,''));
788        # establish absolute path to $DESTDIR
789	$DESTDIR = L2hos->Make_directory_absolute($DESTDIR);
790        &make_tmp_dir;
791        print "\nNote: Working directory is $DESTDIR\n";
792        print "Note: Images will be generated in $TMPDIR\n\n";
793
794# Need to clean up a bit in case there's garbage left
795# from former runs.
796	if ($DESTDIR) { chdir($DESTDIR) || die "$!\n"; }
797	if (opendir (TMP,$TMP_)) {
798	    foreach (readdir TMP) {
799		L2hos->Unlink("TMP_$dd$_") unless (/^\.\.?$/);
800	    }
801	    closedir TMP;
802	}
803	&cleanup(1);
804	unless(-d $TMP_) {
805	    mkdir($TMP_, 0755) ||
806	      die "Cannot create directory '$TMP_': $!\n";
807	}
808	chdir($orig_cwd);
809
810# RRM 14/5/98  moved this to occur earlier
811## JCL(jcl-dir)
812## We need absolute paths for TEXINPUTS here, because
813## we change the directory
814#	if ($orig_cwd eq $texfilepath) {
815#	    &deal_with_texinputs($orig_cwd);
816#	} else {
817#	    &deal_with_texinputs($orig_cwd, $texfilepath);
818#	}
819
820
821# This needs $DESTDIR to have been created ...
822	print " *** calling  `texexpand' ***" if ($VERBOSITY > 1);
823	local($unseg) = ($UNSEGMENT ? "-unsegment " : "");
824
825# does DOS need to check these here ?
826#	die "File $TEXEXPAND does not exist or is not executable\n"
827#	    unless (-x $TEXEXPAND);
828	L2hos->syswait("$TEXEXPAND $dbg -auto_exclude $unseg"
829		 . "-save_styles \"$DESTDIR$dd$TMP_${dd}styles\" "
830		 . ($TEXINPUTS ? "-texinputs \"$TEXINPUTS\" " : '' )
831		 . (($VERBOSITY >2) ? "-verbose " : '' )
832		 . "-out \"$DESTDIR$dd$TMP_$dd$FILE\" "
833		 . "\"$texfilepath$dd$FILE.$EXT\"")
834	    && die " texexpand  failed: $!\n";
835	print STDOUT "\n ***  `texexpand' done ***\n" if ($VERBOSITY > 1);
836
837	chdir($DESTDIR) if $DESTDIR;
838	$SIG{'INT'} = 'handler';
839
840	&open_dbm_database;
841	&initialise_sections;
842	print STDOUT "\n ***  database open ***\n" if ($VERBOSITY > 1);
843
844	if ($IMAGES_ONLY) {
845	    &make_off_line_images;
846	} else {
847	    &rename_image_files;
848	    &load_style_file_translations;
849	    &make_language_rx;
850	    &make_raw_arg_cmd_rx;
851#	    &make_isolatin1_rx unless ($NO_ISOLATIN);
852	    &translate_titles;
853	    &make_sections_rx;
854	    print "\nReading ...";
855	    if ($SHORT_FILENAME) {
856		L2hos->Rename ("$TMP_$dd$FILE" ,"$TMP_$dd$SHORT_FILENAME" );
857		&slurp_input_and_partition_and_pre_process(
858		      "$TMP_$dd$SHORT_FILENAME");
859	    } else {
860		&slurp_input_and_partition_and_pre_process("$TMP_$dd$FILE");
861	    }
862	    &add_preamble_head;
863	    # Create a regular expressions
864	    &set_depth_levels;
865	    &make_sections_rx;
866	    &make_order_sensitive_rx;
867	    &add_document_info_page if ($INFO && !(/\\htmlinfo/));
868	    &add_bbl_and_idx_dummy_commands;
869	    &translate;	# Destructive!
870	}
871	&extract_external_references($FILE) ;
872	&style_sheet;
873	&close_dbm_database;
874	&cleanup();
875
876#JCL: read warnings from file to $warnings
877	local($warnings) = &get_warnings;
878	print "\n\n*********** WARNINGS ***********  \n$warnings"
879	    if ($warnings || $NO_IMAGES || $IMAGES_ONLY);
880	&image_cache_message if ($NO_IMAGES || $IMAGES_ONLY);
881	&image_message if ($warnings =~ /Failed to convert/io);
882	undef $warnings;
883
884# JCL - generate directory index entry.
885# Yet, a hard link, cause Perl lacks symlink() on some systems.
886	do {
887	    print "PCT: EXTN: $EXTN\n" if ($VERBOSITY > 5) ;
888	    local($EXTN) = $EXTN;
889	    $EXTN =~ s/_\w+(\.html?)/$1/ if ($frame_main_name);
890	    print "PCT: EXTN: $EXTN\n" if ($VERBOSITY > 5) ;
891	    local($from,$to) = (eval($LINKPOINT),eval($LINKNAME));
892	    print "PCT: from: $from / to: $to\n" if ($VERBOSITY > 5) ;
893	    if (length($from) && length($to) && ($from ne $to)) {
894		#frames may have altered $EXTN
895		$from =~ s/$frame_main_name(\.html?)/$1/ if ($frame_main_name);
896		$to =~ s/$frame_main_name(\.html?)/$1/ if ($frame_main_name);
897		print "PCT: from: $from / to: $to\n" if ($VERBOSITY > 5) ;
898		L2hos->Unlink($to);
899		L2hos->Link($from,$to);
900	    }
901	} unless ($NO_AUTO_LINK || !($LINKPOINT) || !($LINKNAME));
902
903	&html_validate if ($HTML_VALIDATE && $HTML_VALIDATOR);
904
905# Go back to the source directory
906	chdir($orig_cwd);
907        $TEST_MODE = $DESTDIR if($TEST_MODE); # save path
908	$DESTDIR = '';
909	$OUT_NODE = 0 unless $FIXEDDIR;
910	$STYLESHEET = '' if ($STYLESHEET =~ /^\Q$FILE./);
911    }
912    print "\nUnknown commands: ". join(" ",keys %unknown_commands)
913	if %unknown_commands;
914###MEH -- math support
915    print "\nMath commands outside math: " .
916	join(" ",keys %commands_outside_math) .
917	    "\n  Output may look weird or may be faulty!\n"
918		if %commands_outside_math;
919    print "\nDone.\n";
920    if($TEST_MODE) {
921      $TEST_MODE =~ s:[$dd$dd]+$::;
922      print "\nTo view the results, point your browser at:\n",
923        L2hos->path2URL(L2hos->Make_directory_absolute($TEST_MODE).$dd.
924        "index$EXTN"),"\n";
925    }
926    $end_time = time;
927    $total_time = $end_time - $start_time;
928    print STDOUT join(' ',"Timing:",$total_time,"seconds\n")
929	if ($TIMING||$DEBUG||($VERBOSITY > 2));
930    $_;
931}
932
933sub open_dbm_database {
934    # These are DBM (unix DataBase Management) arrays which are actually
935    # stored in external files. They are used for communication between
936    # the main process and forked child processes;
937    print STDOUT "\n"; # this mysteriously prevents a core dump !
938
939    dbmopen(%verb, "$TMP_${dd}verb",0755);
940#    dbmopen(%verbatim, "$TMP_${dd}verbatim",0755);
941    dbmopen(%verb_delim, "$TMP_${dd}verb_delim",0755);
942    dbmopen(%expanded,"$TMP_${dd}expanded",0755);
943# Holds max_id, verb_counter, verbatim_counter, eqn_number
944    dbmopen(%global, "$TMP_${dd}global",0755);
945# Hold style sheet information
946    dbmopen(%env_style, "$TMP_${dd}envstyles",0755);
947    dbmopen(%txt_style, "$TMP_${dd}txtstyles",0755);
948    dbmopen(%styleID, "$TMP_${dd}styleIDs",0755);
949
950# These next two are used during off-line image conversion
951# %new_id_map maps image id's to page_numbers of the images in images.tex
952# %image_params maps image_ids to conversion parameters for that image
953    dbmopen(%new_id_map, "$TMP_${dd}ID_MAP",0755);
954    dbmopen(%img_params, "$TMP_${dd}IMG_PARAMS",0755);
955    dbmopen(%orig_name_map, "$TMP_${dd}ORIG_MAP",0755);
956
957    $global{'max_id'} = ($global{'max_id'} | 0);
958    &read_mydb(\%verbatim, "verbatim");
959    $global{'verb_counter'} = ($global{'verb_counter'} | 0);
960    $global{'verbatim_counter'} = ($global{'verbatim_counter'} | 0);
961
962    &read_mydb(\%new_command, "new_command");
963    &read_mydb(\%renew_command, "renew_command");
964    &read_mydb(\%provide_command, "provide_command");
965    &read_mydb(\%new_theorem, "new_theorem");
966    &read_mydb(\%new_environment, "new_environment");
967    &read_mydb(\%dependent, "dependent");
968#    &read_mydb(\%env_style, "env_style");
969#    &read_mydb(\%styleID, "styleID");
970    # MRO: Why should we use read_mydb instead of catfile?
971    $preamble = &catfile(&_dbname("preamble"),1) || '';
972    $prelatex = &catfile(&_dbname("prelatex"),1) || '';
973    $aux_preamble = &catfile(&_dbname("aux_preamble"),1) || '';
974    &restore_critical_variables;
975}
976
977sub close_dbm_database {
978    &save_critical_variables;
979    dbmclose(%verb); undef %verb;
980#    dbmclose(%verbatim); undef %verbatim;
981    dbmclose(%verb_delim); undef %verb_delim;
982    dbmclose(%expanded); undef %expanded;
983    dbmclose(%global); undef %global;
984    dbmclose(%env_style); undef %env_style;
985    dbmclose(%style_id); undef %style_id;
986    dbmclose(%new_id_map); undef %new_id_map;
987    dbmclose(%img_params); undef %img_params;
988    dbmclose(%orig_name_map); undef %orig_name_map;
989    dbmclose(%txt_style); undef %txt_style;
990    dbmclose(%styleID); undef %styleID;
991}
992
993sub clear_images_dbm_database {
994    # <Added calls to dbmclose dprhws>
995    # %new_id_map will be used by the off-line image conversion process
996    #
997    dbmclose(%new_id_map);
998    dbmclose(%img_params);
999    dbmclose(%orig_name_map);
1000    undef %new_id_map;
1001    undef %img_params;
1002    undef %orig_name_map;
1003    dbmopen(%new_id_map, "$TMP_${dd}ID_MAP",0755);
1004    dbmopen(%img_params, "$TMP_${dd}IMG_PARAMS",0755);
1005    dbmopen(%orig_name_map, "$TMP_${dd}ORIG_MAP",0755);
1006}
1007
1008sub initialise_sections {
1009    local($key);
1010    foreach $key (keys %numbered_section) {
1011	$global{$key} = $numbered_section{$key}}
1012}
1013
1014sub save_critical_variables {
1015    $global{'math_markup'} = $NO_MATH_MARKUP;
1016    $global{'charset'} = $CHARSET;
1017    $global{'charenc'} = $charset;
1018    $global{'language'} = $default_language;
1019    $global{'isolatin'} = $ISOLATIN_CHARS;
1020    $global{'unicode'} = $UNICODE_CHARS;
1021    if ($UNFINISHED_ENV) {
1022	$global{'unfinished_env'} = $UNFINISHED_ENV;
1023	$global{'replace_end_env'} = $REPLACE_END_ENV;
1024    }
1025    $global{'unfinished_comment'} = $UNFINISHED_COMMENT;
1026    if (@UNMATCHED_OPENING) {
1027	$global{'unmatched'} = join(',',@UNMATCHED_OPENING);
1028    }
1029}
1030
1031sub restore_critical_variables {
1032    $NO_MATH_MARKUP = ($global{'math_markup'}|
1033	(defined $NO_MATH_MARKUP ? $NO_MATH_MARKUP:1));
1034    $CHARSET = ($global{'charset'}| $CHARSET);
1035    $charset = ($global{'charenc'}| $charset);
1036    $default_language = ($global{'language'}|
1037	(defined $default_language ? $default_language:'english'));
1038    $ISOLATIN_CHARS = ($global{'isolatin'}|
1039	(defined $ISOLATIN_CHARS ? $ISOLATIN_CHARS:0));
1040    $UNICODE_CHARS = ($global{'unicode'}|
1041	(defined $UNICODE_CHARS ? $UNICODE_CHARS:0));
1042    if ($global{'unfinished_env'}) {
1043	$UNFINISHED_ENV = $global{'unfinished_env'};
1044	$REPLACE_END_ENV = $global{'replace_end_env'};
1045    }
1046    $UNFINISHED_COMMENT = $global{'unfinished_comment'};
1047    if ($global{'unmatched'}) {
1048	@UNMATCHED_OPENING = split(',',$global{'unmatched'});
1049    }
1050
1051    # undef any renewed-commands...
1052    # so the new defs are read from %new_command
1053    local($cmd,$key,$code);
1054    foreach $key (keys %renew_command) {
1055	$cmd = "do_cmd_$key";
1056	$code = "undef \&$cmd"; eval($code) if (defined &$cmd);
1057	if ($@) { print "\nundef \&do_cmd_$cmd failed"}
1058    }
1059}
1060
1061#JCL: The warnings should have been handled within the DBM database.
1062# Unfortunately if the contents of an array are more than ~900 (system
1063# dependent) chars long then dbm cannot handle it and gives error messages.
1064sub write_warnings { #clean
1065    my ($str) = @_;
1066    $str .= "\n" unless($str =~ /\n$/);
1067    print STDOUT "\n *** Warning: $str\n" if ($VERBOSITY > 1);
1068    my $warnings = '';
1069    if(-f 'WARNINGS') {
1070        $warnings = &catfile('WARNINGS') || '';
1071    }
1072    return () if ($warnings =~ /\Q$str\E/);
1073    if(open(OUT,">>WARNINGS")) {
1074        print OUT $str;
1075        close OUT;
1076    } else {
1077        print "\nError: Cannot append to 'WARNINGS': $!\n";
1078    }
1079}
1080
1081sub get_warnings {
1082    return &catfile('WARNINGS',1) || '';
1083}
1084
1085sub analyze_bacronyms {
1086    local($_) = @_ ;
1087    print "PCT: analyze_bacronyms: $_\n" if ($VERBOSITY > 12) ;
1088    #
1089    #
1090    my $bcontents = &translate_environments($_) ;
1091    print "PCT: analyze_bacronyms: content: $bcontents\n" if ($VERBOSITY > 15) ;
1092    my @keys = sort { $a cmp $b } keys %bacronyms;
1093    foreach $bkey ( @keys ) {
1094	print STDOUT "Key = $bkey - Value = " . $bacronyms{$bkey}{'value'} . "\n"  if ($VERBOSITY > 10) ;
1095    }
1096}
1097
1098# MRO: Standardizing
1099sub catfile {
1100    my ($file,$ignore) = @_;
1101    unless(open(CATFILE,"<$file")) {
1102        print "\nError: Cannot read '$file': $!\n"
1103            unless($ignore);
1104        return undef;
1105    }
1106    local($/) = undef; # slurp in whole file
1107    my $contents = <CATFILE>;
1108    close(CATFILE);
1109    #
1110    # This is a hack... a bad one to locate bacronyms earlier
1111    if ($contents =~ /bacronyms\.tex/) {
1112	my $bcontents = $contents ;
1113	&analyze_bacronyms($bcontents) ;
1114    }
1115    $contents;
1116}
1117
1118
1119sub html_validate {
1120    my ($extn) = $EXTN;
1121    if ($EXTN !~ /^\.html?$/i) {
1122	$extn =~ s/^[^\.]*(\.html?)$/$1/;
1123    }
1124    print "\n *** Validating ***\n";
1125    my @htmls = glob("*$extn");
1126    my $file;
1127    foreach $file (@htmls) {
1128      system("$HTML_VALIDATOR $file");
1129    }
1130}
1131
1132sub lost_argument {
1133    local($cmd) = @_;
1134    &write_warnings("\nincomplete argument to command: \\$cmd");
1135}
1136
1137
1138# These subroutines should have been handled within the DBM database.
1139# Unfortunately if the contents of an array are more than ~900 (system
1140# dependent) chars long then dbm cannot handle it and gives error messages.
1141# So here we save and then read the contents explicitly.
1142sub write_mydb {
1143    my ($db, $key, $str) = @_;
1144    &write_mydb_simple($db, "\n$mydb_mark#$key#$str");
1145}
1146
1147# generate the DB file name from the DB name
1148sub _dbname {
1149    "$TMP_$dd$_[0]";
1150}
1151
1152sub write_mydb_simple {
1153    my ($db, $str) = @_;
1154    my $file = &_dbname($db);
1155    if(open(DB,">>$file")) {
1156        print DB $str;
1157        close DB;
1158    } else {
1159        print "\nError: Cannot append to '$file': $!\n";
1160    }
1161}
1162
1163sub clear_mydb {
1164    my ($db) = @_;
1165    my $file = &_dbname($db);
1166    if(open(DB,">$file")) {
1167        close DB;
1168    } else {
1169        print "\nError: Cannot clear '$file': $!\n";
1170    }
1171}
1172
1173# Assumes the existence of a DB file which contains
1174# sequences of e.g. verbatim counters and verbatim contents.
1175sub read_mydb {
1176    my ($dbref,$name) = @_;
1177    my $contents = &catfile(&_dbname($name),1);
1178    return '' unless(defined $contents);
1179    my @tmp = split(/\n$mydb_mark#([^#]*)#/, $contents);
1180    my $i = 1;	# Ignore the first element at 0
1181    print "\nDBM: $name open..." if ($VERBOSITY > 2);
1182    while ($i < scalar(@tmp)) {
1183	my $tmp1 = $tmp[$i];
1184        my $tmp2 = $tmp[++$i];
1185	$$dbref{$tmp1} = defined $tmp2 ? $tmp2 : '';
1186	++$i;
1187    };
1188    $contents;
1189}
1190
1191
1192# Reads in a latex generated file (e.g. .bbl or .aux)
1193# It returns success or failure
1194# ****** and binds $_ in the caller as a side-effect ******
1195sub process_ext_file {
1196    local($ext) = @_;
1197    local($found, $extfile,$dum,$texpath);
1198    $extfile =  $EXTERNAL_FILE||$FILE;
1199    local($file) = &fulltexpath("$extfile.$ext");
1200    $found = 0;
1201    &write_warnings(
1202	    "\n$extfile.$EXT is newer than $extfile.$ext: Please rerun latex" . ## AYS
1203	    (($ext =~ /bbl/) ? " and bibtex.\n" : ".\n"))
1204	if ( ($found = (-f $file)) &&
1205	    &newer(&fulltexpath("$extfile.$EXT"), $file)); ## AYS
1206    if ((!$found)&&($extfile =~ /\.$EXT$/)) {
1207	$file = &fulltexpath("$extfile");
1208	&write_warnings(
1209	    "\n$extfile is newer than $extfile: Please rerun latex" . ## AYS
1210	    (($ext =~ /bbl/) ? " and bibtex.\n" : ".\n"))
1211	    if ( ($found = (-f $file)) &&
1212		&newer(&fulltexpath("$extfile"), $file)); ## AYS
1213    }
1214
1215    # check in other directories on the $TEXINPUTS paths
1216    if (!$found) {
1217	foreach $texpath (split /$envkey/, $TEXINPUTS ) {
1218	    $file = "$texpath$dd$extfile.$ext";
1219	    last if ($found = (-f $file));
1220	}
1221    }
1222    if ( $found ) {
1223	print "\nReading $ext file: $file ...";
1224	# must allow @ within control-sequence names
1225	$dum = &do_cmd_makeatletter();
1226	&slurp_input($file);
1227	if ($ext =~ /bbl/) {
1228	    # remove the \newcommand{\etalchar}{...} since not needed
1229	    s/^\\newcommand\{\\etalchar\}[^\n\r]*[\n\r]+//s;
1230	}
1231	&pre_process;
1232	&substitute_meta_cmds if (%new_command || %new_environment);
1233	if ($ext eq "aux") {
1234            my $latex_pathname = L2hos->path2latex($file);
1235	    $aux_preamble .=
1236		"\\AtBeginDocument{\\makeatletter\n\\input $latex_pathname\n\\makeatother\n}\n";
1237	    local(@extlines) = split ("\n", $_);
1238	    print " translating ".(0+@extlines). " lines " if ($VERBOSITY >1);
1239	    local($eline,$skip_to); #$_ = '';
1240	    foreach $eline (@extlines) {
1241		if ($skip_to) { next unless ($eline =~ s/$O$skip_to$C//) }
1242		$skip_to = '';
1243		# skip lines added for pdfTeX/hyperref compatibility
1244		next if ($eline =~ /^\\(ifx|else|fi|global \\let|gdef|AtEndDocument|let )/);
1245		# remove \index and \label commands, else invalid links may result
1246		$eline =~ s/\\(index|label)\s*($O\d+$C).*\2//g;
1247		if ($eline =~ /\\(old)?contentsline/) {
1248		    do { local($_,$save_AUX) = ($eline,$AUX_FILE);
1249		    $AUX_FILE = 0;
1250		    &wrap_shorthand_environments;
1251		    #footnote markers upset the numbering
1252		    s/\\footnote(mark|text)?//g;
1253		    $eline = &translate_environments($_);
1254		    $AUX_FILE = $save_AUX;
1255		    undef $_ };
1256		} elsif ($eline =~ s/^\\\@input//) {
1257		    &do_cmd__at_input($eline);
1258		    $eline = '';
1259		} elsif ($eline =~ s/^\\\@setckpt$O(\d+)$C//) {
1260		    $skip_to = $1; next;
1261		}
1262#	    $eline =~ s/$image_mark#([^#]+)#/print "\nIMAGE:",$img_params{$1},"\n";''/e;
1263#		$_ .= &translate_commands(&translate_environments($eline));
1264		$_ .= &translate_commands($eline) if $eline;
1265	    }
1266	    undef @extlines;
1267	} elsif ($ext =~ /$caption_suffixes/) {
1268	    local(@extlines) = split ("\n", $_);
1269	    print " translating ".(0+@extlines). " lines "if ($VERBOSITY >1);
1270	    local($eline); $_ = '';
1271	    foreach $eline (@extlines) {
1272		# remove \index and \label commands, else invalid links may result
1273		$eline =~ s/\\(index|label)\s*($O\d+$C).*\2//gso;
1274                if ($eline =~ /\\(old)?contentsline/) {
1275		    do { local($_,$save_PREAMBLE) = ($eline,$PREAMBLE);
1276		    $PREAMBLE = 0;
1277                    &wrap_shorthand_environments;
1278                    $eline = &translate_environments($_);
1279		    $PREAMBLE = $save_PREAMBLE;
1280                    undef $_ };
1281                }
1282		$_ .= &translate_commands($eline);
1283	    }
1284	    undef @extlines;
1285	} else {
1286	    print " wrapping " if ($VERBOSITY >1);
1287	    &wrap_shorthand_environments;
1288	    $_ = &translate_commands(&translate_environments($_));
1289	    print " translating " if ($VERBOSITY >1);
1290	}
1291	print "\n processed size: ".length($_)."\n" if($VERBOSITY>1);
1292	$dum = &do_cmd_makeatother();
1293    } else {
1294	print "\n*** Could not find file: $file ***\n" if ($DEBUG)
1295    };
1296    $found;
1297}
1298
1299sub deal_with_texinputs {
1300# The dot precedes all, this let's local files override always.
1301# The dirs we want are given as parameter list.
1302    if(!$TEXINPUTS) { $TEXINPUTS = '.' }
1303    elsif ($TEXINPUTS =~ /^$envkey/) {
1304	$TEXINPUTS = '.'.$TEXINPUTS
1305    };
1306    if ($ROOTED) {$TEXINPUTS .= "$envkey$FIXEDDIR"}
1307    $TEXINPUTS = &absolutize_path($TEXINPUTS);
1308    $ENV{'TEXINPUTS'} = join($envkey,".",@_,$TEXINPUTS,$ENV{'TEXINPUTS'});
1309    $TEXINPUTS = $ENV{'TEXINPUTS'} ;
1310    print "deal_with_texinputs: " . $ENV{'TEXINPUTS'} . "\n" ;
1311}
1312
1313# provided by Fred Drake
1314sub absolutize_path {
1315    my ($path) = @_;
1316    my $npath = '';
1317    foreach $dir (split /$envkey/o, $path) {
1318        $npath .= L2hos->Make_directory_absolute($dir) . $envkey;
1319    }
1320    $npath =~ s/$envkey$//;
1321    $npath;
1322}
1323
1324sub add_document_info_page {
1325    # Uses $outermost_level
1326    # Nasty race conditions if the next two are done in parallel
1327    local($X) = ++$global{'max_id'};
1328    local($Y) = ++$global{'max_id'};
1329    ###MEH -- changed for math support: no underscores in commandnames
1330    $_ = join('', $_
1331	      , (($MAX_SPLIT_DEPTH <= $section_commands{$outermost_level})?
1332		 "\n<HR>\n" : '')
1333	      , "\\$outermost_level", "*"
1334	      , "$O$X$C$O$Y$C\\infopagename$O$Y$C$O$X$C\n",
1335	      , " \\textohtmlinfopage");
1336}
1337
1338
1339# For each style file name in TMP_styles (generated by texexpand) look for a
1340# perl file in $LATEX2HTMLDIR/styles and load it.
1341sub load_style_file_translations {
1342    local($_, $style, $options, $dir);
1343    print "\n";
1344    if ($TEXDEFS) {
1345	foreach $dir (split(/$envkey/,$LATEX2HTMLSTYLES)) {
1346	    if (-f ($_ = "$dir${dd}texdefs.perl")) {
1347		print "\nLoading $_...";
1348		require ($_);
1349		$styles_loaded{'texdefs'} = 1;
1350		last;
1351	    }
1352	}
1353    }
1354
1355    # packages automatically implemented
1356    local($auto_styles) = $AUTO_STYLES;
1357    $auto_styles .= 'array|' if ($HTML_VERSION > 3.1);
1358    $auto_styles .= 'tabularx|' if ($HTML_VERSION > 3.1);
1359    $auto_styles .= 'theorem|';
1360
1361    # these are not packages, but can appear as if class-options
1362    $auto_styles .= 'psamsfonts|';
1363    $auto_styles .= 'noamsfonts|';
1364
1365    $auto_styles =~ s/\|$//;
1366
1367    if(open(STYLES, "<$TMP_${dd}styles")) {
1368        while(<STYLES>) {
1369            if(s/^\s*(\S+)\s*(.*)$/$style = $1; $options = $2;/eo) {
1370                &do_require_package($style);
1371	        $_ = $DONT_INCLUDE;
1372	        s/:/|/g;
1373	        &write_warnings(join('',"No implementation found for style ",$style,"\n"))
1374		    unless ($styles_loaded{$style} || $style =~ /^($_)$/
1375			|| $style =~ /$auto_styles/);
1376
1377                # MRO: Process options for packages
1378                &do_package_options($style,$options) if($options);
1379            }
1380        }
1381        close(STYLES);
1382    } else {
1383        print "\nError: Cannot read '$TMP_${dd}styles': $!\n";
1384    }
1385}
1386
1387################## Weird Special case ##################
1388
1389# The new texexpand can be told to leave in \input and \include
1390# commands which contain code that the translator should simply pass
1391# to latex, such as the psfig stuff.  These should still be seen by
1392# TeX, so we add them to the preamble ...
1393
1394sub do_include_lines {
1395    while (s/$include_line_rx//o) {
1396	local($include_line) = &revert_to_raw_tex($&);
1397	&add_to_preamble ('include', $include_line);
1398    }
1399}
1400
1401########################## Preprocessing ############################
1402
1403# JCL(jcl-verb)
1404# The \verb declaration and the verbatim environment contain simulated
1405# typed text and should not be processed. Characters such as $,\,{,and }
1406# loose their special meanings and should not be considered when marking
1407# brackets etc. To achieve this \verb declarations and the contents of
1408# verbatim environments are replaced by markers. At the end the original
1409# text is put back into the document.
1410# The markers for verb and verbatim are different so that these commands
1411# can be restored to what the raw input was just in case they need to
1412# be passed to latex.
1413
1414sub pre_process {
1415    # Modifies $_;
1416    #JKR: We need support for some special environments.
1417    # This has to be here, because  they might contain
1418    # structuring commands like \section etc.
1419    local(%comments);
1420    print "PCT: pre_process: before: $_ \n" if ($VERBOSITY > 5) ;
1421    &pre_pre_process if (defined &pre_pre_process);
1422    print "PCT: pre_process: after: $_ \n" if ($VERBOSITY > 5) ;
1423    s/\\\\/\\\\ /go;		# Makes it unnecessary to look for escaped cmds
1424    &replace_html_special_chars;
1425    # Remove fake environment which should be invisible to LaTeX2HTML.
1426    s/\001//m;
1427    s/[%]end\s*{latexonly}/\001/gom;
1428    s/[%]begin\s*{latexonly}([^\001]*)\001/%/gos;
1429    s/\001//m;
1430
1431    &preprocess_alltt if defined(&preprocess_alltt);
1432
1433    $KEEP_FILE_MARKERS = 1;
1434    if ($KEEP_FILE_MARKERS) {
1435#	if (s/%%% TEXEXPAND: \w+ FILE( MARKER)? (\S*).*/
1436#	    '<tex2html_'.($1?'':'end').'file>'.qq|#$2#|."\n"/em) {
1437#	    $_ = "<tex2html_file>#$2#\n". $_ };
1438	#RRM: ignore \n at end of included file, else \par may result
1439	if (s/(\n{1,2})?%%% TEXEXPAND: \w+ FILE( MARKER)? (\S*).*\n?/
1440	    ($2?$1:"\n").'<tex2html_'.($2?'':'end').'file>'.qq|#$3#|."\n"/em) {
1441	    $_ = "<tex2html_file>#$3#\n". $_ };
1442    } else {
1443	s/%%% TEXEXPAND[^\n]*\n//gm;
1444    }
1445
1446    # Move all LaTeX comments into a local list
1447    s/([ \t]*(^|\G|[^\\]))(%.*(\n[ \t]*|$))/print "%";
1448	$comments{++$global{'verbatim_counter'}} = "$3";
1449	&write_mydb("verbatim", $global{'verbatim_counter'}, $3);
1450	"$1$comment_mark".$global{'verbatim_counter'}."\n"/mge;
1451    # Remove the htmlonly-environment
1452    s/\\begin\s*{htmlonly}\s*\n?//gom;
1453    s/\\end\s*{htmlonly}\s*\n?//gom;
1454    # Remove enviroments which should be invisible to LaTeX2HTML.
1455    s/\n[^%\n]*\\end\s*\{latexonly\}\s*\n?/\001/gom;
1456    s/((^|\n)[^%\n]*)\\begin\s*\{latexonly\}([^\001]*)\001/$1/gom;
1457    s/\\end\s*\{comment\}\s*\n?/\001/gom;
1458    s/\\begin\s*\{comment\}([^\001]*)\001//gom;
1459
1460    # this used to be earlier, but that can create problems with comments
1461    &wrap_other_environments if (%other_environments);
1462
1463#    s/\\\\/\\\\ /go;		# Makes it unnecessary to look for escaped cmds
1464    local($next, $esc_del);
1465    &normalize_language_changes;
1466    # Patches by #JKR, #EI#, #JCL(jcl-verb)
1467
1468    #protect \verb|\begin/end....|  parts, for LaTeX documentation
1469    s/(\\verb\*?(.))\\(begin|end)/$1\003$3/g;
1470
1471    local(@processedV);
1472    local($opt, $style_info,$before, $contents, $after, $env);
1473    while (($UNFINISHED_COMMENT)||
1474  (/\\begin\s*($opt_arg_rx)?\s*\{($verbatim_env_rx|$keepcomments_rx)\}/o)) {
1475	($opt, $style_info) = ($1,$2);
1476	$before=$contents=$after=$env='';
1477	if ($UNFINISHED_COMMENT) {
1478	    $UNFINISHED_COMMENT =~ s/([^:]*)::(\d+)/$env=$1;$after=$_;
1479	        $before = join("",$unfinished_mark,$env,$2,"#");''/e;
1480	    print "\nfound the lost \\end{$env}\n";
1481	}
1482	#RRM: can we avoid copying long strings here ?
1483	#     maybe this loop can be an  s/.../../s  with (.*?)
1484	#
1485	($before, $after, $env) = ($`, $', $3) unless ($env);
1486	if (!($before =~
1487     /\\begin(\s*\[[^\]]*\]\s*)?\{($verbatim_env_rx|$keepcomments_rx)\}/)) {
1488	    push(@processedV,$before);
1489	    print "'";$before = '';
1490	}
1491 	if ($after =~ /\s*\\end\{$env[*]?\}/) { # Must NOT use the s///o option!!!
1492	    ($contents, $after) = ($`, $');
1493 	    $contents =~ s/^\n+/\n/s;
1494# 	    $contents =~ s/\n+$//s;
1495
1496	    # re-insert comments
1497	    $contents =~ s/$comment_mark(\d+)\n?/$comments{$1}/g;
1498#	    $contents =~ s/$comment_mark(\d+)/$verbatim{$1}/g;
1499
1500	    # revert '\\ ' -> '\\' only once
1501	    if ($env =~ /rawhtml|$keepcomments_rx/i) {
1502		$contents = &revert_to_raw_tex($contents);
1503	    } else {
1504		$contents =~ s/([^\\](?:\\\\)*\\)([$html_escape_chars])/$1.&special($2)/geos;
1505		$contents =~ s/\\\\ /\\\\/go;
1506	    }
1507
1508	    if ($env =~/$keepcomments_rx/) {
1509		$verbatim{++$global{'verbatim_counter'}} = "$contents";
1510	    } else {
1511		&write_mydb("verbatim", ++$global{'verbatim_counter'}, $contents);
1512	    }
1513#	    $verbatim{$global{'verbatim_counter'}} = "$contents" if ($env =~/$keepcomments_rx/);
1514#	    $verbatim{$global{'verbatim_counter'}} = "$contents";
1515
1516	    if ($env =~ /rawhtml|$keepcomments_rx/i) {
1517		if ($before) {
1518		    $after = join("",$verbatim_mark,$env
1519			      ,$global{'verbatim_counter'},"#",$after);
1520		} else {
1521		    push (@processedV, join("",$verbatim_mark,$env
1522			   ,$global{'verbatim_counter'},"#"));
1523		}
1524	    } elsif ($env =~ /tex2html_code/) {
1525		if ($before) {
1526		    $after = join("","\\begin", $opt, "\{verbatim_code\}"
1527			  , $verbatim_mark,$env
1528			  , $global{'verbatim_counter'},"#"
1529			  , "\\end\{verbatim_code\}",$after);
1530		} else {
1531		    push (@processedV
1532			  , join("","\\begin", $opt, "\{verbatim_code\}"
1533				 , $verbatim_mark,$env
1534				 , $global{'verbatim_counter'},"#"
1535				 , "\\end\{verbatim_code\}"));
1536		}
1537	    } else {
1538		if ($before) {
1539		    $after = join("","\\begin", $opt, "\{tex2html_preform\}"
1540			  , $verbatim_mark,$env
1541			  , $global{'verbatim_counter'},"#"
1542			  , "\\end\{tex2html_preform\}",$after);
1543		} else {
1544		    push (@processedV
1545			  , join("","\\begin", $opt, "\{tex2html_preform\}"
1546				 , $verbatim_mark,$env
1547				 , $global{'verbatim_counter'},"#"
1548				 , "\\end\{tex2html_preform\}" ));
1549		}
1550	    }
1551	} else {
1552	    print "Cannot find \\end{$env}\n";
1553	    $after =~ s/$comment_mark(\d+)\n?/$comments{$1}/g;
1554#	    $after =~ s/$comment_mark(\d+)/$verbatim{$1}/g;
1555	    if ($env =~ /rawhtml|$keepcomments_rx/i) {
1556                $after = &revert_to_raw_tex($contents);
1557	    } else {
1558		$after =~ s/([^\\](?:\\\\)*\\)([$html_escape_chars])/$1.&special($2)/geos;
1559                $after =~ s/\\\\ /\\\\/go;
1560	    }
1561	    if ($env =~/$keepcomments_rx/) {
1562                $verbatim{++$global{'verbatim_counter'}} = "$after";
1563	    } else {
1564                &write_mydb("verbatim", ++$global{'verbatim_counter'}, $after );
1565	    }
1566	    $after = join("",$unfinished_mark,$env
1567			  ,$global{'verbatim_counter'},"#");
1568	}
1569	$_ = join("",$before,$after);
1570    }
1571    print STDOUT "\nsensitive environments found: ".(int(0+@processedV/2))." "
1572	if((@processedV)&&($VERBOSITY > 1));
1573    $_ = join('',@processedV, $_); undef @processedV;
1574
1575    #restore \verb|\begin/end....|  parts, for LaTeX documentation
1576#    $_ =~ s/(\\verb\W*?)\003(begin|end)/$1\\$2/g;
1577    $_ =~ s/(\\verb(;SPM\w+;|\W*?))\003(begin|end)/$1\\$3/g;
1578
1579    # Now do the \verb declarations
1580    # Patches by: #JKR, #EI#, #JCL(jcl-verb)
1581    # Tag \verb command and legal opening delimiter with unique number.
1582    # Replace tagged ones and its contents with $verb_mark & id number if the
1583    # closing delimiter can be found. After no more \verb's are to tag, revert
1584    # tagged one's to the original pattern.
1585    local($del,$contents,$verb_rerun);
1586    local($id) = $global{'verb_counter'};
1587    # must tag only one alternation per loop
1588    ##RRM: can this be speeded up using a list ??
1589    my $vbmark = $verb_mark;
1590    while (s/\\verb(\t*\*\t*)(\S)/"<verb$1".++$id.">$2"/e ||
1591	    s/\\verb()(\;SPM\w+\;|[^a-zA-Z*\s])/"<verb$1".++$id.">$2"/e ||
1592	    s/\\verb(\t\t*)([^*\s])/"<verb$1".++$id.">$2"/e) {
1593
1594	$del = $2;
1595	#RRM: retain knowledge of whether \verb* or \verb
1596	$vb_mark = ($1 =~/^\s*\*/? $verbstar_mark : $verb_mark);
1597	$esc_del = &escape_rx_chars($del);
1598	$esc_del = '' if (length($del) > 2);
1599
1600	# try to find closing delimiter and substitute the complete
1601	# statement with $verb_mark or $verbstar_mark
1602#	s/(<verb[^\d>]*$id>[\Q$del\E])([^$esc_del\n]*)([\Q$del\E]|$comment_mark(\d+)\n?)/
1603	s/(<verb[^\d>]*$id>\Q$del\E)([^$esc_del\n]*?)(\Q$del\E|$comment_mark(\d+)\n?)/
1604	    $contents=$2;
1605	    if ($4) { $verb_rerun = 1;
1606		join('', "\\verb$del", $contents, $comments{$4})
1607	    } else {
1608		$contents =~ s|\\\\ |\\\\|g;
1609		$contents =~ s|\n| |g;
1610		$verb{$id}=$contents;
1611		$verb_delim{$id}=$del;
1612		join('',$vb_mark,$id,$verb_mark)
1613	    }
1614	/e;
1615    }
1616    $global{'verb_counter'} = $id;
1617    # revert changes to fake verb statements
1618    s/<verb([^\d>]*)\d+>/\\verb$1/g;
1619
1620    #JKR: the comments include the linebreak and the following whitespace
1621#   s/([^\\]|^)(%.*\n[ \t]*)+/$1/gom; # Remove Comments but not % which may be meaningful
1622    s/((^|\n)$comment_mark(\d+))+//gom; # Remove comment markers on new lines, but *not* the trailing \n
1623    s/(\\\w+|(\W?))($comment_mark\d*\n?)/($2)? $2.$3:($1? $1.' ':'')/egm; # Remove comment markers, not after braces
1624#    s/(\W?)($comment_mark\d*\n?)/($1)? $1.$2:''/egm; # Remove comment markers, not after braces
1625    # Remove comment markers, but *not* the trailing \n
1626#  HWS:  Correctly remove multiple %%'s.
1627#
1628    s/\\%/\002/gm;
1629#    s/(%.*\n[ \t]*)//gm;
1630    s/(%[^\n]*\n)[ \t]*/$comment_mark\n/gm;
1631
1632    s/\002/\\%/gm;
1633
1634    local($tmp1,$tmp2);
1635    s/^$unfinished_mark$keepcomments_rx(\d+)#\n?$verbatim_mark$keepcomments_rx(\d+)#/
1636	$verbatim{$4}."\n\\end{$1}"/egm; # Raw TeX
1637    s/$verbatim_mark$keepcomments_rx(\d+)#/
1638	$tmp1 = $1;
1639	$tmp2 = &protect_after_comments($verbatim{$2});
1640	$tmp2 =~ s!\n$!!s;
1641	join ('', "\\begin{$tmp1}"
1642		, $tmp2
1643		, "\n\\end{$tmp1}"
1644		)/egm; # Raw TeX
1645    s/$unfinished_mark$keepcomments_rx(\d+)#/$UNFINISHED_COMMENT="$1::$2";
1646	"\\begin{$1}\n".$verbatim{$2}/egm; # Raw TeX
1647
1648    $KEEP_FILE_MARKERS = 1;
1649    if ($KEEP_FILE_MARKERS) {
1650	s/%%% TEXEXPAND: \w+ FILE( MARKER) (\S*).*\n/
1651	    '<tex2html_'.($1?'':'end').'file>'.qq|#.$2#\n|/gem;
1652    } else {
1653	s/%%% TEXEXPAND[^\n]*\n//gm;
1654    }
1655
1656    &mark_string($_);
1657
1658
1659    # attempt to remove the \html \latex and \latexhtml commands
1660    s/\\latex\s*($O\d+$C)(.*)\1//gm;
1661    s/\\latexhtml\s*($O\d+$C)(.*)\1\s*($O\d+$C)(.*)\3/$4/sg;
1662    s/\\html\s*($O\d+$C)(.*)\1/$2/sg;
1663    s/\\html\s*($O\d+$C)//gm;
1664
1665#    &make_unique($_);
1666}
1667
1668# RRM:  When comments are retained, then ensure that they are benign
1669# by removing \s and escaping braces,
1670# so that environments/bracing cannot become unbalanced.
1671sub protect_after_comments {
1672    my ($verb_text) = @_;
1673#    $verb_text =~ s/\%(.*)/'%'.&protect_helper($1)/eg;
1674    $verb_text =~ s/(^|[^\\])(\\\\)*\%(.*)/$1.$2.'%'.&protect_helper($3)/emg;
1675    $verb_text;
1676}
1677
1678sub protect_helper {
1679    my ($text) = @_;
1680    $text =~ s/\\/ /g;
1681    $text =~ s/(\{|\})/\\$1/g;
1682    $text;
1683}
1684
1685#
1686# Philippe Chauvat - 18-jan-2017
1687# This is the orginal version of make_comment
1688sub old_make_comment {
1689    local($type,$_) = @_;
1690    $_ =~ s/\\(index|label)\s*(($O|$OP)\d+($C|$CP)).*\2//sg;
1691    $_ = &revert_to_raw_tex($_);  s/^\n+//m;
1692    $_ =~ s/\\(index|label)\s*\{.*\}//sg;
1693    s/\-\-/- -/g; s/\-\-/- -/g; # cannot have -- inside a comment
1694    $_ = join('', '<!-- ', $type , "\n ", $_ , "\n -->" );
1695    $verbatim{++$global{'verbatim_counter'}} = $_;
1696    &write_mydb('verbatim', $global{'verbatim_counter'}, $_ );
1697    join('', $verbatim_mark, 'verbatim' , $global{'verbatim_counter'},'#')
1698}
1699#
1700# The changes made below are related to the way the content is handled
1701# Instead of making a comment, we define a <span></span> with class and id
1702# Making the right CSS (mainly: display: none or something else) will
1703# make the result just fine.
1704sub make_comment {
1705    local($type,$_) = @_;
1706    local ($bclassname,$bid) ;
1707    $_ =~ s/\\(index|label)\s*(($O|$OP)\d+($C|$CP)).*\2//sg;
1708    $_ = &revert_to_raw_tex($_);  s/^\n+//m;
1709    if ($type eq "MATH") {
1710	$_ =~ s/^\$// ; s/\$$// ;
1711	$_ =~ s/\\//g ;
1712    }
1713    $_ =~ s/\\(index|label)\s*\{.*\}//sg;
1714    $bclassname = "bhide_" . lc($type) ;
1715    $bid = "bhide_" . $global{'verbatim_counter'} . "_" . lc($type) ;
1716    $_ = join('', "\n",'<span class="',$bclassname,'" id="',$bid,'">', $_ , "</span>" );
1717    $verbatim{++$global{'verbatim_counter'}} = $_;
1718    &write_mydb('verbatim', $global{'verbatim_counter'}, $_ );
1719    join('', $verbatim_mark, 'verbatim' , $global{'verbatim_counter'},'#')
1720}
1721
1722sub wrap_other_environments {
1723    local($key, $env, $start, $end, $opt_env, $opt_start);
1724    foreach $key (keys %other_environments) {
1725	# skip bogus entries
1726	next unless ($env = $other_environments{$key});
1727	$key =~ s/:/($start,$end)=($`,$');':'/e;
1728
1729	if (($end =~ /^\#$/m) && ($start =~ /^\#/m)) {
1730	    # catch Indica pre-processor language switches
1731	    $opt_start = $';
1732	    if ($env =~ s/\[(\w*)\]//o) {
1733		$opt_env = join('','[', ($1 ? $1 : $opt_start ), ']');
1734	    }
1735	    local($next);
1736	    while ($_ =~ /$start\b/) {
1737		push(@pre_wrapped, $`, "\\begin\{pre_$env\}", $opt_env );
1738		$_=$';
1739		if (/(\n*)$end/) {
1740		    push(@pre_wrapped, $`.$1,"\\end\{pre_$env\}$1");
1741		    $_ = $';
1742		    if (!(s/^N(IL)?//o)) {$_ = '#'.$_ }
1743		} else {
1744		    print "\n *** unclosed $start...$end chunk ***\n";
1745		    last;
1746		}
1747	    }
1748	    $_ = join('', @pre_wrapped, $_);
1749	    undef @pre_wrapped;
1750
1751	} elsif (($end=~/^\n$/) && ($start =~ /^\#/)) {
1752	    # catch ITRANS pre-processor language info;  $env = 'nowrap';
1753	    local($ilang) = $start; $ilang =~ s/^\#//m;
1754	    s/$start\s*\=([^<\n%]*)\s*($comment_mark\d*|\n|%)/\\begin\{tex2html_$env\}\\ITRANSinfo\{$ilang\}\{$1\}\n\\end\{tex2html_$env\}$2/g;
1755
1756	} elsif (!$end &&($start =~ /^\#/m)) {
1757	    # catch Indica pre-processor input-mode switches
1758	    s/$start(.*)\n/\\begin\{tex2html_$env\}$&\\end\{tex2html_$env\}\n/g;
1759
1760	} elsif (($start eq $end)&&(length($start) == 1)) {
1761	    $start =~ s/(\W)/\\$1/; $end = $start;
1762	    s/([^$end])$start([^$end]+)$end/$1\\begin\{pre_$env\}$2\\end\{pre_$env\}/mg;
1763	} elsif ($start eq $end) {
1764	    if (!($start =~ /\#\#/)) {
1765		$start =~ s/(\W)/\\$1/g; $end = $start; }
1766	    local (@pre_wrapped);
1767	    local($opt); $opt = '[indian]' if ($start =~ /^\#\#$/m);
1768	    while ($_ =~ /$start/s) {
1769		push(@pre_wrapped, $` , "\\begin\{pre_$env\}$opt");
1770		$_=$';
1771		if (/$end/s) {
1772		    push(@pre_wrapped, $`, "\\end\{pre_$env\}");
1773		    $_ = $';
1774		} else {
1775		    print "\n *** unclosed $start...$end chunk ***\n";
1776		    last;
1777		}
1778	    }
1779	    $_ = join('', @pre_wrapped, $_);
1780	    undef @pre_wrapped;
1781	} elsif ($start && ($env =~ /itrans/)) {
1782	    # ITRANS is of this form
1783	    local($indic); if($start =~ /\#(\w+)$/m) {$indic = $1}
1784	    #include the language-name as an optional parameter
1785	    s/$start\b/\\begin\{pre_$env\}\[$indic\]/sg;
1786	    s/$end\b/\\end\{pre_$env\}/sg;
1787	} elsif (($start)&&($end)) {
1788	    s/$start\b/\\begin\{pre_$env\}/sg;
1789	    s/$end\b/\\end\{pre_$env\}/sg;
1790	}
1791    }
1792    $_;
1793}
1794
1795#################### Marking Matching Brackets ######################
1796
1797# Reads the entire input file and performs pre_processing operations
1798# on it before returning it as a single string. The pre_processing is
1799# done on separate chunks of the input file by separate Unix processes
1800# as determined by LaTeX \input commands, in order to reduce the memory
1801# requirements of LaTeX2HTML.
1802sub slurp_input_and_partition_and_pre_process {
1803    local($file) = @_;
1804    local(%string, @files, $pos);
1805    local ($count) =  1;
1806
1807    unless(open(SINPUT,"<$file")) {
1808        die "\nError: Cannot read '$file': $!\n";
1809    }
1810    local(@file_string);
1811    print STDOUT "$file" if ($VERBOSITY >1);
1812    while (<SINPUT>) {
1813	if (/TEXEXPAND: INCLUDED FILE MARKER (\S*)/) {
1814	    # Forking seems to screw up the rest of the input stream
1815	    # We save the current position ...
1816	    $pos = tell SINPUT;
1817	    print STDOUT " fork at offset $pos " if ($VERBOSITY >1);
1818            $string{'STRING'} = join('',@file_string); @file_string = ();
1819	    &write_string_out($count);
1820	    delete $string{'STRING'};
1821	    # ... so that we can return to it
1822	    seek(SINPUT, $pos, 0);
1823	    print STDOUT "\nDoing $1 ";
1824	    ++$count}
1825	else {
1826#	    $string{'STRING'} .= $_
1827	    push(@file_string,$_);
1828	}
1829    }
1830    $string{'STRING'} = join('',@file_string); @file_string = ();
1831    &write_string_out($count);
1832    delete $string{'STRING'};
1833    close SINPUT;
1834    @files = ();
1835    if(opendir(DIR, $TMP_)) {
1836        @files = sort grep(/^\Q$PARTITION_PREFIX\E\d+/, readdir(DIR));
1837        closedir(DIR);
1838    }
1839
1840    unless(@files) {
1841        die "\nFailed to read in document parts.\n".
1842	     "Look up section Globbing in the troubleshooting manual.\n";
1843    }
1844
1845    $count = 0;
1846    foreach $file (@files) {
1847	print STDOUT "\nappending file: $TMP_$dd$file " if ($VERBOSITY > 1);
1848        $_ .= (&catfile("$TMP_$dd$file") || '');
1849	print STDOUT "\ntotal length: ".length($_)." characters\n" if ($VERBOSITY > 1);
1850    }
1851    die "\nFailed to read in document parts (out of memory?).\n"
1852	unless length($_);
1853    print STDOUT "\ntotal length: ".length($_)." characters\n" if ($VERBOSITY > 1);
1854}
1855
1856sub write_string_out {
1857    local($count) = @_;
1858    if ($count < 10) {$count = '00'.$count}
1859    elsif ($count < 100) {$count = '0'.$count}
1860    local($pid);
1861    # All open unflushed streams are inherited by the child. If this is
1862    # not set then the parent will *not* wait
1863    $| = 1;
1864    # fork returns 0 to the child and PID to the parent
1865    &write_mydb_simple("prelatex", $prelatex);
1866    &close_dbm_database;
1867    unless ($CAN_FORK) {
1868	&do_write_string_out;
1869    } else {
1870	unless ($pid = fork) {
1871	    &do_write_string_out;
1872	    exit 0;
1873	};
1874	waitpid($pid,0);
1875    }
1876    &open_dbm_database;
1877}
1878
1879sub do_write_string_out {
1880    local($_);
1881    close (SINPUT) if($CAN_FORK);
1882    &open_dbm_database;
1883    $_ = delete $string{'STRING'};
1884    # locate blank-lines, for paragraphs.
1885    # Replace verbatim environments etc.
1886    &pre_process;
1887    # locate the blank lines for \par s
1888    &substitute_pars;
1889    # Handle newcommand, newenvironment, newcounter ...
1890    &substitute_meta_cmds;
1891    &wrap_shorthand_environments;
1892    print STDOUT "\n *** End-of-partition ***" if ($VERBOSITY > 1);
1893    if(open(OUT, ">$TMP_$dd$PARTITION_PREFIX$count")) {
1894        print OUT $_;
1895        close(OUT);
1896    } else {
1897        print "\nError: Cannot write '$TMP_$dd$PARTITION_PREFIX$count': $!\n";
1898    }
1899    print STDOUT $_ if ($VERBOSITY > 9);
1900    $preamble = join("\n",$preamble,@preamble); # undef @preamble;
1901    &write_mydb_simple("preamble", $preamble);
1902    # this was done earlier; it should not be repeated
1903    #&write_mydb_simple("prelatex", $prelatex);
1904    &write_mydb_simple("aux_preamble", $aux_preamble);
1905    &close_dbm_database;
1906}
1907
1908# Reads the entire input file into a
1909# single string.
1910sub slurp_input  {
1911    local($file) = @_;
1912    local(%string);
1913    if(open(INPUT,"<$file")) {
1914        local(@file_string);
1915        while (<INPUT>) {
1916	    push(@file_string, $_ );
1917        }
1918        $string{'STRING'} = join('',@file_string);
1919        close INPUT;
1920        undef @file_string;
1921    } else {
1922        print "\nError: Cannot read '$file': $!\n";
1923    }
1924    $_ = delete $string{'STRING'}; # Blow it away and return the result
1925}
1926
1927# MRO: make them more efficient
1928sub special {
1929    $html_specials{$_[0]} || $_[0];
1930}
1931
1932sub special_inv {
1933    $html_specials_inv{$_[0]} || $_[0];
1934}
1935
1936sub special_html {
1937    $html_special_entities{$_[0]} || $_[0];
1938}
1939
1940sub special_html_inv {
1941    $html_spec_entities_inv{$_[0]} || $_[0];
1942}
1943
1944# Mark each matching opening and closing bracket with a unique id.
1945sub mark_string {
1946    # local (*_) = @_; # Modifies $_ in the caller;
1947    # -> MRO: changed to $_[0] (same effect)
1948    # MRO: removed deprecated $*, replaced by option /m
1949    $_[0] =~ s/(^|[^\\])\\\{/$1tex2html_escaped_opening_bracket/gom;
1950    $_[0] =~ s/(^|[^\\])\\\{/$1tex2html_escaped_opening_bracket/gom; # repeat this
1951    $_[0] =~ s/(^|[^\\])\\\}/$1tex2html_escaped_closing_bracket/gom;
1952    $_[0] =~ s/(^|[^\\])\\\}/$1tex2html_escaped_closing_bracket/gom; # repeat this
1953    my $id = $global{'max_id'};
1954    my $prev_id = $id;
1955    # mark all balanced braces
1956    # MRO: This should in fact mark all of them as the hierarchy is
1957    # processed inside-out.
1958    1 while($_[0] =~ s/\{([^{}]*)\}/join("",$O,++$id,$C,$1,$O,$id,$C)/geo);
1959    # What follows seems esoteric...
1960    my @processedB = ();
1961    # Take one opening brace at a time
1962    while ($_[0] =~ /\{/) {
1963	my ($before,$after) = ($`,$');
1964        my $change = 0;
1965	while (@UNMATCHED_OPENING && $before =~ /\}/) {
1966            my $this = pop(@UNMATCHED_OPENING);
1967            print "\n *** matching brace \#$this found ***\n";
1968            $before =~ s/\}/join("",$O,$this,$C)/eo;
1969            $change = 1;
1970        }
1971        $_[0] = join('',$before,"\{",$after) if($change);
1972        # MRO: mark one opening brace
1973	if($_[0] =~ s/^([^{]*)\{/push(@processedB,$1);join('',$O,++$id,$C)/eos) {
1974	    $before=''; $after=$';
1975        }
1976        if ($after =~ /\}/) {
1977	    $after =~ s/\}/join("",$O,$id,$C)/eo;
1978	    $_[0] = join('',$before,$O,$id,$C,$after);
1979	} else {
1980	    print "\n *** opening brace \#$id  is unmatched ***\n";
1981	    $after =~ /^(.+\n)(.+\n)?/;
1982	    print " preceding: $after \n";
1983	    push (@UNMATCHED_OPENING,$id);
1984	}
1985    }
1986    $_[0] = join('',@processedB,$_[0]); undef(@processedB);
1987    print STDOUT "\nInfo: bracketings found: ", $id - $prev_id,"\n"
1988        if ($VERBOSITY > 1);
1989    # process remaining closing braces
1990    while (@UNMATCHED_OPENING && $_[0] =~ /\}/) {
1991        my $this = pop(@UNMATCHED_OPENING);
1992        print "\n *** matching brace \#$this found ***\n";
1993	$_[0] =~ s/\}/join("",$O,$this,$C)/eo;
1994    }
1995
1996    while ($_[0] =~ /\}/) {
1997        print "\n *** there was an unmatched closing \} ";
1998        my ($beforeline,$prevline,$afterline) = ($`, $`.$& , $');
1999        $prevline =~ /\n([^\n]+)\}$/m;
2000        if ($1) {
2001	    print "at the end of:\n" . $1 . "\}\n\n";
2002        } else {
2003	    $afterline =~ /^([^\n]+)\n/m;
2004	    if ($1) {
2005	        print "at the start of:\n\}" . $1 ."\n\n";
2006	    } else {
2007	        $prevline =~ /\n([^\n]+)\n\}$/m;
2008	        print "on a line by itself after:\n" . $1 . "\n\}\n\n";
2009	    }
2010        }
2011        $_[0] =  $beforeline . $afterline;
2012    }
2013    $global{'max_id'} = $id;
2014
2015    # restore escaped braces
2016    $_[0] =~ s/tex2html_escaped_opening_bracket/\\\{/go;
2017    $_[0] =~ s/tex2html_escaped_closing_bracket/\\\}/go;
2018}
2019
2020sub replace_html_special_chars {
2021    # Replaces html special characters with markers unless preceded by "\"
2022    s/([^\\])(<|>|&|\"|``|'')/&special($1).&special($2)/geom;
2023    # MUST DO IT AGAIN JUST IN CASE THERE ARE CONSECUTIVE HTML SPECIALS
2024    s/([^\\])(<|>|&|\"|``|'')/&special($1).&special($2)/geom;
2025    s/^(<|>|&|\"|``|'')/&special($1)/geom;
2026}
2027
2028#  used in \verbatiminput only:   $html_escape_chars = '<>&';
2029sub replace_all_html_special_chars { s/([$html_escape_chars])/&special($1)/geom; }
2030
2031# The bibliography and the index should be treated as separate sections
2032# in their own HTML files. The \bibliography{} command acts as a sectioning command
2033# that has the desired effect. But when the bibliography is constructed
2034# manually using the thebibliography environment, or when using the
2035# theindex environment it is not possible to use the normal sectioning
2036# mechanism. This subroutine inserts a \bibliography{} or a dummy
2037# \textohtmlindex command just before the appropriate environments
2038# to force sectioning.
2039sub add_bbl_and_idx_dummy_commands {
2040    local($id) = $global{'max_id'};
2041
2042    s/([\\]begin\s*$O\d+$C\s*thebibliography)/$bbl_cnt++; $1/eg;
2043    ## if ($bbl_cnt == 1) {
2044	s/([\\]begin\s*$O\d+$C\s*thebibliography)/$id++; "\\bibliography$O$id$C$O$id$C $1"/geo;
2045    #}
2046    $global{'max_id'} = $id;
2047    s/([\\]begin\s*$O\d+$C\s*theindex)/\\textohtmlindex $1/o;
2048    s/[\\]printindex/\\textohtmlindex /o;
2049    &lib_add_bbl_and_idx_dummy_commands() if defined(&lib_add_bbl_and_idx_dummy_commands);
2050}
2051
2052
2053# Uses and modifies $default_language
2054# This would be straight-forward except when there are
2055#  \MakeUppercase, \MakeLowercase  or \uppercase , \lowercase commands
2056# present in the source. The cases have to be adjusted before the
2057# ISO-character code is set; e.g. with "z --> "Z  in  german.perl
2058#
2059sub convert_iso_latin_chars {
2060    local($_) = @_;
2061    local($next_language, $pattern);
2062    local($xafter, $before, $after, $funct, $level, $delim);
2063    local(@case_processed);
2064    while (/$case_change_rx/) {
2065	$xafter = $2;
2066#	$before .= $`;
2067	push(@case_processed, $`);
2068	$funct = $3;
2069	$after = '';
2070	$_ = $';
2071	if ($xafter =~ /noexpand/) { $before .= "\\$funct"; next; }
2072
2073	s/^[\s%]*(.)/$delim=$1;''/eo;
2074	if ($delim =~ /{/ ) {
2075            # brackets not yet numbered...
2076#	    $before .= $funct . $delim;
2077	    push(@case_processed, $funct . $delim);
2078	    $level = 1;
2079	    $after = $delim;
2080	    while (($level)&&($_)&&(/[\{\}]/)) {
2081		$after .= $` . $&;
2082		$_ = $';
2083		if ( "$&" eq "\{" ) {$level++}
2084		elsif ( "$&" eq "\}" ) { $level-- }
2085		else { print $_ }
2086		print "$level";
2087	    }
2088#	    $before .= $after;
2089	    push(@case_processed, $after);
2090	} elsif ($delim eq "<") {
2091            # brackets numbered, but maybe not processed...
2092	    s/((<|#)(\d+)(>|#)>).*\1//;
2093	    $after .= $delim . $&;
2094	    $_ = $';
2095	    print STDOUT "\n<$2$funct$4>" if ($VERBOSITY > 2);
2096	    $funct =~ s/^\\//o;
2097	    local($cmd) = "do_cmd_$funct";
2098	    $after = &$cmd($after);
2099#	    $before .= $after;
2100	    push(@case_processed, $after);
2101	} elsif (($xafter)&&($delim eq "\\")) {
2102	    # preceded by \expandafter ...
2103	    # ...so expand the following macro first
2104	    $funct =~ s/^\\//o;
2105	    local($case_change) = $funct;
2106	    s/^(\w+|\W)/$funct=$1;''/eo;
2107	    local($cmd) = $funct;
2108	    local($thiscmd) = "do_cmd_$funct";
2109	    if (defined &$thiscmd) { $_ = &$thiscmd($_) }
2110	    elsif ($new_command{$funct}) {
2111		local($argn, $body, $opt) = split(/:!:/, $new_command{$funct});
2112		do { ### local($_) = $body;
2113		     &make_unique($body);
2114		} if ($body =~ /$O/);
2115		if ($argn) {
2116		    do {
2117			local($before) = '';
2118			local($after) = "\\$funct ".$_;
2119			$after = &substitute_newcmd;   # may change $after
2120			$after =~ s/\\\@#\@\@/\\/o ;
2121		    }
2122		} else { $_ = $body . $_; }
2123	    } else { print "\nUNKNOWN COMMAND: $cmd "; }
2124
2125	    $cmd = $case_change;
2126	    $case_change = "do_cmd_$cmd";
2127	    if (defined &$case_change) { $_ = &$case_change($_) }
2128	} else {
2129            # this should not happen, but just in case...
2130	    $funct =~ s/^\\//o;
2131	    local($cmd) = "do_cmd_$funct";
2132	    print STDOUT "\n\n<$delim$funct>" if ($VERBOSITY > 2);
2133	    $_ = join('', $delim , $_ );
2134	    if (defined &$cmd) { $_ = &$cmd($_) }
2135	}
2136    }
2137#   $_ = join('', $before, $_) if ($before);
2138    $_ = join('', @case_processed, $_) if (@case_processed);
2139
2140    # ...now do the conversions
2141    ($before, $after, $funct) = ('','','');
2142    @case_processed = ();
2143    if (/$language_rx/o) {
2144	($next_language, $pattern, $before, $after) = (($2||$1), $&, $`, $');
2145	$before = &convert_iso_latin_chars($before) if ($before);
2146#	push(@case_processed, $pattern, $before);
2147	local($br_id) = ++$global{'max_id'};
2148	$pattern = join('' , '\selectlanguage', $O.$br_id.$C
2149	    , (($pattern =~ /original/) ? $TITLES_LANGUAGE : $next_language )
2150	    , $O.$br_id.$C );
2151	push(@case_processed, $before, $pattern);
2152	push(@language_stack, $default_language);
2153	$default_language = $next_language;
2154	$_ = &convert_iso_latin_chars($after);
2155	$default_language = pop @language_stack;
2156    } else {
2157	$funct = $language_translations{$default_language};
2158	(defined(&$funct) ? $_ = &$funct($_) :
2159	 do {   &write_warnings(
2160		"\nCould not find translation function for $default_language.\n\n")
2161	    }
2162	);
2163	if ($USE_UTF ||(!$NO_UTF &&(%unicode_table)&&length(%unicode_table)>2)) {
2164	    &convert_to_unicode($_)};
2165    }
2166    $_ = join('', @case_processed, $_); undef(@case_processed);
2167    $_;
2168}
2169
2170# May need to add something here later
2171sub english_translation { $_[0] }
2172
2173# This replaces \setlanguage{\language} with \languageTeX
2174# This makes the identification of language chunks easier.
2175sub normalize_language_changes {
2176    s/$setlanguage_rx/\\$2TeX/gs;
2177}
2178
2179sub get_current_language {
2180    return () if ($default_language eq $TITLES_LANGUAGE);
2181    local($lang,$lstyle) = ' LANG="';
2182    $lang_code = $iso_languages{$default_language};
2183    if (%styled_languages) {
2184	$lstyle = $styled_languages{$default_language};
2185	$lstyle = '" CLASS="'.$lstyle  if $lstyle;
2186    }
2187    ($lang_code ? $lang.$lang_code.$lstyle.'"' : '');
2188}
2189
2190%styled_languages = ();
2191
2192sub do_cmd_htmllanguagestyle {
2193    local($_) = @_;
2194    local($class) = &get_next_optional_argument;
2195    local($lang) = &missing_braces unless (
2196	(s/$next_pair_pr_rx/$lang=$2;''/e)
2197	||(s/$next_pair_rx/$lang=$2;''/e));
2198    return ($_) unless $lang;
2199    local($class) = $iso_languages{$lang} unless $class;
2200    if ($USING_STYLES && $class) {
2201	print "\nStyling language: $lang = \"$class\" ";
2202    	$styled_languages{"$lang"} = $class;
2203    }
2204    $_;
2205}
2206
2207# General translation mechanism:
2208#
2209#
2210# The main program latex2html calls texexpand with the document name
2211# in order to expand some of its \input and \include statements, here
2212# also called 'merging', and to write a list of sensitized style, class,
2213# input, or include file names.
2214# When texexpand has finished, all is contained in one file, TMP_foo.
2215# (assumed foo.tex is the name of the document to translate).
2216#
2217# In this version, texexpand cares for following environments
2218# that may span include files / section boundaries:
2219# (For a more technical description, see texexpand.)
2220#  a) \begin{comment}
2221#  b) %begin{comment}
2222#  c) \begin{any}  introduced with \excludecomment
2223#  d) %begin{any}
2224#  e) \begin{verbatim}
2225#  f) \begin{latexonly}
2226#  g) %begin{latexonly}
2227#
2228# a)-d) cause texexpand to drop its contents, it will not show up in the
2229# output file. You can use this to 'comment out' a bunch of files, say.
2230#
2231# e)-g) prevent texexpand from expanding input files, but the environment
2232# content goes fully into the output file.
2233#
2234# Together with each merging of \input etc. there are so-called %%%texexpand
2235# markers accompanying the boundary.
2236#
2237# When latex2html reads in the output file, it uses these markers to write
2238# each part to a separate file, and process them further.
2239#
2240#
2241# If you have, for example:
2242#
2243# a) preample
2244# b) \begin{document}
2245# c) text
2246# d) \input{chapter}
2247# e) more text
2248# f) \end{document}
2249#
2250# you end up in two parts, part 1 is a)-c), part 2 is the rest.
2251# Regardless of environments spanning input files or sections.
2252#
2253#
2254# What now starts is meta command substitution:
2255# Therefore, latex2html forks a child process on the first part and waits
2256# until it finished, then forks another on the next part and so forth
2257# (see also &slurp_input_and_partition_and_preprocess).
2258#
2259# Here's what each child is doing:
2260# Each child process reads the new commands translated so far by the previous
2261# child from the TMP_global DBM database.
2262# After &pre_processing, it substitutes the meta commands (\newcommand, \def,
2263# and the like) it finds, and adds the freshly retrieved new commands to the
2264# list so far.
2265# This is done *only on its part* of the document; this saves upwards of memory.
2266# Finally, it writes its list of new commands (synopsis and bodies) to the
2267# DBM database, and exits.
2268# After the last child finished, latex2html reads in all parts and
2269# concatenates them.
2270#
2271#
2272# So, at this point in time (start of &translate), it again has the complete
2273# document, but now preprocessed and with new commands substituted.
2274# This has several disadvantages: an amount of commands is substituted (in
2275# TeX lingo, expanded) earlier than the rest.
2276# This causes trouble if commands really must get expanded at the point
2277# in time they show up.
2278#
2279#
2280# Then, still in &translate, latex2html uses the list of section commands to
2281# split the complete document into chunks.
2282# The chunks are not written to files yet. They are retained in the @sections
2283# list, but each chunk is handled separately.
2284# latex2html puts the current chunk to $_ and processes it with
2285# &translate_environments etc., then fetches the next chunk, and so on.
2286# This prevents environments that span section boundaries from getting
2287# translated, because \begin and \end cannot find one another, to say it this
2288# way.
2289#
2290#
2291# After the chunk is translated to HTML, it is written to a file.
2292# When all chunks are done, latex2html rereads each file to get cross
2293# references right, replace image markers with the image file names, and
2294# writes index and bibliography.
2295#
2296#
2297sub translate {
2298    &normalize_sections;	# Deal with the *-form of sectioning commands
2299
2300
2301    # Split the input into sections, keeping the preamble together
2302    # Due to the regular expression, each split will create 5 more entries.
2303    # Entry 1 and 2: non-letter/letter sectioning command,
2304    # entry 4: the delimiter (may be empty)
2305    # entry 5: the text.
2306    local($pre_section, @sections);
2307    if (/\\(startdocument|begin\s*($O\d+$C)\s*document\s*\2)/) {
2308	$pre_section = $`.$&; $_ = $';
2309    }
2310    @sections = split(/$sections_rx/, $_);
2311    $sections[0] = $pre_section.$sections[0] if ($pre_section);
2312    undef $pre_section;
2313    local($sections) = int(scalar(@sections) / 5);
2314
2315    # Initialises $curr_sec_id to a list of 0's equal to
2316    # the number of sectioning commands.
2317    local(@curr_sec_id) = split(' ', &make_first_key);
2318    local(@segment_sec_id) = @curr_sec_id;
2319    local($i, $j, $current_depth) = (0,0,0);
2320    local($curr_sec) = $SHORT_FILENAME||$FILE;
2321    local($top_sec) = ($SEGMENT ? '' : 'top of ');
2322#    local(%section_info, %toc_section_info, $CURRENT_FILE, %cite_info, %ref_files);
2323    local($CURRENT_FILE);
2324    # These filenames may be set when translating the corresponding commands.
2325    local($tocfile, $loffile, $lotfile, $footfile, $citefile, $idxfile,
2326	  $figure_captions, $table_captions, $footnotes, $citations, %font_size, %index,
2327	  %done, $t_title, $t_author, $t_date, $t_address, $t_affil, $changed);
2328    local(@authors,@affils,@addresses,@emails,@authorURLs);
2329    local(%index_labels, %index_segment, $preindex, %footnotes, %citefiles);
2330    local($segment_table_captions, $segment_figure_captions);
2331    local($dir,$nosave) = ('','');
2332    local($del,$close_all,$open_all,$toc_sec_title,$multiple_toc);
2333    local($open_tags_R) = [];
2334    local(@save_open_tags)= ();
2335    local(@language_stack) = ();
2336    push (@language_stack, $default_language);
2337
2338#    $LATEX_FONT_SIZE = '10pt' unless ($LATEX_FONT_SIZE);
2339    &process_aux_file
2340	if $SHOW_SECTION_NUMBERS || /\\(caption|(html|hyper)?((eq)?ref|cite))/;
2341
2342    require ("${PREFIX}internals.pl") if (-f "${PREFIX}internals.pl");
2343#JCL(jcl-del)
2344    &make_single_cmd_rx;
2345#
2346    $tocfile = $EXTERNAL_CONTENTS;
2347    $idxfile = $EXTERNAL_INDEX;
2348    $citefile = $EXTERNAL_BIBLIO; $citefile =~ s/#.*$//;
2349    $citefiles{1} = $citefile if ($citefile);
2350    print "\nTranslating ...";
2351
2352    while ($i <= @sections) {
2353        undef $_;
2354	$_ = $sections[$i];
2355	s/^[\s]*//;		# Remove initial blank lines
2356
2357	# The section command was removed when splitting ...
2358	s/^/\\$curr_sec$del/  if ($i > 0); # ... so put it back
2359	if ($current_depth < $MAX_SPLIT_DEPTH)  {
2360	    if (($footnotes)&&($NO_FOOTNODE)&&( $current_depth < $MAX_SPLIT_DEPTH)) {
2361		local($thesenotes) = &make_footnotes ;
2362		print OUTPUT $thesenotes;
2363	    }
2364	    $CURRENT_FILE = &make_name($curr_sec, join('_',@curr_sec_id));
2365
2366	    open(OUTPUT, ">$CURRENT_FILE")
2367		|| die "Cannot write '$CURRENT_FILE': $!\n";
2368	    if ($XBIT_HACK) { # use Apache's XBit hack
2369		chmod 0744, $CURRENT_FILE;
2370		&check_htaccess;
2371	    } else {
2372		chmod 0644, $CURRENT_FILE;
2373	    }
2374
2375	    if ($MULTIPLE_FILES && $ROOTED) {
2376	        if ($DESTDIR =~ /^\Q$FIXEDDIR\E[$dd$dd]?([^$dd$dd]+)/)
2377	            { $CURRENT_FILE = "$1$dd$CURRENT_FILE" };
2378	    }
2379	}
2380	&remove_document_env;
2381#        &wrap_shorthand_environments;    #RRM  Is this needed ?
2382	print STDOUT "\n" if ($VERBOSITY);
2383	print STDOUT "\n" if ($VERBOSITY > 2);
2384	print $i/5,"/$sections";
2385	print ":$top_sec$curr_sec:" if ($VERBOSITY);
2386
2387	# Must do this early ... It also sets $TITLE
2388	&process_command($sections_rx, $_) if (/^$sections_rx/);
2389	# reset tags saved from the previous section
2390	$open_tags_R = [ @save_open_tags ];
2391	@save_open_tags = ();
2392
2393	local($curr_sec_tex);
2394	if ((! $TITLE) || ($TITLE eq $default_title)) {
2395	    eval '$TITLE = '.$default_title;
2396	    $TITLE = $default_title if $@;
2397	    $curr_sec_tex = ($top_sec ? '' :
2398		  join('', '"', &revert_to_raw_tex($curr_sec), '"'));
2399	    print STDOUT "$curr_sec_tex for $CURRENT_FILE\n" if ($VERBOSITY);
2400	} else {
2401	    local($tmp) = &purify($TITLE,1);
2402	    $tmp = &revert_to_raw_tex($tmp);
2403	    print STDOUT "\"$tmp\" for $CURRENT_FILE\n" if ($VERBOSITY);
2404	}
2405
2406	if (/\\(latextohtmlditchpreceding|startdocument)/m) {
2407 	    local($after) = $';
2408 	    local($before) = $`.$&;
2409	    $SEGMENT = 1 if ($1 =~ /startdocument/);
2410	    print STDOUT "\n *** translating preamble ***\n" if ($VERBOSITY);
2411	    $_ = &translate_preamble($before);
2412	    s/\n\n//g; s/<BR>//g;	# remove redundant blank lines and breaks
2413#
2414#	    &process_aux_file  if $AUX_FILE_NEEDED;
2415#
2416	    print STDOUT "\n *** preamble done ***\n" if ($VERBOSITY);
2417	    $PREAMBLE = 0;
2418 	    $NESTING_LEVEL=0;
2419	    &do_AtBeginDocument;
2420	    $after =~ s/^\s*//m;
2421	    print STDOUT (($VERBOSITY >2)? "\n*** Translating environments ***" : ";");
2422	    $after = &translate_environments($after);
2423	    print STDOUT (($VERBOSITY >2)? "\n*** Translating commands ***" : ";");
2424	    $_ .= &translate_commands($after);
2425#            $_ = &translate_commands($after);
2426 	} else {
2427	    &do_AtBeginDocument;
2428	    $PREAMBLE = 0;
2429 	    $NESTING_LEVEL=0;
2430	    print STDOUT (($VERBOSITY >2)? "\n*** Translating environments ***" : ";");
2431 	    $_ = &translate_environments($_);
2432	    print STDOUT (($VERBOSITY >2)? "\n*** Translating commands ***" : ";");
2433 	    $_ = &translate_commands($_);
2434 	}
2435
2436	# close any tags that remain open
2437	if (@$open_tags_R) {
2438	    ($close_all,$open_all) = &preserve_open_tags();
2439	    $_ .= $close_all;
2440	    @save_open_tags = @$open_tags_R; $open_tags_R = [];
2441	} else { ($close_all,$open_all) = ('','') }
2442
2443	print STDOUT (($VERBOSITY >2)? "\n*** Translations done ***" : "\n");
2444#	if (($footnotes)&&($NO_FOOTNODE)&&( $current_depth < $MAX_SPLIT_DEPTH)) {
2445#	    $_ .= &make_footnotes
2446#	}
2447	print OUTPUT $_;
2448
2449	# Associate each id with the depth, the filename and the title
2450	###MEH -- starred sections don't show up in TOC ...
2451	# RRM:  ...unless $TOC_STARS is set
2452#	$toc_sec_title = &simplify($toc_sec_title);
2453	$toc_sec_title = &purify($toc_sec_title);# if $SEGMENT;
2454	$toc_sec_title = &purify($TITLE) unless ($toc_sec_title);
2455
2456	if ($TOC_STARS) {
2457	    $toc_section_info{join(' ',@curr_sec_id)} =
2458		"$current_depth$delim$CURRENT_FILE$delim$toc_sec_title"
2459#		    if ($current_depth <= $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH);
2460		    if ($current_depth <= $TOC_DEPTH);
2461	} else {
2462	    $toc_section_info{join(' ',@curr_sec_id)} =
2463		"$current_depth$delim$CURRENT_FILE$delim$toc_sec_title"
2464		. ($curr_sec =~ /star$/ ? "$delim<tex2html_star_mark>" : "")
2465#		    if ($current_depth <= $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH);
2466		    if ($current_depth <= $TOC_DEPTH);
2467	}
2468
2469	# include $BODYTEXT in the section_info, when starting a new page
2470	$section_info{join(' ',@curr_sec_id)} =
2471	    "$current_depth$delim$CURRENT_FILE$delim$TITLE$delim"
2472		. (($current_depth < $MAX_SPLIT_DEPTH)? $BODYTEXT: "");
2473
2474	# Get type of section (see also the split above)
2475	$curr_sec = $sections[$i+1].$sections[$i+2];
2476	$del = $sections[$i+4];
2477
2478	# Get the depth of the current section;
2479#	$curr_sec = $outermost_level unless $curr_sec;
2480	$current_depth = $section_commands{$curr_sec};
2481	if ($after_segment) {
2482	    $current_depth = $after_segment;
2483            $curr_sec_id[$after_segment] += $after_seg_num;
2484            ($after_segment,$after_seg_num) = ('','');
2485	    for($j=1+$current_depth; $j <= $#curr_sec_id; $j++) {
2486		$curr_sec_id[$j] = 0;
2487	    }
2488	}
2489	if ($SEGMENT||$SEGMENTED) {
2490	    for($j=1; $j <= $#curr_sec_id; $j++) {
2491		$curr_sec_id[$j] += $segment_sec_id[$j];
2492		$segment_sec_id[$j] = 0;
2493	    }
2494	};
2495
2496
2497	# this may alter the section-keys
2498	$multiple_toc = 1 if ($MULTIPLE_FILES && $ROOTED && (/$toc_mark/));
2499
2500
2501	#RRM : Should this be done here, or in \stepcounter ?
2502	@curr_sec_id = &new_level($current_depth, @curr_sec_id);
2503
2504	$toc_sec_title = $TITLE = $top_sec = '';
2505	$i+=5; #skip to next text section
2506    }
2507    $open_tags_R = [];
2508    $open_all = '';
2509
2510    $_ = undef;
2511    $_ = &make_footnotes if ($footnotes);
2512    $CURRENT_FILE = '';
2513    print OUTPUT;
2514    close OUTPUT;
2515
2516
2517#    # this may alter the section-keys
2518#    &adjust_root_keys if $multiple_toc;
2519
2520    if ($PREPROCESS_IMAGES) { &preprocess_images }
2521    else { &make_image_file }
2522    print STDOUT "\n *** making images ***" if ($VERBOSITY > 1);
2523    &make_images;
2524
2525    # Link sections, add head/body/address do cross-refs etc
2526    print STDOUT "\n *** post-process ***" if ($VERBOSITY > 1);
2527    &post_process;
2528
2529    if (defined &document_post_post_process) {
2530    	#BRM: extra document-wide post-processing
2531	print STDOUT "\n *** post-processing Document ***" if ($VERBOSITY > 1);
2532	&document_post_post_process();
2533    }
2534
2535    print STDOUT "\n *** post-processed ***" if ($VERBOSITY > 1);
2536    &copy_icons if $LOCAL_ICONS;
2537    if ($SEGMENT || $DEBUG || $SEGMENTED) {
2538	&save_captions_in_file("figure",  $figure_captions) if $figure_captions;
2539	&save_captions_in_file("table",  $table_captions) if $table_captions;
2540#	&save_array_in_file ("captions", "figure_captions", 0, %figure_captions) if %figure_captions;
2541#	&save_array_in_file ("captions", "table_captions", 0, %table_captions) if %table_captions;
2542	&save_array_in_file ("index", "index", 0, %index);
2543	&save_array_in_file ("sections", "section_info", 0, %section_info);
2544	&save_array_in_file ("contents", "toc_section_info", 0,%toc_section_info);
2545	&save_array_in_file ("index", "sub_index", 1, %sub_index) if %sub_index;
2546	&save_array_in_file ("index", "index_labels", 1, %index_labels) if %index_labels;
2547	&save_array_in_file ("index", "index_segment", 1, %index_segment) if %index_segment;
2548	&save_array_in_file ("index", "printable_key", 1, %printable_key)
2549	    if (%printable_key || %index_segment);
2550    }
2551    elsif ($MULTIPLE_FILES && $ROOTED) {
2552	&save_array_in_file ("sections", "section_info", 0, %section_info);
2553	&save_array_in_file ("contents", "toc_section_info", 0, %toc_section_info);
2554    }
2555    &save_array_in_file ("internals", "ref_files", 0, %ref_files) if $changed;
2556    &save_array_in_file ("labels", "external_labels", 0, %ref_files);
2557    &save_array_in_file ("labels", "external_latex_labels", 1, %latex_labels);
2558    &save_array_in_file ("images", "cached_env_img", 0, %cached_env_img);
2559}
2560
2561# RRM:
2562sub translate_preamble {
2563    local($_) = @_;
2564    $PREAMBLE = 1;
2565    $NESTING_LEVEL=0;   #counter for TeX group nesting level
2566    # remove some artificially inserted constructions
2567    s/\n${tex2html_deferred_rx}\\par\s*${tex2html_deferred_rx2}\n/\n/gm;
2568    s/\\newedcommand(<<\d+>>)([A-Za-z]+|[^A-Za-z])\1(\[\d+\])?(\[[^]]*\])?(<<\d+>>)[\w\W\n]*\5($comment_mark\d*)?//gm;
2569    s/\n{2,}/\n/ogm;
2570
2571    if (/\\htmlhead/) {
2572        print STDOUT "\nPREAMBLE: discarding...\n$`" if ($VERBOSITY > 4);
2573        local($after) = $&.$';
2574	# translate segment preamble preceding  \htmlhead
2575	&translate_commands(&translate_environments($`));
2576	# translate \htmlhead  and rest of preamble
2577	$_=&translate_commands(&translate_environments($after));
2578        print STDOUT "\nPREAMBLE: retaining...\n$_" if ($VERBOSITY > 4);
2579    } else {
2580	# translate only preamble here (metacommands etc.)
2581	# there should be no textual results, if so, discard them
2582	&translate_commands(&translate_environments($_));
2583        print STDOUT "\nPREAMBLE: discarding...\n$_" if ($VERBOSITY > 4);
2584	$_="";
2585    };
2586    $_ = &do_AtBeginDocument($_);
2587    if (! $SEGMENT) { $_ = ''} # segmented documents have a heading already
2588    $_;
2589}
2590
2591############################ Processing Environments ##########################
2592
2593sub wrap_shorthand_environments {
2594    # This wraps a dummy environment around environments that do not use
2595    # the begin-end convention. The wrapper will force them to be
2596    # evaluated by Latex rather than them being translated.
2597    # Wrap a dummy environment around matching TMPs.
2598    # s/^\$\$|([^\\])\$\$/{$1.&next_wrapper('tex2html_double_dollar')}/ge;
2599    # Wrap a dummy environment around matching $s.
2600    # s/^\$|([^\\])\$/{$1.&next_wrapper('$')}/ge;
2601    # s/tex2html_double_dollar/\$\$/go;
2602    # Do \(s and \[s
2603    #
2604    local($wrapper) = "tex2html_wrap_inline";	# \ensuremath wrapper
2605    print STDOUT "\n *** wrapping environments ***\n" if ($VERBOSITY > 3);
2606
2607    # MRO: replaced $* with /m
2608    print STDOUT "\\(" if ($VERBOSITY > 3);
2609    s/(^\\[(])|([^\\])(\\[(])/{$2.&make_any_wrapper(1,'',$wrapper).$1.$3}/geom;
2610    print STDOUT "\\)" if ($VERBOSITY > 3);
2611    s/(^\\[)]|[^\\]\\[)])/{$1.&make_any_wrapper(0,'',$wrapper)}/geom;
2612
2613    print STDOUT "\\[" if ($VERBOSITY > 3);
2614    s/(^\\[[])|([^\\])(\\[[])/{$2.&make_any_wrapper(1,1,"displaymath")}/geom;
2615    print STDOUT "\\]" if ($VERBOSITY > 3);
2616    s/(^\\[\]])|([^\\])(\\[\]])/{$2.&make_any_wrapper(0,1,"displaymath")}/geom;
2617
2618    print STDOUT "\$" if ($VERBOSITY > 3);
2619    s/$enspair/print "\$";
2620       {&make_any_wrapper(1,'',$wrapper).$&.&make_any_wrapper(0,'',$wrapper)}/geom;
2621
2622    $double_dol_rx = '(^|[^\\\\])\\$\\$';
2623    $single_dol_rx = '(^|[^\\\\])\\$';
2624    print STDOUT "\$" if ($VERBOSITY > 3);
2625
2626    local($dollars_remain) = 0;
2627    $_ = &wrap_math_environment;
2628    $_ = &wrap_raw_arg_cmds;
2629}
2630
2631sub wrap_math_environment {
2632
2633    # This wraps math-type environments
2634    # The trick here is that the opening brace is the same as the close,
2635    # but they *can* still nest, in cases like this:
2636    #
2637    # $ outer stuff ... \hbox{ ... $ inner stuff $ ... } ... $
2638    #
2639    # Note that the inner pair of $'s is nested within a group.  So, to
2640    # handle these cases correctly, we need to make sure that the outer
2641    # brace-level is the same as the inner. --- rst
2642    #tex2html_wrap
2643    # And yet another problem:  there is a scungy local idiom to do
2644    # this:  $\_$ for a boldfaced underscore.  xmosaic can't display the
2645    # resulting itty-bitty bitmap, for some reason; even if it could, it
2646    # would probably come out as an overbar because of the floating-
2647    # baseline problem.  So, we have to special case this.  --- rst again.
2648
2649    local ($processed_text, @processed_text, $before, $end_rx, $delim, $ifclosed);
2650    local ($underscore_match_rx) = "^\\s*\\\\\\_\\s*\\\$";
2651    local ($wrapper);
2652    print STDOUT "\nwrap math:" if ($VERBOSITY > 3);
2653
2654    #find braced dollars, in tabular-specs
2655    while (/((($O|$OP)\d+($C|$CP))\s*)\$(\s*\2)/) {
2656        push (@processed_text, $`, $1.$dol_mark.$5);
2657        $_ = $';
2658    }
2659    $_ = join('',@processed_text, $_) if (@processed_text);
2660    undef @processed_text;
2661
2662    $dollars_remain = 0;
2663    while (/$single_dol_rx/) {
2664	$processed_text .= $`.$1;
2665	$_ = $';
2666	$wrapper = "tex2html_wrap_inline";
2667	$end_rx = $single_dol_rx; # Default, unless we begin with $$.
2668	$delim = "\$";
2669
2670        if (/^\$/ && (! $`)) {
2671	    s/^\$//;
2672	    $end_rx = $double_dol_rx;
2673	    $delim = "";	# Cannot say "\$\$" inside displaymath
2674	    $wrapper = "displaymath";
2675
2676        } elsif (/$underscore_match_rx/ && (! $`)) {
2677
2678            # Special case for $\_$ ...
2679
2680            s/$underscore_match_rx//;
2681            $processed_text .= '\\_';
2682            next;
2683        }
2684
2685        # Have an opening $ or $$.  Find matching close, at same bracket level
2686#	$processed_text .= &make_any_wrapper(1,'',$wrapper).$delim;
2687
2688	print STDOUT "\$" if ($VERBOSITY > 3);
2689	$ifclosed = 0;
2690	local($thismath);
2691        while (/$end_rx/) {
2692	    # Forget the $$ if we are going to replace it with "displaymath"
2693            $before = $` . (($wrapper eq "displaymath")? "$1" : $&);
2694	    last if ($before =~ /\\(sub)*(item|section|chapter|part|paragraph)(star)?\b/);
2695	    $thismath .= $before;
2696            $_ = $';
2697	    s/^( [^\n])/\\space$1/s;  #make sure a trailing space doesn't get lost.
2698
2699            # Found dollar sign inside open subgroup ... now see if it's
2700            # at the same brace-level ...
2701
2702            local ($losing, $br_rx) = (0, '');
2703	    print STDOUT "\$" if ($VERBOSITY > 3);
2704            while ($before =~ /$begin_cmd_rx/) {
2705                $br_rx = &make_end_cmd_rx($1);  $before = $';
2706
2707                if ($before =~ /$br_rx/) { $before = $'; }
2708                else { $losing = 1; last; }
2709            }
2710            do { $ifclosed = 1; last } unless $losing;
2711
2712            # It wasn't ... find the matching close brace farther on; then
2713            # keep going.
2714
2715            /$br_rx/;
2716
2717            $thismath .= $`.$&;
2718
2719	    #RRM: may now contain unprocessed $s e.g. $\mbox{...$...$...}$
2720	    # the &do_cmd_mbox uses this specially to force an image
2721	    # ...but there may be other situations; e.g. \hbox
2722	    # so set a flag:
2723	    $dollars_remain = 1;
2724
2725            $_ = $';
2726        }
2727
2728        # Got to the end.  Whew!
2729	if ($ifclosed) {
2730	    # also process any nested math
2731	    while (($dollars_remain)&&($delim eq "\$")) {
2732		local($saved) = $_;
2733                $thismath =~ s/\$$//;
2734                $_ = $thismath;
2735		$thismath =  &wrap_math_environment;
2736		$thismath .= "\$";
2737		$_ = $saved;
2738	    }
2739	    $processed_text .= &make_any_wrapper(1,'',$wrapper) . $delim
2740		. $thismath . &make_any_wrapper(0,'',$wrapper);
2741	} else {
2742	    print STDERR "\n\n *** Error: unclosed math or extra `\$', before:\n$thismath\n\n";
2743#	    # remove a $ to try to recover as much as possible.
2744#	    $thismath =~ s/([^\\]\\\\|[^\\])\$/$1\%\%/;
2745#	    $_ = $thismath . $_; $thismath = "";
2746	print "\n$thismath\n\n\n$_\n\n\n"; die;
2747
2748	}
2749    }
2750    $processed_text . $_;
2751}
2752
2753sub translate_environments {
2754    local ($_) = @_;
2755    local($tmp, $capenv);
2756    print "\nPCT: Translating environments ...\n" if ($VERBOSITY > 20) ;
2757    local($after, @processedE);
2758    local ($contents, $before, $br_id, $env, $pattern);
2759    for (;;) {
2760#	last unless (/$begin_env_rx/o);
2761	last unless (/$begin_env_rx|$begin_cmd_rx|\\(selectlanguage)/o);
2762#	local ($contents, $before, $br_id, $env, $pattern);
2763	local($this_env, $opt_arg, $style_info);
2764	$contents = '';
2765	# $1,$2 : optional argument/text --- stylesheet info
2766	# $3 : br_id (at the beginning of an environment name)
2767	# $4 : environment name
2768	# $5 : br_id of open-brace, when $3 == $4 == '';
2769	# $6 : \selectlanguage{...}
2770	if ($7) {
2771	    push(@processedE,$`);
2772	    $_ = $';
2773	    if (defined &do_cmd_selectlanguage) {
2774		$_ = &do_cmd_selectlanguage($_);
2775	    } else {
2776		local($cmd) = $7;
2777		$pattern = &missing_braces unless (
2778		    s/$next_pair_rx/$pattern = $2;''/e);
2779		local($trans) = $pattern.'_translation';
2780		if (defined &$trans) {
2781		    &set_default_language($pattern,$_);
2782		}
2783		undef $cmd; undef $trans;
2784	    }
2785	    next;
2786	} elsif ($4) {
2787	    ($before, $opt_arg, $style_info, $br_id
2788	     , $env, $after, $pattern) = ($`, $2, $3, $4, $5, $', $&);
2789	    if (($before)&& (!($before =~ /$begin_env_rx|$begin_cmd_rx/))) {
2790		push(@processedE,$before);
2791		$_ = $pattern . $after; $before = '';
2792	    }
2793	} else {
2794	    ($before, $br_id, $env, $after, $pattern) = ($`, $6, 'group', $', $&);
2795	    if (($before)&& (!($before =~ /$begin_env_rx|$begin_cmd_rx/))) {
2796		push(@processedE,$before);
2797		$_ = $pattern . $after; $before = '';
2798	    }
2799	    local($end_cmd_rx) = &make_end_cmd_rx($br_id);
2800	    if ($after =~ /$end_cmd_rx/) {
2801		# ... find the the matching closing one
2802		$NESTING_LEVEL++;
2803		($contents, $after) = ($`, $');
2804		$contents = &process_group_env($contents);
2805		print STDOUT "\nOUT: {$br_id} ".length($contents) if ($VERBOSITY > 3);
2806		print STDOUT "\n:$contents\n" if ($VERBOSITY > 7);
2807		# THIS MARKS THE OPEN-CLOSE DELIMITERS AS PROCESSED
2808		$_ = join("", $before,"$OP$br_id$CP", $contents,"$OP$br_id$CP", $after);
2809		$NESTING_LEVEL--;
2810	    } else {
2811		$pattern = &escape_rx_chars($pattern);
2812		s/$pattern//;
2813		print "\nCannot find matching bracket for $br_id";
2814		$_ = join("", $before,"$OP$br_id$CP", $after);
2815	    }
2816	    next;
2817	}
2818	$contents = undef;
2819	local($defenv) = $env =~ /deferred/;
2820#	local($color_env);
2821	local($color_env)
2822	    unless ($env =~ /tabular|longtable|in(line|display)|math/);
2823	local($closures,$reopens);
2824	local(@save_open_tags) = @$open_tags_R unless ($defenv);
2825	local($open_tags_R) = [ @save_open_tags ] unless ($defenv);
2826	local(@saved_tags) if ($env =~ /tabular|longtable/);
2827	if ($env =~ /tabular|longtable|makeimage|in(line|display)/) {
2828	    @save_open_tags = @$open_tags_R;
2829	    $open_tags_R = [ @save_open_tags ];
2830	    # check for color
2831	    local($color_test) = join(',',@$open_tags_R);
2832	    if ($color_test =~ /(color\{[^}]*\})/g ) {
2833		$color_env = $1;
2834	    } # else { $color_env = '' }
2835
2836	    if ($env =~ /tabular|longtable|makeimage/) {
2837		# close to the surrounding block-type tag
2838		($closures,$reopens,@saved_tags) = &preserve_open_block_tags();
2839		@save_open_tags = @$open_tags_R;
2840		$open_tags_R = [ @save_open_tags ];
2841		if ($color_env) {
2842		    $color_test = join(',',@saved_tags);
2843		    if ($color_test =~ /(color\{[^}]*\})/g ) {
2844		        $color_env = $1;
2845		    }
2846		}
2847	    } elsif ($env =~ /in(line|display)/) {
2848		$closures = &close_all_tags() if ((&defined_env($env))
2849		    &&!($defenv)&&!($env=~/inline/)&&(!$declarations{$env}));
2850		if ($color_env) {
2851		    $color_test = $declarations{$color_env};
2852		    $color_test =~ s/<\/.*$//;
2853		    $closures .= "\n$color_test";
2854		    push (@$open_tags_R , $color_env);
2855		}
2856	    }
2857	} elsif ($env =~ /alltt|tex2html_wrap/) {
2858	    # alltt is constructed as paragraphs, not with <PRE>
2859	    #  tex2html_wrap  creates an image, which is at text-level
2860	} else {
2861	    $closures = &close_all_tags() if ((&defined_env($env))
2862		&&!($defenv)&&(!$declarations{$env}) );
2863	}
2864	# Sets $contents and modifies $after
2865	if (&find_end_env($env,$contents,$after)) {
2866	    print STDOUT "\nIN-A {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2867	    &process_command($counters_rx, $before)
2868		if ($before =~ /$counters_rx/);
2869	    # This may modify $before and $after
2870	    # Modifies $contents
2871#RRM: the do_env_... subroutines handle when to translate sub-environments
2872#	    $contents = &translate_environments($contents) if
2873##		((!$defenv) && (&defined_env($env)) && (! $raw_arg_cmds{$env})
2874##		&& (!$declarations{$env})
2875#		((&defined_env($env)) && (! $raw_arg_cmds{$env})
2876#		&& (!($env =~ /latexonly|enumerate|figure|table|makeimage|wrap_inline/))
2877#		&& ((! $NO_SIMPLE_MATH)||(!($env =~ /wrap/)))
2878#		&& (!($env =~ /(math|wrap|equation|eqnarray|makeimage|minipage|tabular)/) )
2879#		);
2880	    if ($opt_arg) {
2881		print "PCT: translate_environment: opt_arg\n" if ($VERBOSITY > 10) ;
2882		&process_environment(1, $env, $br_id, $style_info); # alters $contents
2883	    } else {
2884		print "PCT: translate_environment: NO opt_arg\n" if ($VERBOSITY > 10) ;
2885		&process_environment(0, $env, $br_id, '');
2886	    }
2887	    undef $_;
2888	    print STDOUT "\nOUT-A {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2889	    #JCL(jcl-env) - insert the $O$br_id$C stuff to handle environment grouping
2890	    if (!($contents eq '')) {
2891		$after =~ s/^\n//o if ($defenv);
2892		$this_env = join("", $before, $closures
2893			  , $contents
2894			  , ($defenv ? '': &balance_tags())
2895			  , $reopens ); $_ = $after;
2896	    } else {
2897		$this_env = join("", $before , $closures
2898			  , ($defenv ? '': &balance_tags())
2899			  , $reopens ); $_ = $after;
2900	    };
2901	### Evan Welsh <welsh@epcc.ed.ac.uk> added the next 24 lines ##
2902	} elsif (&defined_env($env)) {
2903	    print STDOUT "\nIN-B {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2904	    # If I specify a function for the environment then it
2905	    # calls it with the contents truncated at the next section.
2906	    # It assumes I know what I'm doing and doesn't give a
2907	    # deferred warning.
2908	    $contents = $after;
2909	    if ($opt_arg) {
2910		$contents = &process_environment(1, $env, $br_id, $style_info);
2911	    } else {
2912		$contents = &process_environment(0, $env, $br_id, '');
2913	    }
2914	    print STDOUT "\nOUT-B {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2915	    $this_env = join("", $before, $closures ,$contents, $reopens);
2916
2917	    # there should not be anything left over
2918#	    $_ = $after;
2919	    $_ = '';
2920	} elsif ($ignore{$env}) {
2921	    print STDOUT "\nIGNORED {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2922	    # If I specify that the environment should be ignored then
2923	    # it is but I get a deferred warning.
2924	    $this_env = join("", $before , $closures , &balance_tags()
2925		      , $contents, $reopens );
2926	    $_ = $after;
2927	    &write_warnings("\n\\end{$env} not found (ignored).\n");
2928	} elsif ($raw_arg_cmds{$env}) {
2929	    print "\nIN-C {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2930	    # If I specify that the environment should be passed to tex
2931	    # then it is with the environment truncated at the next
2932	    # section and I get a deferred warning.
2933
2934	    $contents = $after;
2935	    if ($opt_arg) {
2936		$contents = &process_environment(1, $env, $br_id, $style_info);
2937	    } else {
2938		$contents = &process_environment(0, $env, $br_id, '');
2939	    }
2940	    print STDOUT "\nOUT-C {$env $br_id}\n$contents\n" if ($VERBOSITY > 4);
2941	    $this_env = join("", $before, $closures
2942			     , $contents, &balance_tags(), $reopens );
2943	    $_='';
2944	    &write_warnings(
2945	        "\n\\end{$env $br_id} not found (truncated at next section boundary).\n");
2946	} else {
2947	    $pattern = &escape_rx_chars($pattern);
2948	    s/$pattern/$closures/;
2949	    print "\nCannot find \\end{$env $br_id}\n";
2950	    $_ .= join('', &balance_tags(), $reopens) unless ($defenv);
2951	}
2952	if ($this_env =~ /$begin_env_rx|$begin_cmd_rx/) {
2953	    $_ = $this_env . $_;
2954	} else { push (@processedE, $this_env) }
2955    }
2956    $_ = join('',@processedE) . $_;
2957    $tmp = $_; undef $_;
2958    &process_command($counters_rx, $tmp) if ($tmp =~ /$counters_rx/);
2959    $_ = $tmp; undef $tmp;
2960    $_
2961}
2962
2963sub find_end_env {
2964    # MRO: find_end_env($env,$contents,$rest)
2965    #local ($env, *ref_contents, *rest) = @_;
2966    my $env = $_[0];
2967    my $be_rx = &make_begin_end_env_rx($env);
2968    my $count = 1;
2969
2970    while ($_[2] =~ /($be_rx)(\n?)/s) { # $rest
2971	$_[1] .= $`; # $contents
2972
2973	if ($2 eq "begin") { ++$count }
2974	else { --$count };
2975
2976	#include any final \n at an {end} only
2977	$_[2] = (($2 eq 'end')? $5 : '') . $'; # $rest
2978	last if $count == 0;
2979
2980	$_[1] .= $1; # $contents
2981    }
2982
2983    if ($count != 0) {
2984	$_[2] = join('', $_[1], $_[2]); # $rest = join('', $contents, $rest);
2985	$_[1] = ''; # $contents
2986	return(0)
2987    } else { return(1) }
2988}
2989
2990
2991sub process_group_env {
2992    local($contents) = @_;
2993    local(@save_open_tags) = @$open_tags_R;
2994    local($open_tags_R) = [ @save_open_tags ];
2995    print STDOUT "\nIN::{group $br_id}" if ($VERBOSITY > 4);
2996    print STDOUT "\n:$contents\n" if ($VERBOSITY > 6);
2997
2998    # need to catch explicit local font-changes
2999    local(%font_size) = %font_size if (/\\font\b/);
3000
3001    # record class/id info for a style-sheet entry
3002    local($env_id, $tmp, $etmp);
3003    if (($USING_STYLES) && !$PREAMBLE ) { $env_id = $br_id; }
3004#	$env_id = "grp$br_id";
3005#	$styleID{$env_id} = " ";
3006#        $env_id = " ID=\"$env_id\"";
3007#    }
3008
3009    undef $_;
3010    $contents =~ s/^\s*$par_rx\s*//s; # don't start with a \par
3011    if ($contents =~ /^\s*\\($image_switch_rx)\b\s*/s) {
3012	# catch TeX-like environments: {\fontcmd ... }
3013	local($image_style) = $1;
3014	if ($USING_STYLES) {
3015	    $env_style{$image_style} = " " unless ($env_style{$image_style});
3016	}
3017	local($switch_cmd) = "do_cmd_${image_style}";
3018	if (defined &$switch_cmd ) {
3019	    eval "\$contents = \&${switch_cmd}(\$')";
3020	    print "\n*** &$switch_cmd didn't work: $@\n$contents\n\n" if ($@);
3021	} elsif ($contents =~ /$par_rx/) {
3022	    # split into separate image for each paragraph
3023	    local($par_style,$this_par_img) = '';
3024	    local(@par_pieces) = split($par_rx, $contents);
3025	    local($this_par,$par_style,$par_comment);
3026	    $contents = '';
3027	    while (@par_pieces) {
3028		$this_par = shift @par_pieces;
3029		if ($this_par =~ /^\s*\\($image_switch_rx)\b/s) {
3030		    $image_style = $1;
3031		    $par_style = 'P.'.$1;
3032		    $env_style{$par_style} = " " unless ($env_style{$par_style});
3033		}
3034#	no comment: source is usually too highly encoded to be meaningful
3035#	$par_comment = &make_comment($image_style,$this_par);
3036		$this_par_img = &process_in_latex("\{".$this_par."\}");
3037		$contents .=  join(''  #,"\n", $par_comment
3038			, "\n<P"
3039			, (($USING_STYLES && $image_style)? " CLASS=\"$image_style\"" :'')
3040			,">", $this_par_img
3041			, "</P>\n");
3042		if (@par_pieces) {
3043		    # discard the pieces from matching  $par_rx
3044		    $dum = shift @par_pieces;
3045		    $dum = shift @par_pieces;
3046		    $dum = shift @par_pieces;
3047		    $dum = shift @par_pieces;
3048		    $dum = shift @par_pieces;
3049		    $dum = shift @par_pieces;
3050#		    $contents .= "\n</P>\n<P>";
3051		}
3052	    }
3053	} else {
3054	    $contents = &process_undefined_environment("tex2html_accent_inline"
3055		, ++$global{'max_id'},"\{".$contents."\}");
3056        }
3057    } elsif ($contents =~ /^\s*\\(html)?url\b($O\d+$C)[^<]*\2\s*/) {
3058	# do nothing
3059	$contents = &translate_environments($contents);
3060	$contents = &translate_commands($contents);
3061    } elsif (($env_switch_rx)&&($contents =~ s/^(\s*)\\($env_switch_rx)\b//s)) {
3062	# write directly into images.tex, protected by \begingroup...\endgroup
3063	local($prespace, $cmd, $tmp) = ($1,$2,"do_cmd_$2");
3064	$latex_body .= "\n\\begingroup ";
3065	if (defined &$tmp) {
3066	    eval("\$contents = &do_cmd_$cmd(\$contents)");
3067	}
3068	$contents = &translate_environments($contents);
3069	$contents = &translate_commands($contents);
3070	undef $tmp; undef $cmd;
3071	$contents .= "\n\\endgroup ";
3072    } elsif ($contents =~ /^\s*\\([a-zA-Z]+)\b/s) {
3073	local($after_cmd) = $';
3074	local($cmd) = $1; $tmp = "do_cmd_$cmd"; $etmp = "do_env_$cmd";
3075	if (($cmd =~/^(rm(family)?|normalsize)$/)
3076		||($declarations{$cmd}&&(defined &$tmp))) {
3077	    do{
3078		local(@save_open_tags) = @$open_tags_R;
3079		eval "\$contents = \&$tmp(\$after_cmd);";
3080		print "\n*** eval &$tmp failed: $@\n$contents\n\n" if ($@);
3081		$contents .= &balance_tags();
3082	    };
3083	} elsif ($declarations{$cmd}&&(defined &$etmp)) {
3084	    eval "\$contents = \&$etmp(\$after_cmd);";
3085	} else {
3086	    $contents = &translate_environments($contents);
3087	    $contents = &translate_commands($contents)
3088		if ($contents =~ /$match_br_rx/o);
3089	    # Modifies $contents
3090	    &process_command($single_cmd_rx,$contents) if ($contents =~ /\\/o);
3091	}
3092	undef $cmd; undef $tmp; undef $etmp;
3093    } else {
3094	$contents = &translate_environments($contents);
3095	$contents = &translate_commands($contents)
3096	    if ($contents =~ /$match_br_rx/o);
3097        # Modifies $contents
3098	&process_command($single_cmd_rx,$contents)
3099	    if ($contents =~ /\\/o);
3100    }
3101    $contents . &balance_tags();
3102}
3103
3104# MODIFIES $contents
3105sub process_environment {
3106    local($opt, $env, $id, $styles) = @_;
3107    print "PCT: process_environment: begin $opt, $env, $id, $styles\n" if ($VERBOSITY > 20) ;
3108    local($envS) = $env; $envS =~ s/\*\s*$/star/;
3109    local($env_sub,$border,$attribs,$env_id) = ("do_env_$envS",'','','');
3110    local($original) = $contents;
3111
3112    if ($env =~ /tex2html_deferred/ ) {
3113	print "PCT: process_environment: tex2html_deferred\n" if ($VERBOSITY > 20) ;
3114	$contents = &do_env_tex2html_deferred($contents);
3115	return ($contents);
3116    }
3117    $env_id = &read_style_info($opt, $env, $id, $styles)
3118	if (($USING_STYLES)&&($opt));
3119
3120    if (&defined_env($env)) {
3121	print "PCT: process_environment: env defined: $env\n" if ($VERBOSITY > 20) ;
3122	print STDOUT ",";
3123	print STDOUT "{$env $id}" if ($VERBOSITY > 1);
3124	#	$env_sub =~ s/\*$/star/;
3125	print "PCT: process_environment: env sub: " . $env_sub . "\n" if ($VERBOSITY > 20) ;
3126	$contents = &$env_sub($contents);
3127
3128    } elsif ($env =~ /tex2html_nowrap/) {
3129	#pass it on directly for LaTeX, via images.tex
3130	print "PCT: process_environment: tex2html_nowrap\n" if ($VERBOSITY > 20) ;
3131	$contents = &process_undefined_environment($env, $id, $contents);
3132	return ($contents);
3133
3134#    elsif (&special_env) {	# &special_env modifies $contents
3135    } else {
3136	print "PCT: process_environment: else\n" if ($VERBOSITY > 20) ;
3137	local($no_special_chars) = 0;
3138	local($failed) = 0;
3139	local($has_special_chars) = 0;
3140	&special_env; #  modifies $contents
3141	print STDOUT "\n<MATH $env$id $contents>" if ($VERBOSITY > 3);
3142	if ($failed || $has_special_chars) {
3143	    $contents = $original;
3144	    $failed = 1;
3145	    print STDOUT " !failed!\n" if ($VERBOSITY > 3);
3146        }
3147    }
3148    if (($contents) && ($contents eq $original)) {
3149	print "PCT: process_environment: content...\n" if ($VERBOSITY > 20) ;
3150        if ($ignore{$env}) {  return(''); }
3151        # Generate picture
3152	if ($contents =~ s/$htmlborder_rx//o) {
3153	    $attribs = $2; $border = (($4)? "$4" : 1)
3154	} elsif ($contents =~ s/$htmlborder_pr_rx//o) {
3155	    $attribs = $2; $border = (($4)? "$4" : 1)
3156	}
3157	$contents = &process_undefined_environment($env, $id, $contents);
3158	$env_sub = "post_latex_$env_sub"; # i.e. post_latex_do_env_ENV
3159        if ( defined &$env_sub) {
3160	    $contents = &$env_sub($contents);
3161	} elsif (($border||($attributes))&&($HTML_VERSION > 2.1)) {
3162	    $contents = &make_table($border,$attribs,'','','',$contents);
3163	} else {
3164	    $contents = join('',"<BR>\n",$contents,"\n<BR>")
3165	        unless (!($contents)||($inner_math)||($env =~
3166	              /^(tex2html_wrap|tex2html_nowrap|\w*math|eq\w*n)/o ));
3167	}
3168    }
3169    print "PCT: process_environment: contents: $contents\n" if ($VERBOSITY > 20) ;
3170    $contents;
3171}
3172
3173
3174#RRM: This reads the style information contained in the optional argument
3175#   to the \begin command. It is stored to be recovered later as an entry
3176#   within the automatically-generated style-sheet, if $USING_STYLES is set.
3177# Syntax for this info is:
3178#   <style names> ; <extra style-info>
3179
3180sub read_style_info {
3181    local($opt, $envS, $id, $styles) = @_;
3182    return() unless (($opt)&&($USING_STYLES));
3183    # allow macro-expansion within the style-info
3184    $opt = &translate_commands($opt) if ($opt =~ /\\/);
3185
3186    # record class/id info for a style-sheet entry
3187    local($style_names, $style_extra, $env_id)=(''," ",'');
3188    if ($opt) {
3189	# if there is a `;'  then <names> ; <extra>
3190	if ($styles =~ /^\s*([^\|]*)\|\s*(.*)$/) {
3191	    $style_names = $1; $style_extra = $2;
3192	    if ($style_names =~ /[=:;]/) {
3193		# cannot be <names>, so is <extra>
3194		$style_extra = $style_names.$style_extra;
3195		$style_names = '';
3196	    }
3197	} elsif ($styles =~ /[\=\:]/) {
3198	    # cannot be <names>, so is <extras>
3199	    $style_extra = $styles;
3200	} else { $style_names = $styles }
3201	$style_extra =~ s/\s*[=:]\s*/ : /go;
3202	$style_extra =~ s/([\w,\-]+)\s+([\w,\-]+)/$1 ; $2/go;
3203	$style_extra =~ s/\s*,\s*/ /go;
3204
3205	if ($style_names) {
3206	    local($sname);
3207	    local(@names) = split ( /\s+/ , $style_names );
3208	    # ensure a style-sheet entry for each new name
3209	    foreach $sname (@names) {
3210		$env_style{$sname} = " "
3211		    unless (($env_style{$sname})||($sname =~ /^\s*$/));
3212	    }
3213	}
3214    }
3215    # remove uninformative part of internally-defined env names
3216    $envS =~ s/tex2html_(\w+_)?(\w+)/$2/; $envS =~ s/preform/pre/;
3217    $env_id = $envS.$id;
3218    $styleID{$env_id} = $style_extra unless ($PREAMBLE);
3219
3220    if ($style_names) { $envS = "$style_names" }
3221    elsif (($envS =~ /^pre$/)&&
3222	(/^\\begin.*preform($O|$OP)\d+($C|$CP)$verbatim_mark(\w*[vV]erbatim)(\*?)/))
3223	    { $envS = $3.($4 ? 'star' : '') };
3224    $env_style{$envS} = " " unless (($style_names)||($env_style{$envS}));
3225    $env_id = " ID=\"$env_id\"".(($envS) ? " CLASS=\"$envS\"" : '');
3226    return($env_id);
3227}
3228
3229# RRM: This provides the mechanism to save style information in %env_style
3230#      using LaTeX macros  \htmlsetstyle  and  \htmladdtostyle
3231#
3232sub process_htmlstyles {
3233    local($mode, $_) = @_;
3234    local($pre_tags) = &get_next_optional_argument;
3235    local($class) = &missing_braces unless (
3236        (s/$next_pair_pr_rx/$class = $2;''/e)
3237        ||(s/$next_pair_rx/$class = $2;''/e));
3238    local($sinfo) = &missing_braces unless (
3239        (s/$next_pair_pr_rx/$sinfo = $2;''/e)
3240        ||(s/$next_pair_rx/$sinfo = $2;''/e));
3241    return ($_) unless ($class||$pre_tags);
3242
3243    $class = $pre_tags.($class ?'.':'').$class;
3244    $sinfo =~ s/\s*[:=]\s*/ : /g;
3245    $sinfo =~ s/\s*,\s*/ /g;
3246    if ($mode =~ /add/) {
3247    	$sinfo = '; '.$sinfo if ($env_style{$class});
3248	$env_style{$class} .= $sinfo;
3249    } else { $env_style{$class} = $sinfo }
3250    $_;
3251}
3252sub do_cmd_htmlsetstyle   { &process_htmlstyles('set',@_) }
3253sub do_cmd_htmladdtostyle { &process_htmlstyles('add',@_) }
3254
3255
3256# The $<$, $>$, $|$ and $=>$, etc strings are replaced with their textual
3257# equivalents instead of passing them on to latex for processing in math-mode.
3258# This will not be necessary when the mechanism for passing environments
3259# to Latex is improved.
3260# RETURNS SUCCESS OR FAILURE
3261sub special_env {
3262    # Modifies $contents in its caller
3263    local($next)='';
3264    local ($allow) = $HTML_VERSION ge '3.0' ?
3265	 "[^#\$%&~\\\\\{\}]|\\limits" : "[^^#\$%&~_\\\\\{\}]";
3266    #JKR: Use italics instead of bold #HWS: Generalize to include more symbols.
3267#    $contents =~ s/^\$(\s*($html_specials_inv_rx|$allow)*\s*)\$(.)?/
3268#	$next=$3;&simple_math_env($1).(($next =~ m|\w|)? " ":'').$next/ige;
3269    $contents =~ s/^\$(\s*($html_specials_inv_rx|$allow)*\s*)\$$/
3270	&simple_math_env($1)." "/ige;
3271    if ($contents =~ /\&\w*;/) { $has_math_chars=1 }
3272    if ($contents =~ /;SPM([a-zA-Z]+);/) { $has_special_chars=1 };
3273}
3274
3275# Translate simple math environments into italic.
3276# Only letters should become italic; symbols should stay non-italic.
3277sub simple_math_env {
3278    local($mathcontents) = @_;
3279    if ($mathcontents eq '') { return("$mathcontents"); }
3280    elsif ($NO_SIMPLE_MATH) {  # always make an image
3281	$failed = 1; return($mathcontents);
3282    } elsif ($mathcontents =~ /\\/) { # any macro kills "simple-math"
3283	local($save_math) = $mathcontents;
3284	local(@text_only) = ();
3285	while ((!$failed)&&($mathcontents =~
3286		/\\((boldsymbol|bm)|(math|text)(bf|rm|it|tt)|times|[{}@#^_])(\b|[^A-Za-z]|$)/)) {
3287	    # ...except when only simple styles
3288	    push (@text_only, $`, ("$2$4" ? "\\simplemath".($4 ? $4 :"bf") :"\\$1") );
3289	    $mathcontents = $5.$';
3290	    $failed = 1 if ($` =~ /\\/);
3291	}
3292	$failed = 1 if ($mathcontents =~ /\\/);
3293	return($save_math) if $failed;
3294	$mathcontents = join('',@text_only,$mathcontents);
3295    }
3296    # Is there a problem here, with nested super/subscripts ?
3297    # Yes, so do each pattern-match for bracketings within a while-loop
3298    while ($mathcontents =~ s/\^$any_next_pair_rx/<SUP>$2<\/SUP>/go){};
3299    while ($mathcontents =~ s/\^$any_next_pair_pr_rx/<SUP>$2<\/SUP>/go){};
3300    while ($mathcontents =~ s/_$any_next_pair_rx/<SUB>$2<\/SUB>/g){};
3301    while ($mathcontents =~ s/_$any_next_pair_pr_rx/<SUB>$2<\/SUB>/g){};
3302
3303    $mathcontents =~ s/\^(\\[a-zA-Z]+|.)/<SUP>$1<\/SUP>/g;
3304    $mathcontents =~ s/_(\\[a-zA-Z]+|.)/<SUB>$1<\/SUB>/g;
3305    $mathcontents =~ s/(^|\s|[,;:'\?\.\[\]\(\)\+\-\=\!>]|[^\\<]\/|\d)(<(I|TT|B)>)?([a-zA-Z]([a-zA-Z ]*[a-zA-Z])?)(<\/\3>)?/
3306	$1.(($2)? $2 :'<I>').$4.(($6)? $6 : '<\/I>')/eig;
3307
3308    $mathcontents =~ s/\\times($|\b|[^A-Za-z])/ x $1/g;
3309    $mathcontents =~ s/\\times($|\b|[^A-Za-z])/ x $1/g;
3310    $mathcontents =~ s/\\\\/<BR>\n/g;
3311    $mathcontents =~ s/\\\\/<BR>\n/g;
3312    $mathcontents =~ s/\\([,;])/ /g;
3313    $mathcontents =~ s/\\(\W)/$1/g;
3314    $mathcontents =~ s/ {2,}/ /g;
3315
3316    # any simple style changes remove enclosed <I> tags
3317    $mathcontents = &translate_commands($mathcontents)
3318	if ($mathcontents =~ /\\/);
3319
3320    $mathcontents =~ s/<I><\/(SUB|SUP)>/<\/$1><I>/g;
3321    $mathcontents =~ s/<(SUB|SUP)><\/I>/<\/I><$1>/g;
3322    $mathcontents =~ s/;<I>SPM([a-zA-Z]+)<\/I>;/;SPM$1;/go;
3323    $mathcontents =~ s/<(\/?)<I>(SUB|SUP|I|B|TT)<\/I>>/<$1$2>/g;
3324    $mathcontents =~ s/<\/(B|I|TT)><\1>//g;
3325    $mathcontents;
3326}
3327
3328sub do_cmd_simplemathrm {
3329    local ($_) = @_;
3330    local($text);
3331    $text = &missing_braces unless (
3332        (s/$next_pair_pr_rx/$text = $2;''/e)
3333        ||(s/$next_pair_rx/$text = $2;''/e));
3334    $text =~ s/<\/?I>//g;
3335    join('', $text, $_)
3336}
3337sub do_cmd_simplemathbf {
3338    local ($_) = @_;
3339    local($text);
3340    $text = &missing_braces unless (
3341        (s/$next_pair_pr_rx/$text = $2;''/e)
3342        ||(s/$next_pair_rx/$text = $2;''/e));
3343    $text =~ s/<\/?I>//g;
3344    join('','<B>', $text, '</B>', $_)
3345}
3346sub do_cmd_simplemathtt {
3347    local ($_) = @_;
3348    local($text);
3349    $text = &missing_braces unless (
3350        (s/$next_pair_pr_rx/$text = $2;''/e)
3351        ||(s/$next_pair_rx/$text = $2;''/e));
3352    $text =~ s/<\/?I>//g;
3353    join('','<TT>', $text, '</TT>', $_)
3354}
3355
3356sub process_math_in_latex {
3357    local($mode,$style,$level,$math) = @_;
3358    local(@anchors);
3359    if ($level) {
3360	$style = (($level > 1) ? "script" : "") . "script";
3361    } elsif (! $style) {
3362	$style = (($mode =~/display|equation/)? "display" : "")
3363    }
3364    $style = "\\${style}style" if ($style);
3365
3366    #  &process_undefined_environment  changes $_ , so save it.
3367    local($after) = $_;
3368
3369    # the 'unless' catches nested AMS-aligned environments
3370    $mode = "tex2html_wrap_" .
3371	(($mode =~/display|equation|eqnarray/) ? 'indisplay' : 'inline')
3372	    unless ($mode =~ /^equationstar/ && $outer_math =~ /^equationstar/);
3373
3374    $global{'max_id'}++;
3375    $math =~ s/\\(\n|$)/\\ $1/g;	# catch \ at end of line or string
3376    $math =~ s/^\s*((\\!|;SPMnegsp;)\s*)*//g;		# remove neg-space at start of string
3377    if ($mode =~ /tex2html_wrap_/ ) {
3378	$math = &process_undefined_environment( $mode
3379	    , $global{'max_id'}, join('', "\$$style ", $math, "\$"));
3380    } else {
3381	# some AMS environments must be within {equation} not {displaymath}
3382	$math =~ s/displaymath/equation*/
3383		if ($math =~ /\\begin\{(x+|fl)*align/);
3384	$math = &process_undefined_environment($mode, $global{'max_id'}, $math);
3385    }
3386    $math .= "\n" if ($math =~ /$comment_mark\s*\d+$/s);
3387    $_ = $after;
3388    # the delimiter \001 inhibits an unwanted \n at image-replacement
3389    $math . ($math =~ /$image_mark/? "\001" : '');
3390}
3391
3392#RRM: Explicit font switches need images. Use the image_switch mechanism.
3393sub do_cmd_font {
3394    local($_) = @_;
3395    local($fontinfo,$fontname,$size) = ('','','10pt');
3396    s/\s*\\(\w+)\s*=?\s*(.*)(\n|$)/$fontname=$1;$fontinfo=$2;''/eo;
3397    $image_switch_rx .= "|$fontname";
3398
3399    if ($fontinfo =~ /([.\d]+\s*(true)?(pt|mm|cm))/ ) { $size = $1 }
3400    elsif ( $fontinfo =~ /[a-zA-Z]+(\d+)\b/ ) { $size = $1.'pt' }
3401    if  ( $fontinfo =~ /(scaled|at)\s*\\?(.+)/) { $size .= " scaled $1" }
3402    $font_size{$fontname} = $size;
3403    $_;
3404}
3405sub wrap_cmd_font {
3406    local($cmd, $_) = @_;
3407    local ($args, $dummy, $pat) = "";
3408    if (/\n/) { $args .= $`.$& ; $_ = $' } else {$args = $_; $_ = ''};
3409    (&make_deferred_wrapper(1).$cmd.$padding.$args.&make_deferred_wrapper(0),$_)
3410}
3411
3412sub do_cmd_newfont {
3413    local($_) = @_;
3414    local($fontinfo,$fontname,$size) = ('','','10pt');
3415    $fontname = &missing_braces unless (
3416	(s/$next_pair_pr_rx/$fontname=$2;''/eo)
3417	||(s/$next_pair_rx/$fontname=$2;''/eo));
3418    $fontname=~ s/^\s*\\|\s*$//g;
3419    $image_switch_rx .= "|$fontname";
3420
3421    $fontinfo = &missing_braces unless (
3422	(s/$next_pair_pr_rx/$fontinfo=$2;''/eo)
3423	||(s/$next_pair_rx/$fontinfo=$2;''/eo));
3424    if ($fontinfo =~ /([.\d]+\s*(true)?(pt|mm|cm))/ ) { $size = $1 }
3425    elsif ( $fontinfo =~ /[a-zA-Z]+(\d+)\b/ ) { $size = $1.'pt' }
3426    if  ( $fontinfo =~ /(scaled|at)\s*\\?(.+)/) { $size .= " scaled $1" }
3427    $font_size{$fontname} = $size;
3428    $_;
3429}
3430
3431sub defined_env {
3432    local($env) = @_;
3433    $env =~ s/\*$/star/;
3434    local($env_sub) = ("do_env_$env");
3435    # The test using declarations should not be necessary but 'defined'
3436    # doesn't seem to recognise subroutines generated dynamically using 'eval'.
3437    # Remember that each entry in $declarations generates a dynamic prodedure ...
3438    ((defined &$env_sub) || ($declarations{$env}));
3439}
3440
3441# RRM: utility to add style information to stored image-parameters
3442#      currently only (math) scaling info is included;
3443#      current color, etc.  could also be added here.
3444sub addto_encoding {
3445    local($env, $contents) = @_;
3446#    $contents =~ s/(\\(begin|end)\s*)?<<\d*>>|\n//g;	# RRM: remove env delimiters
3447    $contents =~ s/(\\(begin|end)\s*(<<\d*>>))|\n//g;	# RRM: remove env delimiters
3448    # append scaling information for environments using it
3449    if (($MATH_SCALE_FACTOR)
3450	&&(($contents =~ /makeimage|inline|indisplay|entity|displaymath|eqnarray|equation|xy|diagram/)
3451	   ||($env =~ /makeimage|inline|indisplay|entity|displaymath|eqnarray|equation|xy|diagram/))
3452	) { $contents .= ";MSF=$MATH_SCALE_FACTOR" }
3453
3454    if ($LATEX_FONT_SIZE =~ /([\d\.]+)pt/) {
3455	local($fsize) = $1;
3456	$contents .= ";LFS=$fsize" unless ($fsize ==10);
3457    }
3458
3459    if (($EXTRA_IMAGE_SCALE)
3460	&&(($contents =~ /makeimage|inline|indisplay|entity|displaymath|eqnarray|equation|xy|diagram/)
3461	   ||($env =~ /makeimage|inline|indisplay|entity|displaymath|eqnarray|equation|xy|diagram/))
3462	) { $contents .= ";EIS=$EXTRA_IMAGE_SCALE" }
3463
3464    if (($DISP_SCALE_FACTOR)
3465	&&(($contents =~ /indisplay|displaymath|eqnarray|equation/)
3466	   ||($env =~ /indisplay|displaymath|eqnarray|equation/))
3467	&&!(($contents =~ /makeimage/)||($env =~ /makeimage/))
3468	) { $contents .= ";DSF=$DISP_SCALE_FACTOR" }
3469
3470    if (($EQN_TAGS)
3471	&&(($env =~ /eqnarray($|[^_\*])|equation/)
3472	   ||($contents =~ /eqnarray($|[^_\*])|equation/))
3473	&&!(($contents =~ /makeimage/)||($env =~ /makeimage/))
3474	) { $contents .= ";TAGS=$EQN_TAGS" }
3475
3476    if (($FIGURE_SCALE_FACTOR)
3477	&&!(($contents =~ /makeimage/)||($env =~ /makeimage/))
3478	&&(($contents =~ /figure/)||($env =~ /figure/))
3479	) { $contents .= ";FSF=$FIGURE_SCALE_FACTOR"}
3480
3481    if (($ANTI_ALIAS)
3482	&&(($contents =~ /figure/)||($env =~ /figure/))
3483	&&!(($contents =~ /makeimage/)||($env =~ /makeimage/))
3484	) { $contents .= ";AAF" }
3485    elsif ($ANTI_ALIAS_TEXT) { $contents .= ";AAT" }
3486    if (!$TRANSPARENT_FIGURES) { $contents .= ";NTR" }
3487
3488    $contents;
3489}
3490
3491sub process_undefined_environment {
3492    local($env, $id, $contents) = @_;
3493    if ($env =~ s/\*{2,}/*/) { print "\n*** $_[0] has too many \*s ***"};
3494
3495    local($name,$cached,$raw_contents,$uucontents) = ("$env$id");
3496    $name =~ s/\*/star/;
3497    local($oldimg,$size,$fullcontents,$imgID);
3498    return if ($AUX_FILE);
3499
3500    # catch \footnotemark within an image, especially if in math
3501    local(@foot_anchors,$foot_anchor);
3502    local($im_footnote,$im_mpfootnote) = ($global{'footnote'},$global{'mpfootnote'});
3503    @foot_anchors = &process_image_footnote($contents)
3504	if ($contents =~ /\\footnote(mark)?\b/s);
3505    if ((@foot_anchors)&&($eqno)) {
3506	# append the markers to the equation-numbers
3507	$eqno .= join(' ', ' ', @foot_anchors);
3508	@foot_anchors = ();
3509    }
3510
3511    print STDOUT "\nUNDEF-IN {$env $id}:\n$contents\n" if ($VERBOSITY > 4);
3512    #RRM - LaTeX commands wrapped with this environment go directly into images.tex.
3513    if ($env =~ /tex2html_nowrap|^lrbox$/){ # leave off the wrapper, do not cache
3514	# totally ignore if in preamble...
3515	# ...since it will be put into  images.tex  anyway!!
3516	if (!($PREAMBLE)) {
3517	    $contents =~ s/^\n+|\n+$/\n/g;
3518	    local($lcontents) = join('', "\\begin{$env}", $contents , "\\end{$env}" );
3519	    $lcontents =~ s/\\(index|label)\s*(($O|$OP)\d+($C|$CP)).*\2//sg;
3520	    print STDOUT "pre-LATEX {$env}:\n$lcontents\n" if ($VERBOSITY > 3);
3521	    $raw_contents = &revert_to_raw_tex($lcontents);
3522	    print STDOUT "LATEX {$env}:\n$raw_contents\n" if ($VERBOSITY > 3);
3523	    $latex_body .= "\n$raw_contents"."%\n\n" ;
3524	}
3525	return("") if ($env =~ /^lrbox/);
3526	# ignore enclosed environments; e.g. in  \settolength  commands
3527#	$contents = &translate_environments($contents); # ignore environments
3528#	$contents = &translate_commands($contents);
3529	# ...but apply any Perl settings that may be defined
3530	$contents = &process_command($single_cmd_rx,$contents);
3531	print STDOUT "\nOUT {$env $id}:\n$contents\n" if ($VERBOSITY > 4);
3532	return("");
3533    }
3534    # catch pre-processor environments
3535    if ($PREPROCESS_IMAGES) {
3536	local($pre_env,$which, $done, $indic);
3537	while ($contents =~ /$pre_processor_env_rx/) {
3538	    $done .= $`; $pre_env = $5; $which =$1; $contents = $';
3539	    if (($which =~ /begin/)&&($pre_env =~ /indica/)) {
3540		if ($contents =~ s/^\[(\w+)]//o) { $done .= '#'.$1 }
3541	    } elsif (($which =~ /end/)&&($pre_env =~ /indica/)) {
3542		$done .= '#NIL';
3543	    } elsif (($which =~ /begin/)&&($pre_env =~ /itrans/)) {
3544		if ($contents =~ s/^\[(\w+)]/$indic=$1;''/e)
3545	            { $done .= "\#$indic" }
3546	    } elsif (($which =~ /end/)&&($pre_env =~ /itrans/)) {
3547		$done .= "\#end$indic";
3548	    } elsif ($which =~ /begin/) {
3549		$done .= (($which =~ /end/)? $end_preprocessor{$pre_env}
3550		          : $begin_preprocessor{$pre_env} )
3551	    }
3552	}
3553	$contents = $done . $contents;
3554    }
3555    $fullcontents =  $contents; # save for later \label search.
3556    # MRO: replaced $* with /m
3557    $contents =~ s/\n?$labels_rx(\%([^\n]+$|$EOL))?/\n/gm;
3558
3559    local($tmp) = $contents;
3560    $tmp =~ s/^((\\par|\%)?\s*\n)+$//g;
3561    return( &do_labels($fullcontents, "\&nbsp;") ) unless $tmp;
3562
3563    # just a comment as the contents of a cell in a math-display
3564    if ($tmp =~ /\$\\(display|text|(script)+)style\s*$comment_mark\d+\s*\$$/)
3565	{ return ( &do_labels($fullcontents, "\&nbsp;") ) };
3566
3567    $contents = "\n% latex2html id marker $id\n$contents" if
3568	(!$PREAMBLE &&($contents =~ /$order_sensitive_rx/)
3569		&&(!($env =~ /makeimage/)));
3570
3571    $env =~ s/displaymath/equation*/
3572	if ($contents =~ /\\begin\{(x+|fl)*align/);
3573    #RRM: include the inline-color, when applicable
3574    $contents = join(''
3575	    , (($inner_math =~ /in(display|line)/) ? '$' : '')
3576	    , "\\begin{$env}"
3577	    , ($color_env ? "\\bgroup\\$color_env" : '')
3578	    , $contents , ($color_env ? "\\egroup" : '')
3579	    , "\\end{$env}"
3580	    , (($inner_math =~ /in(display|line)/) ? '$' : '')
3581	) if ($contents);
3582
3583    # append to the name of special environments found within math
3584    if ($inner_math) {
3585	local($ext) = $inner_math;
3586	if ($inner_math =~ /(display|line)/){ $ext = 'in'.$1;};
3587	$name =~ s/(\d+)$/_$ext$1/;
3588    }
3589
3590    if (!($latex_body{$name} = $contents)) {
3591	print "\n *** code for $name is too long ***\n"}
3592    if ($contents =~ /$htmlimage_rx/) {
3593	$uucontents = &special_encoding($env,$2,$contents);
3594    } elsif ($contents =~ /$htmlimage_pr_rx/) {
3595	$uucontents = &special_encoding($env,$2,$contents);
3596    } else {
3597	$uucontents = &encode(&addto_encoding($env,$contents));
3598    }
3599    $cached = $cached_env_img{$uucontents};
3600    print STDOUT "\nCACHED: $uucontents:\n$cached\n" if ($VERBOSITY > 4);
3601    if ($NOLATEX) {
3602	$id_map{$name} = "[$name]";
3603    } elsif (defined ($_ = $cached)) { # Is it in our cache?
3604	# Have we already used it?
3605	if (($oldimg) = /SRC="$PREFIX$img_rx\.$IMAGE_TYPE"/o) {
3606	    # No, check its size
3607	    local($eis) = 1;
3608	    # Does it have extra scaling ?
3609	    if ($uucontents =~ /EIS=(.*);/) { $eis = $1 }
3610	    ($size, $imgID) = &get_image_size("$PREFIX$oldimg.old", $eis);
3611	    # Does it have extra scaling ?
3612#	    if ($uucontents =~ /EIS=(.*);/) {
3613#		local($eis) = $1; local($w,$h);
3614#		# quotes will not be there with HTML 2.0
3615#		$size =~ s/(WIDTH=\")(\d*)(\".*HEIGHT=\")(\d*)\"/
3616#		    $w = int($2\/$eis + .5); $h=int($4\/$eis + .5);
3617#		    "$1$w$3$h\""/e ; # insert the re-scaled size
3618#	    }
3619	    # quotes will not be there with HTML 2.0
3620	    $size =~ s/\"//g if ($HTML_VERSION < 2.2);
3621	    if ($size && /\s$size\s/) {
3622		# Size is OK; recycle it!
3623		++$global_page_num;
3624		$_ = $cached ;    # ...perhaps restoring the desired size.
3625		s/(${PREFIX}T?img)\d+\.($IMAGE_TYPE|html)/
3626			&rename_html($&,"$1$global_page_num.$2")/geo;
3627	    } else {
3628		if ($env =~ /equation/) { &extract_eqno($name,$cached) }
3629		$_ = "";				# The old Image has wrong size!
3630		undef($cached);			#  (or it doesn't exist)
3631	    }
3632	}
3633	s/(IMG\n)/$1$imgID/ if $imgID;
3634
3635	s/$PREFIX$img_rx\.new/$PREFIX$1.$IMAGE_TYPE/go; # Point to the actual image file(s)
3636	$id_map{$name} = $_;
3637	s/$PREFIX$img_rx\.$IMAGE_TYPE/$PREFIX$1.new/go;	# But remember them as used.
3638	$cached_env_img{$uucontents} = $_;
3639    }
3640
3641    if (! defined($cached)) {				# Must generate it anew.
3642	&clear_images_dbm_database
3643	    unless ($new_page_num ||($NO_SUBDIR && $FIXEDDIR));
3644	$new_id_map{$name} = $id_map{$name} = ++$global_page_num . "#" .
3645	    ++$new_page_num;
3646	$orig_name_map{$id_map{$name}} = $name;
3647	$cached_env_img{$uucontents} = $id_map{$name} if ($REUSE == 2);
3648
3649	#RRM: this (old) code frequently crashes NDBM, so do it in 2 steps
3650#	$img_params{$name} = join('#', &extract_parameters($contents));
3651	local(@params) = &extract_parameters($contents);
3652	$img_params{$name} = join('#',@params); undef $params;
3653	print "\nIMAGE_PARAMS $name: ".$img_params{$name} if ($VERBOSITY > 3);
3654
3655	$contents =~ s/\\(index|label)\s*(($O|$OP)\d+($C|$CP)).*\2//sg;
3656	print STDOUT "\nLATEX {$env}:\n$contents" if ($VERBOSITY > 3);
3657	$raw_contents = &revert_to_raw_tex($contents) unless ($contents =~ /^\s*$/) ;
3658	$raw_contents =~ s/\\pagebreak|\\newpage|\\clearpage/\\\\/go;
3659	print STDOUT "\nLATEX {$env}:\n$raw_contents\n" if ($VERBOSITY > 3);
3660	local($box_type) = '';
3661	if ($raw_contents =~ /\\special\s*\{/) {
3662	    $tex_specials{$name} = "1";
3663	    &write_warnings("\nenvironment $name contains \\special commands");
3664	    print STDOUT "\n *** environment $name contains \\special commands ***\n"
3665		if ($VERBOSITY);
3666	} elsif (($env =~ /$inline_env_rx/)||($inner_math =~ /in(line|display)/)) {
3667	    # crop to the marks only... or shave a bit off the bottom
3668	    if (($env =~ /tex2html_[^w]/)||$inner_math) {
3669		# e.g. accents, indic  but not wrap
3670		$crop{$name} = "bl";
3671		$box_type = "i";
3672	    } else {
3673	    # ...or shave a bit off the bottom as well
3674		$crop{$name} = "bls";
3675		$box_type = "h";
3676	    }
3677	} elsif (($env =~ /(eqnarray|equation)(\*|star)/)||($inner_math)) {
3678	    # crop to minimum size...
3679	    $crop{$name} = "blrl";
3680	    $box_type = "v";
3681	} elsif ($env =~ /(picture|tex2html_wrap)(\*|star)?/) {
3682	    # crop hbox to minimum size...
3683	    $crop{$name} = "";
3684	    $box_type = "p";
3685	} elsif ($env =~ /$display_env_rx/) {
3686	    # crop vbox to minimum size...
3687	    $crop{$name} = "blrl" ;
3688	    if ($env =~ /(equation|eqnarray)((s)?$|\d)/) {
3689		# ... unless equation numbers are included ...
3690		if ($3) { #  AMS {subequations}
3691		    $global{'eqn_number'}=$prev_eqn_number if $prev_eqn_number;
3692		    --$global{'eqn_number'};
3693		}
3694		$raw_contents = join('' ,
3695		    (($eqno{$name}||$global{'eqn_number'})?
3696		      &set_equation_counter($eqno{$name}) : '')
3697		    , $raw_contents);
3698		$crop{$name} = "bl" ;
3699	    } elsif ($HTML_VERSION < 2.2) {
3700		# ... HTML 2.0 cannot align images, so keep the full typeset width
3701		$crop{$name} = "bl" ;
3702	    }
3703	    $box_type = "v";
3704	}
3705
3706	#RRM: include the TeX-code for the appropriate type of box.
3707	eval "\$raw_contents = \&make_$box_type"."box($name, \$raw_contents);";
3708
3709	# JCL(jcl-pag) - remember html text if debug is set.
3710	local($_);
3711	if ($DEBUG) {
3712	    $_ = $contents;
3713	    s/\n/ /g;
3714	    $_ = &revert_to_raw_tex($_);
3715	    # incomplete or long commented code can break pre-processors
3716	    if ($PREPROCESS_IMAGES) {
3717		$_ = ((/^(\\\w+)?\{[^\\\}\<]*\}?/)? $& : '').'...' ;
3718		$_ = '{ ... }' if ( length($_) > 100);
3719	    } elsif ( length($_) > 200) {
3720		    $_ = join('',substr($_,0,200),"...\}");
3721	    }
3722	    s/\\(begin|end)/$1/g; s/[\000-\020]//g;
3723	    $_ = join('',"% contents=",$_,"\n");
3724	}
3725	$raw_contents = '\setcounter{equation}{'.$prev_eqn_number."}\n".$raw_contents
3726	    if ($env =~ /subequations/);
3727
3728# JCL(jcl-pag) - build the page entries for images.tex:  Each page is embraced to
3729# let most statements have only local effect. Each page must compile into a
3730# single dvi page to get proper image translation. Hence the invisible glue to
3731# get *at least* one page (raw_contents alone might not wield glue), and
3732# sufficing page length to get *exactly* one page.
3733#
3734	$latex_body .= "{\\newpage\\clearpage\n$_" .
3735#	    "$raw_contents\\hfill\\vglue1pt\\vfill}\n\n";
3736#	    "$raw_contents\\hfill\\vss}\n\n" if ($raw_contents);
3737#	    "$raw_contents\\hfill\\lthtmlcheckvsize\\clearpage}\n\n" if ($raw_contents);
3738	    "$raw_contents\\lthtmlcheckvsize\\clearpage}\n\n" if ($raw_contents);
3739    }
3740    print STDOUT "\nIMAGE_CODE:{$env $id}:\n$raw_contents\n" if ($VERBOSITY > 4);
3741
3742    # Anchor the labels and put a marker in the text;
3743    local($img) = &do_labels($fullcontents,"$image_mark#$name#");
3744    print STDOUT "\nUNDEF_OUT {$env $id}:\n$img\n" if ($VERBOSITY > 4);
3745    return($img) unless (@foot_anchors);
3746
3747    # use the image as source to the 1st footnote, unless it is already an anchor.
3748    if ($img =~ /<\/?A>/) {
3749	join(' ', $img, @foot_anchors);
3750    } elsif ($#foot_anchors ==0) {
3751	$foot_anchor = shift @foot_anchors;
3752	$foot_anchor =~ s/<SUP>.*<\/SUP>/$img/;
3753#	join(' ', $foot_anchor, @foot_anchors);
3754	$foot_anchor;
3755    } else {
3756	join(' ', $img, @foot_anchors);
3757    }
3758}
3759
3760sub special_encoding { # locally sets $EXTRA_IMAGE_SCALE
3761    local($env,$_,$contents) = @_;
3762    local($exscale) = /extrascale=([\.\d]*)/;
3763    local($EXTRA_IMAGE_SCALE) = $exscale if ($exscale);
3764    &encode(&addto_encoding($env,$contents));
3765}
3766
3767
3768sub extract_eqno{
3769    local($name,$contents) = @_;
3770    if ($contents =~ /<P ALIGN="\w+">\(([^<>])\)<\/P>$/) {
3771	if (($eqno{$name})&&!($eqno{$name} eq $1)) {
3772	    &write_warnings("\nequation number for $name may be wrong.")};
3773	$eqno{$name}="$1";
3774    }
3775}
3776sub set_equation_counter{
3777    if ( $global{'eqn_number'}) {
3778	"\\setcounter{equation}{". $global{'eqn_number'} ."}\n"
3779    } else { "\\setcounter{equation}{0}\n" }
3780}
3781
3782# RRM: 3 different types of boxing, for image environments.
3783
3784#	general environments --- crops to width & height
3785sub make_box {
3786    local($id,$contents) = @_;
3787    "\\lthtmlfigureA{". $id ."}%\n". $contents ."%\n\\lthtmlfigureZ\n";
3788}
3789
3790#	inline math --- horizontal mode, captures height/depth + \mathsurround
3791sub make_hbox {
3792    local($id,$contents) = @_;
3793    if ($id =~ /indisplay/) {
3794	"\\lthtmlinlinemathA{". $id ."}%\n". $contents ."%\n\\lthtmlindisplaymathZ\n";
3795    } else {
3796	"\\lthtmlinlinemathA{". $id ."}%\n". $contents ."%\n\\lthtmlinlinemathZ\n";
3797    }
3798}
3799
3800#	inline text-image (e.g. accents) --- horizontal mode, captures height/depth
3801sub make_ibox {
3802    local($id,$contents) = @_;
3803    "\\lthtmlinlineA{". $id ."}%\n". $contents ."%\n\\lthtmlinlineZ\n";
3804}
3805
3806#	centered images (e.g. picture environments) --- horizontal mode
3807sub make_pbox {
3808    local($id,$contents) = @_;
3809    "\\lthtmlpictureA{". $id ."}%\n". $contents ."%\n\\lthtmlpictureZ\n";
3810}
3811
3812#	displayed math --- vertical mode, captures height/depth + page-width
3813sub make_vbox {
3814    local($id,$contents) = @_;
3815    if (($HTML_VERSION >=3.2)&&($id =~/(equation|eqnarray)($|\d)/) &&! $failed ) {
3816	if ($contents =~ s/^\\setcounter\{equation\}\{\d+\}/$&%\n\\lthtmldisplayB\{$id\}%/)
3817	    { $contents ."%\n\\lthtmldisplayZ\n" }
3818	else { "\\lthtmldisplayB{$id}%\n". $contents ."%\n\\lthtmldisplayZ\n" }
3819    } else { "\\lthtmldisplayA{$id}%\n". $contents ."%\n\\lthtmldisplayZ\n"}
3820}
3821
3822sub preprocess_images {
3823    do {
3824	print "\nWriting image.pre file ...\n";
3825	open(ENV,">.$dd${PREFIX}images.pre")
3826            || die "\nCannot write '${PREFIX}images.pre': $!\n";
3827	print ENV &make_latex($latex_body);
3828	print ENV "\n";
3829	close ENV;
3830	&copy_file($FILE, "bbl");
3831	&copy_file($FILE, "aux");
3832	local($num_cmds, $cnt, $this, @cmds);
3833	@cmds = (split ('\n', $preprocessor_cmds));
3834	$this_cmd = $num_cmds = 1+$#cmds;
3835	$cnt = $num_cmds; $preprocessor_cmds = '';
3836	while (@cmds) {
3837	    $this_cmd = shift @cmds; last unless ($this_cmd);
3838	    $this_cmd =~ s/.pre /.tex$cnt / if(($cnt)&&($cnt < $num_cmds));
3839	    $cnt--; $this_cmd .= $cnt if ($cnt);
3840	    $preprocessor_cmds .= $this_cmd."\n";
3841	    L2hos->syswait($this_cmd);
3842	}
3843	# save pre-processor commands in a file:  preproc
3844	open(CMDS,">.$dd${PREFIX}preproc")
3845            || die "\nCannot write '${PREFIX}preproc': $!\n";
3846	print CMDS $preprocessor_cmds ;
3847	close CMDS;
3848
3849    } if ((%latex_body) && ($latex_body =~ /newpage/));
3850}
3851sub make_image_file {
3852    do {
3853	print "\nWriting image file ...\n";
3854	open(ENV,">.$dd${PREFIX}images.tex")
3855            || die "\nCannot write '${PREFIX}images.tex': $!\n";
3856	print ENV &make_latex($latex_body);
3857	print ENV "\n";
3858	close ENV;
3859	&copy_file($FILE, "bbl");
3860	&copy_file($FILE, "aux");
3861    } if ((%latex_body) && ($latex_body =~ /newpage/));
3862}
3863
3864sub make_latex_images{
3865    &close_dbm_database if $DJGPP;
3866    local($dd) = $dd; $dd = '/' if ($dd eq "\\");
3867    local($latex_call) = "$LATEX .$dd${PREFIX}images.tex";
3868    print "$latex_call\n" if (($DEBUG)||($VERBOSITY > 1));
3869    L2hos->syswait($latex_call);
3870    &open_dbm_database if $DJGPP;
3871}
3872
3873sub make_off_line_images {
3874    local($name, $page_num);
3875    if (!$NOLATEX && -f ".${dd}${PREFIX}images.tex") {
3876	&make_tmp_dir;	# sets  $TMPDIR  and  $DESTDIR
3877	$IMAGE_PREFIX =~ s/^_//o if ($TMPDIR);
3878
3879	&make_latex_images();
3880
3881	print "\nGenerating postscript images using dvips ...\n";
3882	&process_log_file(".$dd${PREFIX}images.log"); # Get eqn size info
3883	unless ($LaTeXERROR) {
3884	    local($dvips_call) =
3885		"$DVIPS -S1 -i $DVIPSOPT -o$TMPDIR$dd${IMAGE_PREFIX} .${dd}${PREFIX}images.dvi";
3886	    print "$dvips_call\n" if (($DEBUG)||($VERBOSITY > 1));
3887
3888	    &close_dbm_database if $DJGPP;
3889	    L2hos->syswait($dvips_call) && print "Error: $!\n";
3890	    undef $dvips_call;
3891	    &open_dbm_database if $DJGPP;
3892
3893	    # add suffix .ps to the file-names for each image
3894	    if(opendir(DIR, $TMPDIR || '.')) {
3895                #  use list-context instead; thanks De-Wei Yin <yin@asc.on.ca>
3896	        my (@ALL_IMAGE_FILES) = grep /^$IMAGE_PREFIX\d+$/o, readdir(DIR);
3897	        foreach (@ALL_IMAGE_FILES) {
3898		        L2hos->Rename("$TMPDIR$dd$_", "$TMPDIR$dd$_.ps");
3899	        }
3900	        closedir(DIR);
3901            } else {
3902                print "\nError: Cannot read dir '$TMPDIR': $!\n";
3903            }
3904	}
3905    }
3906    if ($LaTeXERROR) {
3907        print "\n\n*** LaTeXERROR\n"; return();
3908    }
3909
3910    while ( ($name, $page_num) = each %new_id_map) {
3911	# Extract the page, convert and save it
3912	&extract_image($page_num,$orig_name_map{$page_num});
3913    }
3914}
3915
3916# Generate images for unknown environments, equations etc, and replace
3917# the markers in the main text with them.
3918# - $cached_env_img maps encoded contents to image URL's
3919# - $id_map maps $env$id to page numbers in the generated latex file and after
3920# the images are generated, maps page numbers to image URL's
3921# - $page_map maps page_numbers to image URL's (temporary map);
3922# Uses global variables $id_map and $cached_env_img,
3923# $new_page_num and $latex_body
3924
3925
3926sub make_images {
3927    local($name, $contents, $raw_contents, $uucontents, $page_num,
3928	  $uucontents, %page_map, $img);
3929    # It is necessary to run LaTeX this early because we need the log file
3930    # which contains information used to determine equation alignment
3931    if ( $latex_body =~ /newpage/) {
3932	print "\n";
3933	if ($LATEX_DUMP) {
3934	    # dump a pre-compiled format
3935	    if (!(-f "${PREFIX}images.fmt")) {
3936	        print "$INILATEX ./${PREFIX}images.tex\n"
3937		    if (($DEBUG)||($VERBOSITY > 1));
3938	        print "dumping ${PREFIX}images.fmt\n"
3939		    unless ( L2hos->syswait("$INILATEX ./${PREFIX}images.tex"));
3940	    }
3941	    local ($img_fmt) = (-f "${PREFIX}images.fmt");
3942	    if ($img_fmt) {
3943                # use the pre-compiled format
3944	        print "$TEX \"&./${PREFIX}images\" ./${PREFIX}images.tex\n"
3945		    if (($DEBUG)||($VERBOSITY > 1));
3946	        L2hos->syswait("$TEX \"&./${PREFIX}images\" ./${PREFIX}images.tex");
3947	    } elsif (-f "${PREFIX}images.dvi") {
3948	        print "${PREFIX}images.fmt failed, proceeding anyway\n";
3949	    } else {
3950	        print "${PREFIX}images.fmt failed, trying without it\n";
3951		print "$LATEX ./${PREFIX}images.tex\n"
3952		    if (($DEBUG)||($VERBOSITY > 1));
3953		L2hos->syswait("$LATEX ./${PREFIX}images.tex");
3954	    }
3955	} else { &make_latex_images() }
3956#	    local($latex_call) = "$LATEX .$dd${PREFIX}images.tex";
3957#	    print "$latex_call\n" if (($DEBUG)||($VERBOSITY > 1));
3958#	    L2hos->syswait("$latex_call");
3959##	    print "$LATEX ./${PREFIX}images.tex\n" if (($DEBUG)||($VERBOSITY > 1));
3960##	    L2hos->syswait("$LATEX ./${PREFIX}images.tex");
3961##        }
3962	$LaTeXERROR = 0;
3963	&process_log_file("./${PREFIX}images.log"); # Get image size info
3964    }
3965    if ($NO_IMAGES) {
3966        my $img = "image.$IMAGE_TYPE";
3967	my $img_path = "$LATEX2HTMLDIR${dd}icons$dd$img";
3968	L2hos->Copy($img_path, ".$dd$img")
3969            if(-e $img_path && !-e $img);
3970    }
3971    elsif ((!$NOLATEX) && ($latex_body =~ /newpage/) && !($LaTeXERROR)) {
3972   	print "\nGenerating postscript images using dvips ...\n";
3973        &make_tmp_dir;  # sets  $TMPDIR  and  $DESTDIR
3974	$IMAGE_PREFIX =~ s/^_//o if ($TMPDIR);
3975
3976	local($dvips_call) =
3977		"$DVIPS -S1 -i $DVIPSOPT -o$TMPDIR$dd$IMAGE_PREFIX .${dd}${PREFIX}images.dvi\n";
3978	print $dvips_call if (($DEBUG)||($VERBOSITY > 1));
3979
3980	if ((($PREFIX=~/\./)||($TMPDIR=~/\./)) && not($DVIPS_SAFE)) {
3981	    print " *** There is a '.' in $TMPDIR or $PREFIX filename;\n"
3982	    	. "  dvips  will fail, so image-generation is aborted ***\n";
3983	} else {
3984	    &close_dbm_database if $DJGPP;
3985	    L2hos->syswait($dvips_call) && print "Error: $!\n";
3986	    &open_dbm_database if $DJGPP;
3987	}
3988
3989	# append .ps suffix to the filenames
3990	if(opendir(DIR, $TMPDIR || '.')) {
3991            # use list-context instead; thanks De-Wei Yin <yin@asc.on.ca>
3992	    my @ALL_IMAGE_FILES = grep /^$IMAGE_PREFIX\d+$/o, readdir(DIR);
3993	    foreach (@ALL_IMAGE_FILES) {
3994	        L2hos->Rename("$TMPDIR$dd$_", "$TMPDIR$dd$_.ps");
3995	    }
3996	    closedir(DIR);
3997        } else {
3998            print "\nError: Cannot read dir '$TMPDIR': $!\n";
3999        }
4000    }
4001    do {print "\n\n*** LaTeXERROR"; return()} if ($LaTeXERROR);
4002    return() if ($LaTeXERROR); # empty .dvi file
4003    L2hos->Unlink(".$dd${PREFIX}images.dvi") unless $DEBUG;
4004
4005    print "\n *** updating image cache\n" if ($VERBOSITY > 1);
4006    while ( ($uucontents, $_) = each %cached_env_img) {
4007	delete $cached_env_img{$uucontents}
4008	    if ((/$PREFIX$img_rx\.$IMAGE_TYPE/o)&&!($DESTDIR&&$NO_SUBDIR));
4009	$cached_env_img{$uucontents} = $_
4010	    if (s/$PREFIX$img_rx\.new/$PREFIX$1.$IMAGE_TYPE/go);
4011    }
4012    print "\n *** removing unnecessary images ***\n" if ($VERBOSITY > 1);
4013    while ( ($name, $page_num) = each %id_map) {
4014	$contents = $latex_body{$name};
4015	if ($page_num =~ /^\d+\#\d+$/) { # If it is a page number
4016	    do {		# Extract the page, convert and save it
4017		$img = &extract_image($page_num,$orig_name_map{$page_num});
4018		if ($contents =~ /$htmlimage_rx/) {
4019		    $uucontents = &special_encoding($env,$2,$contents);
4020		} elsif ($contents =~ /$htmlimage_pr_rx/) {
4021		    $uucontents = &special_encoding($env,$2,$contents);
4022		} else {
4023		    $uucontents = &encode(&addto_encoding($contents,$contents));
4024		}
4025		if (($HTML_VERSION >=3.2)||!($contents=~/$order_sensitive_rx/)){
4026		    $cached_env_img{$uucontents} = $img;
4027		} else {
4028                    # Blow it away so it is not saved for next time
4029		    delete $cached_env_img{$uucontents};
4030		    print "\nimage $name not recycled, contents may change (e.g. numbering)";
4031		}
4032		$page_map{$page_num} = $img;
4033	    } unless ($img = $page_map{$page_num}); # unless we've just done it
4034	    $id_map{$name} = $img;
4035	} else {
4036	    $img = $page_num;	# it is already available from previous runs
4037	}
4038	print STDOUT " *** image done ***\n" if ($VERBOSITY > 2);
4039    }
4040    &write_warnings(
4041		    "\nOne of the images is more than one page long.\n".
4042		    "This may cause the rest of the images to get out of sync.\n\n")
4043	if (-f sprintf("%s%.3d%s", $IMAGE_PREFIX, ++$new_page_num, ".ps"));
4044    print "\n *** no more images ***\n"  if ($VERBOSITY > 1);
4045    # MRO: The following cleanup seems to be incorrect: The DBM is
4046    # still open at this stage, this causes a lot of unlink errors
4047    #
4048    #do { &cleanup; print "\n *** clean ***\n"  if ($VERBOSITY > 1);}
4049    #	unless $DJGPP;
4050}
4051
4052# MRO: This copies the navigation icons from the distribution directory
4053# or an alternative specified in $ALTERNATIVE_ICONS
4054# to the document directory.
4055
4056sub copy_icons {
4057    local($icon,$_);
4058    print "\nCopying navigation icons ...";
4059    foreach (keys %used_icons) {
4060	# each entry ends in gif or png
4061	if ($ALTERNATIVE_ICONS) {
4062	    L2hos->Copy("$ALTERNATIVE_ICONS$dd$_", ".$dd$_")
4063		if (-e "$ALTERNATIVE_ICONS$dd$_" && !-e $_);
4064	} elsif (/(gif|png)$/) {
4065	    L2hos->Copy("$LATEX2HTMLDIR${dd}icons$dd$_", ".$dd$_")
4066		if (-e "$LATEX2HTMLDIR${dd}icons$dd$_" && !-e $_);
4067	}
4068    }
4069}
4070
4071sub process_log_file {
4072    local($logfile) = @_;
4073    local($name,$before,$lengthsfound);
4074    local($TeXpt)= 72/72.27;
4075    local($image_counter);
4076    open(LOG, "<$logfile") || die "\nCannot read logfile '$logfile': $!\n";
4077    while (<LOG>) {
4078        if (/Overfull/) { $before .= $_ }
4079        elsif (/latex2htmlLength ([a-zA-Z]+)=(\-?[\d\.]+)pt/) {
4080	    ${$1} = 0.0+$2; $lengthsfound = 1;
4081	} elsif (/latex2htmlSize|l2hSize/) {
4082	    /:([^:]*):/;
4083	    $name = $1; $name =~ s/\*//g;
4084	    ++$image_counter;
4085	    s/:([0-9.]*)pt/$height{$name} = $1*$TeXpt;''/e;
4086	    s/::([0-9.]*)pt/$depth{$name} = $1*$TeXpt;''/e;
4087	    s/::([0-9.]*)pt/$width{$name} = $1*$TeXpt;''/e;
4088	    s/\((.*)\)/$eqno{$name} = 1+$1;''/e;
4089	    if ($before) {
4090		local($tmp);
4091		if ($before =~ /hbox\s*\((\d+\.?\d*)pt/) {
4092		    $width{$name} = $width{$name}+$1*$TeXpt;
4093		}
4094		if ($before =~ /vbox\s*\((\d+\.?\d*)pt/) {
4095		    $height{$name} = $height{$name}+$1*$TeXpt;
4096		}
4097	        $before = '';
4098	    }
4099	}
4100    $LaTeXERROR = 1 if (/^No pages of output./);
4101    }
4102
4103    if ($LaTeXERROR) {
4104	print STDERR "\n\n *** LaTeX produced no output ***\n"
4105	    . " *** no new images can be created\n"
4106	    . " *** Examine the  images.log  file.\n\n";
4107	return;
4108    }
4109    print STDOUT "\n *** processing $image_counter images ***\n";
4110    print STDOUT "\n *** LATEX LOG OK. ***\n" if ($VERBOSITY > 1);
4111
4112    if ($lengthsfound) {
4113	$ODD_HMARGIN  = $hoffset + $oddsidemargin;
4114	$EVEN_HMARGIN = $hoffset + $evensidemargin;
4115	$VMARGIN = $voffset + $topmargin + $headheight + $headsep;
4116        if ($dvi_mag >0 && $dvi_mag != 1000) {
4117	    $ODD_HMARGIN = int($dvi_mag /1000 * $ODD_HMARGIN);
4118	    $EVEN_HMARGIN = int($dvi_mag /1000 * $EVEN_HMARGIN);
4119	    $VMARGIN = int($dvi_mag /1000 * $VMARGIN);
4120	}
4121    } else {
4122	$ODD_HMARGIN = 0;
4123	$EVEN_HMARGIN = 0;
4124	$VMARGIN = 0;
4125    }
4126    $ODD_HMARGIN  = int($ODD_HMARGIN*$TeXpt  + 72.5);
4127    $EVEN_HMARGIN = int($EVEN_HMARGIN*$TeXpt + 72.5);
4128    $VMARGIN = int($VMARGIN*$TeXpt + 72.5);
4129    close(LOG);
4130}
4131
4132sub extract_image { # clean
4133    my ($page_num,$name) = @_;
4134
4135    # The followin come out of %img_params
4136    my ($scale, $external, $thumbnail, $map, $psimage, $align, $usemap,
4137	  $flip, $aalias, $trans, $exscale, $alt, $exstr);
4138
4139    my ($lwidth, $val) = (0, '');
4140    my ($custom_size,$color_depth,$height,$width,$croparg);
4141
4142    print STDOUT "\nextracting $name as $page_num\n" if ($VERBOSITY > 1);
4143    # $global_num identifies this image in the original source file
4144    # $new_num identifies this image in images.tex
4145    my ($global_num, $new_num) = split(/#/, $page_num);
4146    $name =~ s/\*/star/;
4147    my ($env,$basename,$img) = ($name,"img$global_num",'');
4148    $env =~ s/\d+$//;
4149    $psname = sprintf("%s%.3d", "$TMPDIR$dd$IMAGE_PREFIX", $new_num);
4150    if ( $EXTERNAL_IMAGES && $PS_IMAGES ) {
4151	$img =  "$basename.ps";
4152	L2hos->Copy("$psname.ps", "${PREFIX}$img");
4153    } else {
4154	$img = "$basename.$IMAGE_TYPE";
4155	($scale, $external, $thumbnail, $map, $psimage, $align, $usemap,
4156	    $flip, $aalias, $trans, $exscale, $alt, $exstr) =
4157            split('#', $img_params{$name});
4158	$lwidth = ($align =~ s/nojustify/middle/) ? 0 : $LINE_WIDTH;
4159	$alt = "ALT=\"$name\"" unless $alt;
4160	$exscale = $EXTRA_IMAGE_SCALE unless($exscale);
4161	if ($NO_IMAGES) {
4162	    L2hos->Symlink("image.$IMAGE_TYPE", "${PREFIX}$img");
4163	    if ($thumbnail) {
4164		L2hos->Symlink("image.$IMAGE_TYPE", "${PREFIX}T$img");
4165		$thumbnail = "${PREFIX}T$img";
4166	    }
4167	} else {
4168	    # RRM: deal with size data
4169 	    if ($width{$name} < 0) {
4170		if ($exscale && $PK_GENERATION) {
4171	    	    $height = int(
4172			$exscale*$height{$name}+
4173			$exscale*$depth{$name} +.5);
4174		    $width = int($exscale*$width{$name}-.5);
4175		} else {
4176	    	    $height = int($height{$name}+$depth{$name}+.5);
4177		    $width = int($width{$name}-.5);
4178		}
4179		$custom_size = "${width}x$height";
4180	    } elsif ($width{$name}) {
4181		if ($exscale && $PK_GENERATION) {
4182		    $height = int( $height{$name} * $exscale +
4183			$depth{$name} * $exscale +.5);
4184		    $width = int($width{$name} * $exscale +.5);
4185		} else {
4186		    $height = int($height{$name}+$depth{$name}+.5);
4187		    $width = int($width{$name}+.5);
4188		}
4189		$custom_size = "${width}x$height";
4190            } else {
4191		$custom_size = '';
4192	    }
4193            # MRO: add first overall crop
4194	    $croparg = '-crop a' . ($crop{$name} || '') . ' ';
4195	    $page_num  =~ s/^\d+#//o;
4196	    $custom_size .= " -margins "
4197		. (($page_num % 2) ? $ODD_HMARGIN:$EVEN_HMARGIN)
4198		. ",$VMARGIN" if ($custom_size);
4199
4200	    #RRM: \special commands may place ink outside the expected bounds:
4201	    $custom_size = '' if ($tex_specials{$name});
4202
4203	    # MRO: Patches for image conversion with pstoimg
4204	    # RRM: ...with modifications and fixes
4205	    L2hos->Unlink("${PREFIX}$img");
4206	    &close_dbm_database if $DJGPP;
4207            print "Converting image #$new_num\n";
4208
4209	    if ( ($name =~ /figure/) || $psimage || $scale || $thumbnail) {
4210		$scale = $FIGURE_SCALE_FACTOR unless ($scale);
4211		print "\nFIGURE: $name scaled $scale  $aalias\n" if ($VERBOSITY > 2);
4212		(L2hos->syswait( "$PSTOIMG -type $IMAGE_TYPE "
4213		. ($DEBUG ? '-debug ' : '-quiet ' )
4214		. ($TMPDIR ? "-tmp $TMPDIR " : '' )
4215		. (($DISCARD_PS && !$thumbnail && !$psimage)? "-discard " :'')
4216		. (($INTERLACE) ? "-interlace " : '' )
4217		. (((($ANTI_ALIAS)||($aalias))&&($aalias !~ /no|text/))? "-antialias ":'')
4218		. (($ANTI_ALIAS_TEXT||(($aalias =~/text/)&&($aalias !~/no/)))?
4219			"-aaliastext ":'')
4220		. (($custom_size) ? "-geometry $custom_size ": '' )
4221		. $croparg
4222		. ($color_depth || '')
4223		. (($flip) ? "-flip $flip " : '' )
4224		. (($scale > 0) ? "-scale $scale " : '' )
4225		. (((($TRANSPARENT_FIGURES && ($env =~ /figure/o))||($trans))
4226		     &&(!($trans =~ /no/))) ? "-transparent " : '')
4227		. (($WHITE_BACKGROUND) ? "-white " : '' )
4228		. "-out ${PREFIX}$img $psname.ps"
4229		) ) # ||!(print "\nWriting image: ${PREFIX}$img"))
4230		    && print "\nError while converting image: $!\n";
4231
4232		if ($thumbnail) { # $thumbnail contains the reduction factor
4233		    L2hos->Unlink("${PREFIX}T$img");
4234		    print "\nIMAGE thumbnail: $name" if ($VERBOSITY > 2);
4235		    (L2hos->syswait( "$PSTOIMG -type $IMAGE_TYPE "
4236		    . ($DEBUG ? '-debug ' : '-quiet ' )
4237		    . ($TMPDIR ? "-tmp $TMPDIR " : '' )
4238		    . (($DISCARD_PS && !$psimage) ? "-discard " : '' )
4239		    . (($INTERLACE) ? "-interlace " : '' )
4240		    . ((($ANTI_ALIAS||($aalias))&&(!($aalias =~/no/)))? "-antialias " :'')
4241		    . (($ANTI_ALIAS_TEXT||(($aalias =~/text/)&&($aalias !~/no/)))?
4242			"-aaliastext ":'')
4243		    . (($custom_size) ? "-geometry $custom_size " : '' )
4244		    . ($color_depth || '')
4245		    . (($flip) ? "-flip $flip " : '' )
4246		    . (($thumbnail > 0) ? "-scale $thumbnail " : '' )
4247		    . ((($trans)&&(!($trans =~ /no/))) ? "-transparent " : '')
4248		    . (($WHITE_BACKGROUND) ? "-white " : '' )
4249		    . "-out ${PREFIX}T$img $psname.ps"
4250		    ) ) # ||!(print "\nWriting image: ${PREFIX}T$img"))
4251			&& print "\nError while converting thumbnail: $!\n";
4252		    $thumbnail = "${PREFIX}T$img";
4253		}
4254	    } elsif (($exscale &&(!$PK_GENERATION))&&($width{$name})) {
4255		my $under = '';
4256		my $mathscale = ($MATH_SCALE_FACTOR > 0) ? $MATH_SCALE_FACTOR : 1;
4257		if (($DISP_SCALE_FACTOR > 0) &&
4258		    ( $name =~ /equation|eqnarray|display/))
4259		        { $mathscale *= $DISP_SCALE_FACTOR; };
4260		if ($scale) {
4261		    $scale *= $exscale if ($name =~ /makeimage|tab/);
4262		} else {
4263		    $scale = $mathscale*$exscale;
4264		    $under = "d" if (($name =~/inline|indisplay/)&&($depth{$name}));
4265		}
4266		print "\nIMAGE: $name  scaled by $scale \n" if ($VERBOSITY > 2);
4267		(L2hos->syswait( "$PSTOIMG -type $IMAGE_TYPE "
4268		. ($DEBUG ? '-debug ' : '-quiet ' )
4269		. ($TMPDIR ? "-tmp $TMPDIR " : '' )
4270		. (($DISCARD_PS)? "-discard " : '' )
4271		. (($INTERLACE)? "-interlace " : '' )
4272		. ((($ANTI_ALIAS_TEXT||($aalias))&&($aalias !=~/no/))?
4273		    "-antialias -depth 1 " :'')
4274		. (($custom_size)? "-geometry $custom_size " : '' )
4275                . $croparg
4276		. (($scale != 1)? "-scale $scale " : '' )
4277		. ((($exscale)&&($exscale != 1)&&
4278		    !($ANTI_ALIAS_TEXT &&($LATEX_COLOR)))?
4279			"-shoreup $exscale$under " :'')
4280		. ((($TRANSPARENT_FIGURES ||($trans))
4281		     &&(!($trans =~ /no/)))? "-transparent " : '')
4282		. (($WHITE_BACKGROUND && !$TRANSPARENT_FIGURES) ? "-white " : '' )
4283		. "-out ${PREFIX}$img $psname.ps"
4284		) ) # ||!(print "\nWriting image: ${PREFIX}$img"))
4285		    && print "\nError while converting image: $!\n";
4286	    } else {
4287		print "\nIMAGE: $name\n" if ($VERBOSITY > 2);
4288		my $under = '';
4289		my $mathscale = ($MATH_SCALE_FACTOR > 0) ? $MATH_SCALE_FACTOR : 1;
4290		if (($DISP_SCALE_FACTOR > 0) &&
4291		    ( $name =~ /equation|eqnarray|display/))
4292		        { $mathscale *= $DISP_SCALE_FACTOR; };
4293		if (($scale)&&($exscale)) {
4294		    $scale *= $exscale if ($name =~ /makeimage|tab/);
4295		} elsif ($scale) {
4296		} elsif (($mathscale)&&($exscale)) {
4297		    $scale = $mathscale*$exscale;
4298		    $under = "d" if (($name =~/inline|indisplay/)&&($depth{$name}));
4299		} elsif ($mathscale) { $scale = $mathscale; }
4300
4301		(L2hos->syswait("$PSTOIMG -type $IMAGE_TYPE "
4302		. ($DEBUG ? '-debug ' : '-quiet ' )
4303		. ($TMPDIR ? "-tmp $TMPDIR " : '' )
4304		. (($DISCARD_PS) ? "-discard " : '' )
4305		. (($INTERLACE) ? "-interlace " : '' )
4306		. ((($ANTI_ALIAS_TEXT||($aalias))&&(!($aalias =~ /no/)))?
4307		    "-antialias -depth 1 " :'')
4308		. ((($exscale)&&($exscale != 1)&&
4309		    !($ANTI_ALIAS_TEXT &&($LATEX_COLOR)))?
4310			"-shoreup $exscale " :'')
4311		. (($scale ne 1) ? "-scale $scale " : '' )
4312		. (($custom_size) ? "-geometry $custom_size " : '' )
4313                . $croparg
4314#		.  (($name =~ /(equation|eqnarray)/) ? "-rightjustify $lwidth " : '')
4315#		.  (($name =~ /displaymath/) ? "-center $lwidth " : '')
4316		. (($name =~ /inline|indisplay/ && (!($custom_size))&&$depth{$name}!= 0) ?
4317		    do {$val=($height{$name}-$depth{$name})/($height{$name}+$depth{$name});
4318			"-topjustify x$val "} : '')
4319		. ((($TRANSPARENT_FIGURES||($trans))
4320		    &&(!($trans =~ /no/))) ? "-transparent " : '')
4321		. (($WHITE_BACKGROUND && !$TRANSPARENT_FIGURES) ? "-white " : '' )
4322		. "-out ${PREFIX}$img $psname.ps")
4323		) #|| !(print "\nWriting image: ${PREFIX}$img"))
4324		    && print "\nError while converting image\n";
4325	    }
4326	    if (! -r "${PREFIX}$img") {
4327		&write_warnings("\nFailed to convert image $psname.ps")
4328	    } else { } #L2hos->Unlink("$psname.ps") unless $DEBUG }
4329	    &open_dbm_database if $DJGPP;
4330	}
4331    }
4332    print "\nextracted $name as $page_num\n" if ($VERBOSITY > 1);
4333    &embed_image("${PREFIX}$img", $name, $external, $alt, $thumbnail, $map,
4334        $align, $usemap, $exscale, $exstr);
4335}
4336
4337sub extract_parameters {
4338    local($contents) = @_;
4339    local($_, $scale, $external, $thumbnail, $map, $psimage, $align,
4340	  $usemap, $flip, $aalias, $trans, $pagecolor, $alt, $exscale,
4341	  $cdepth, $htmlparams);
4342
4343    #remove the \htmlimage commands and arguments before...
4344    $contents =~ s/$htmlimage_rx/$_ = $2;''/ego;
4345    $contents =~ s/$htmlimage_pr_rx/$_ .= $2;''/ego;
4346
4347    # code adapted from original idea by Stephen Gildea:
4348    # If the document specifies the ALT tag explicitly
4349    # with \htmlimage{alt=some text} then use it.
4350    s!alt=([^,]+)!$alt = $1;
4351        $alt =~ s/^\s+|\s+$//g; $alt =~ s/"//g;
4352        $alt="ALT=\"$alt\"";
4353    ''!ie;
4354
4355  if (!$alt) {
4356    #...catching all the code for the ALT text.
4357    local($keep_gt)=1;
4358    $alt = &flatten_math($contents); undef $keep_gt;
4359    #RRM: too long strings upset the DBM. Truncate to <= 165 chars.
4360    if ( length($alt) > 163 ) {
4361	local($start,$end);
4362	$start = substr($alt,0,80);
4363	$end = substr($alt,length($alt)-80,80);
4364	$alt = join('',$start,"...\n ...",$end);
4365    }
4366    s/ALT\s*=\"([\w\W]*)\"/$alt=$1;''/ie;
4367    if ($alt) {
4368	if ($alt =~ /\#/) {
4369	    $alt =~ s/^(\\vbox\{)?\#[A-Za-z]*\s*//;
4370	    $alt =~ s/\n?\#[A-Za-z]*\s*\}?$//s;
4371	    if ($alt =~ /\#/) { $alt = $` . " ... " };
4372	}
4373	$alt =~ s/\`\`/\\lq\\lq /g; $alt =~ s/\`/\\lq /g;
4374	$alt =~ s/(^\s*|\s*$)//mg;
4375	$alt = "ALT=\"$alt\"" if ($alt);
4376    } else { $alt = 'ALT="image"' }
4377  }
4378
4379    $psimage++ if ($contents =~ /\.ps/);
4380#    $contents =~ s/\s//g;	# Remove spaces   Why ?
4381    s/extrascale=([\.\d]*)/$exscale=$1;''/ie;
4382    s/\bscale=([\.\d]*)/$scale=$1;''/ie;
4383    s/(^|,\s*)external/$external=1;''/ie;
4384    s/(^|,\s*)((no)?_?anti)alias(_?(text))?/$aalias = $2.$4;''/ie;
4385    s/(^|,\s*)((no)?_?trans)parent/$trans = $2;''/ie;
4386    s/thumbnail=([\.\d]*)/$thumbnail=$1;''/ie;
4387    s/usemap=([^\s,]+)/$usemap=$1;''/ie;
4388    s/map=([^\s,]+)/;$map=$1;''/ie;
4389    s/align=([^\s,]+)/$align=$1;''/ie;
4390    s/flip=([^\s,]+)/$flip=$1;''/ie;
4391    s/color_?(depth)?=([^\s,]+)/$cdepth=$2;''/ie;
4392    ($scale,$external,$thumbnail,$map,$psimage,$align
4393     ,$usemap,$flip,$aalias,$trans,$exscale,$alt,$_);
4394}
4395
4396
4397# RRM: Put the raw \TeX code into the ALT tag
4398# replacing artificial environments and awkward characters
4399sub flatten_math {
4400    local ($_) = @_;
4401    $_ = &revert_to_raw_tex($_);
4402    s/[ \t]+/ /g;
4403    # MRO: replaced $* with /m
4404    s/$tex2html_wrap_rx//gm;
4405    s/(\\begin\s*\{[^\}]*\})(\s*(\[[^]]*\]))?[ \t]*/$1$3/gm;
4406    s/(\\end\{[^\}]*\})\n?/$1/gm;
4407    s/>(\w)?/($1)?"\\gt $1":"\\gt"/eg unless ($keep_gt); # replace > by \gt
4408    s/\\\|(\w)?/($1)?"\\Vert $1":"\\Vert"/eg; 	# replace \| by \Vert
4409    s/\|(\w)?/($1)?"\\vert $1":"\\vert"/eg; 	# replace | by \vert
4410    s/\\\\/\\\\ /g; 	# insert space after \\
4411    s/\\"/\\uml /g;	# screen umlaut accents...
4412    s/"/\'\'/g;		# replace " by ''
4413    s/\\\#/\\char93 /g;	# replace \# by \char93 else caching fails
4414#    s/"(\w)?/($1)?"\\rq\\rq $1":"\'\'"/eg;	# replace " by \rq\rq
4415#    s/\&\\uml /\\\"/g;	# ...reinstate umlauts
4416    $_;
4417}
4418
4419sub scaled_image_size {
4420    local($exscale,$_) = @_;
4421    local($width,$height) = ('','');
4422    /WIDTH=\"?(\d*)\"?\s*HEIGHT=\"?(\d*)\"?$/o;
4423    $width=int($1/$exscale + .5);
4424    $height=int($2/$exscale + .5);
4425    "WIDTH=\"$width\" HEIGHT=\"$height\""
4426}
4427
4428sub process_in_latex {
4429    # This is just a wrapper for process_undefined_environment.
4430    # @[0] = contents
4431    $global{'max_id'}++;
4432    &process_undefined_environment('tex2html_wrap',$global{'max_id'},$_[0]);
4433}
4434
4435# MRO: cp deprecated, replaced by L2hos->Copy
4436
4437# Marcus Hennecke  6/3/96
4438# MRO: test for existance
4439sub copy_file {
4440    local($file, $ext) = @_;
4441    $file =  &fulltexpath("$FILE.$ext");
4442    if(-r $file) {
4443        print "\nNote: Copying '$file' for image generation\n"
4444            if($VERBOSITY > 2);
4445        L2hos->Copy($file, ".$dd${PREFIX}images.$ext");
4446    }
4447}
4448
4449sub rename_image_files {
4450    local($_, $old_name, $prefix);
4451    if ($PREFIX) {
4452	foreach (<${PREFIX}*img*.$IMAGE_TYPE>) {
4453	    $old_name = $_;
4454	    s/\.$IMAGE_TYPE$/\.old/o;
4455	    L2hos->Rename($old_name, $_);
4456	    }
4457	}
4458    else {
4459	foreach (<img*.$IMAGE_TYPE>) {
4460	    $old_name = $_;
4461	    s/\.$IMAGE_TYPE$/\.old/o;
4462	    L2hos->Rename($old_name, $_);
4463	}
4464	foreach (<Timg*.$IMAGE_TYPE>) {
4465	    $old_name = $_;
4466	    s/\.$IMAGE_TYPE$/\.old/o;
4467	    L2hos->Rename($old_name, $_);
4468	}
4469    }
4470}
4471
4472
4473############################ Processing Commands ##########################
4474
4475sub ignore_translate_commands {
4476    local ($_) = @_;
4477#   print "\nTranslating commands ...";
4478
4479    local(@processedC);
4480    &replace_strange_accents;
4481    local($before, $contents, $br_id, $after, $pattern, $end_cmd_rx);
4482    s/$begin_cmd_rx/&replace_macro_expansion($`, $1, $&, $')/eg;
4483}
4484
4485sub replace_macro_expansion {
4486    push(@processedC,$_[1]);
4487    $end_cmd_rx = &make_end_cmd_rx($_[2]);
4488    $pattern = $_[3];
4489    $_ = join('',$_[3],$_[4]);
4490    $after = $_[4];
4491    if (($before)&&(!($before =~ /$begin_cmd_rx/))) {
4492	push(@processedC,$before);
4493	    $_ = join('',$pattern,$after); $before = '';
4494	}
4495	local($end_cmd_rx) = &make_end_cmd_rx($br_id);
4496
4497}
4498
4499sub translate_aux_commands {
4500    s/^(.*)$/&translate_commands($1)/s;
4501}
4502
4503sub translate_commands {
4504    local ($_) = @_;
4505#   print "\nTranslating commands ...";
4506
4507    local(@processedC);
4508    &replace_strange_accents;
4509    for (;;) {			# For each opening bracket ...
4510	last unless ($_ =~ /$begin_cmd_rx/);
4511	local($before, $contents, $br_id, $after, $pattern);
4512	($before, $br_id, $after, $pattern) = ($`, $1, $', $&);
4513	if (($before)&&(!($before =~ /$begin_cmd_rx/))) {
4514	    push(@processedC,$before);
4515	    $_ = join('',$pattern,$after); $before = '';
4516	}
4517	local($end_cmd_rx) = &make_end_cmd_rx($br_id);
4518	if ($after =~ /$end_cmd_rx/) { # ... find the the matching closing one
4519	    $NESTING_LEVEL++;
4520	    ($contents, $after) = ($`, $');
4521	    do {
4522		local(@save_open_tags) = @$open_tags_R;
4523		local($open_tags_R) = [ @save_open_tags ];
4524		print STDOUT "\nIN::{$br_id}" if ($VERBOSITY > 4);
4525		print STDOUT "\n:$contents\n" if ($VERBOSITY > 7);
4526		undef $_;
4527		$contents = &translate_commands($contents)
4528		    if ($contents =~ /$match_br_rx/o);
4529                # Modifies $contents
4530		&process_command($single_cmd_rx,$contents)
4531		    if ($contents =~ /\\/o);
4532
4533		$contents .= &balance_tags();
4534	    };
4535
4536	    print STDOUT "\nOUT: {$br_id}" if ($VERBOSITY > 4);
4537	    print STDOUT "\n:$contents\n" if ($VERBOSITY > 7);
4538	    # THIS MARKS THE OPEN-CLOSE DELIMITERS AS PROCESSED
4539	    $_ = join("", $before,"$OP$br_id$CP", $contents,"$OP$br_id$CP", $after);
4540	    $NESTING_LEVEL--;
4541	}
4542	else {
4543	    $pattern = &escape_rx_chars($pattern);
4544	    s/$pattern//;
4545	    print "\nCannot find matching bracket for $br_id" unless $AUX_FILE;
4546	}
4547	last unless ($_ =~ /$begin_cmd_rx/o);
4548    }
4549    $_ = join('',@processedC) . $_;
4550    # Now do any top level commands that are not inside any brackets
4551    # MODIFIES $_
4552    print "$_\n" if ($VERBOSITY > 8);
4553    &process_command($single_cmd_rx,$_);
4554}
4555
4556#RRM: based on earlier work of Marcus Hennecke
4557# makes sure the $open_tags_R at the end of an environment
4558# is the same as @save_open_tags from the start,
4559# ensuring that the HTML page indeed has balanced tags
4560sub balance_tags {
4561    local($tag_cmd, $tags, $save_tags, $open_tags, @reopen_tags);
4562    $save_tags = join(',',@save_open_tags) if (@save_open_tags);
4563    $open_tags = join(',',@$open_tags_R) if (@$open_tags_R);
4564    if ($open_tags eq $save_tags) { return(); }
4565    if ($save_tags =~ s/^$open_tags//) {
4566	@reopen_tags = split (',',$');
4567    } else {
4568	@reopen_tags = @save_open_tags;
4569	while (@$open_tags_R) {
4570	    $tag_cmd = pop (@$open_tags_R);
4571	    print STDOUT "\n</$tag_cmd>" if $VERBOSITY > 2;
4572	    $declarations{$tag_cmd} =~ m|</.*$|;
4573	    $tags .= $& unless ($` =~ /^<>$/);
4574	    $open_tags = join(',',@$open_tags_R) if (@$open_tags_R);
4575	    last if ( $save_tags =~ s/^$open_tags/
4576		     @reopen_tags = split (',',$');''/e);
4577	}
4578    }
4579    while (@reopen_tags) {
4580	$tag_cmd = shift @reopen_tags;
4581	if ($tag_cmd) {
4582	    push (@$open_tags_R, $tag_cmd) if ($tag_cmd);
4583	    print STDOUT "\n<$tag_cmd>" if $VERBOSITY > 2;
4584	    $declarations{$tag_cmd} =~ m|</.*$|;
4585	    $tags .= $` unless ($` =~ /^<>$/);
4586	}
4587    }
4588    $tags;
4589}
4590
4591sub close_all_tags {
4592    return() if (!@$open_tags_R);
4593    local($tags,$tag_cmd);
4594    while (@$open_tags_R) {
4595	$tag_cmd = pop (@$open_tags_R);
4596	print STDOUT "\n</$tag_cmd>" if $VERBOSITY > 2;
4597	$declarations{$tag_cmd} =~ m|</.*$|;
4598	$tags .= $& unless ($` =~ /^<>$/);
4599    }
4600    $tags;
4601}
4602
4603sub preserve_open_tags {
4604    local(@save_open_tags) = @$open_tags_R;
4605    local($open_tags_R) = [ @save_open_tags ];
4606    # provides the markup to close and reopen the current tags
4607    (&close_all_tags(), &balance_tags());
4608}
4609
4610sub preserve_open_block_tags {
4611    local($tag_cmd,$tags_open,$tags_close,$pre,$post,@tags);
4612    while (@$open_tags_R) {
4613	$tag_cmd = pop (@$open_tags_R);
4614	print STDOUT "\n</$tag_cmd>" if $VERBOSITY > 2;
4615	$declarations{$tag_cmd} =~ m|</.*$|;
4616	($pre,$post) = ($`,$&);
4617	if ($post =~ /$block_close_rx/) {
4618	    # put it back and exit
4619	    push(@$open_tags_R,$tag_cmd);
4620	    last;
4621	} else {
4622	    # leave it closed, collecting tags for it
4623	    $tags_close .= $post;
4624	    $tags_open = $pre . $tags_open;
4625	    unshift(@tags,$tag_cmd);
4626	}
4627    }
4628    ($tags_close , $tags_open, @tags);
4629}
4630
4631sub minimize_open_tags {
4632    local($this_tag, $close_only) = @_;
4633    local($pre,$post,$decl);
4634    $decl = $declarations{$this_tag};
4635    if ($decl) {
4636    # if it is a declaration, get the corresponding tags...
4637	$decl =~ m|</.*$|;
4638	($pre,$post) = ($`,$&) unless ($` =~ /^<>$/);
4639	if (!@$open_tags_R) { # when nothing else is open...
4640            # pushing the style, when appropriate
4641	    push (@$open_tags_R, $this_tag)
4642		unless ($close_only ||($post =~ /$block_close_rx/));
4643	    print STDOUT "\n<$this_tag>" if $VERBOSITY > 2;
4644            # and return the tags
4645	    return($pre,$post) unless ($USING_STYLES);
4646	    local($env_id) = '' if ($env_id =~/^\w+$/);
4647	    $pre =~ s/>$/ $env_id>/ if ($env_id);
4648	    return($pre,$post);
4649	}
4650    } else { # ...else record the argument as $pre
4651	$pre = $this_tag unless $close_only;
4652    }
4653    local($env_id) = '' if ($env_id =~/^\w+$/);
4654    $pre =~ s/>$/ ID="$env_id">/ if ($USING_STYLES &&($env_id));
4655
4656    # return the tags, if nothing is already open
4657    if (!@$open_tags_R) {
4658	return($pre,$post);
4659    }
4660#    elsif ($close_only) { push (@$open_tags_R, $this_tag) }
4661
4662    local($tags,$tag_cmd,$tag_open);
4663    local($closures,$reopens,@tags);
4664    local($tag_close,$tag_open);
4665    local($size_cmd,$size_open);
4666    local($font_cmd,$font_open);
4667    local($fontwt_cmd,$fontwt_open);
4668    local($color_cmd,$color_open);
4669     if ($decl) {
4670	if ($this_tag =~ /$sizechange_rx/) {
4671	    $size_cmd = $this_tag;
4672	} else {
4673	    if ($this_tag =~ /$fontchange_rx/) {
4674	        $font_cmd = $this_tag }
4675	    if ($this_tag =~ /$fontweight_rx/) {
4676		$fontwt_cmd = $this_tag }
4677	}
4678    }
4679    while (@$open_tags_R) {
4680	($tag_close,$tag_open) = ('','');
4681	$tag_cmd = pop (@$open_tags_R);
4682	print STDOUT "\n</$tag_cmd>" if $VERBOSITY > 2;
4683	$declarations{$tag_cmd} =~ m|</.*$|;
4684	($tag_close,$tag_open) = ($&,$`) unless ($` =~ /<>/);
4685	$closures .= $tag_close;
4686
4687	if ((!$size_cmd)&&($tag_cmd =~ /$sizechange_rx/)) {
4688	    $size_cmd = $tag_cmd;
4689	    $size_open = $tag_open;
4690	}
4691	elsif ((!$font_cmd)&&($tag_cmd =~ /$fontchange_rx/)) {
4692	    $font_cmd = $tag_cmd;
4693	    $font_open = $tag_open;
4694	}
4695	elsif ((!$fontwt_cmd)&&($tag_cmd =~ /$fontweight_rx/)) {
4696	    $fontwt_cmd = $tag_cmd;
4697	    $fontwt_open = $tag_open;
4698	}
4699	elsif ((!$color_cmd)&&($tag_cmd =~ /$colorchange_rx/)) {
4700	    $color_cmd = $tag_cmd;
4701	    $color_open = $tag_open;
4702	}
4703	elsif ($tag_cmd =~
4704	     /$sizechange_rx|$fontchange_rx|$fontweight_rx|$colorchange_rx/) {
4705	} else {
4706	    unshift (@tags, $tag_cmd);
4707	    print STDOUT "\n<<$tag_cmd>" if $VERBOSITY > 2;
4708	    $reopens = $tag_open . $reopens;
4709	}
4710    }
4711    if ($USING_STYLES) {
4712	local($TAG) = "DIV";
4713	if ($pre =~ /^<(DIV|SPAN|PRE)/) { $TAG = $1 };
4714	if (($pre =~ /^<$TAG/)&&($env_id =~ /^\s+(CLASS|ID)/)) {
4715	    $pre =~ s/<$TAG/<$TAG$env_id/;
4716	} elsif ($pre =~ /<P>/) {
4717	    $TAG = 'P';
4718	} else {
4719	}
4720#	$post .= "</$TAG>";
4721    }
4722    push (@$open_tags_R, @tags);
4723    $tags .= $pre if ($pre && $post =~ /$block_close_rx/);
4724    if ($font_cmd && !($font_cmd eq $this_tag)) {
4725	push (@$open_tags_R,$font_cmd);
4726	print STDOUT "\n<$font_cmd>" if $VERBOSITY > 2;
4727	$tags .= $font_open;
4728    }
4729    if ($fontwt_cmd && !($fontwt_cmd eq $this_tag)) {
4730	push (@$open_tags_R,$fontwt_cmd);
4731	print STDOUT "\n<$fontwt_cmd>" if $VERBOSITY > 2;
4732	$tags .= $fontwt_open;
4733    }
4734    if ($size_cmd && !($size_cmd eq $this_tag)) {
4735	push (@$open_tags_R,$size_cmd);
4736	print STDOUT "\n<$size_cmd>" if $VERBOSITY > 2;
4737	$tags .= $size_open;
4738    }
4739    if ($color_cmd && !($color_cmd eq $this_tag)) {
4740	push (@$open_tags_R,$color_cmd);
4741	print STDOUT "\n<$color_cmd>" if $VERBOSITY > 2;
4742	$tags .= $color_open;
4743    }
4744    $tags .= $pre unless ($pre && $post =~ /$block_close_rx/);
4745    push (@$open_tags_R, $this_tag)
4746	if ($decl &&!($post =~ /$block_close_rx|$all_close_rx/));
4747    print STDOUT "\n<$this_tag>" if $VERBOSITY > 2;
4748    ($closures.$reopens.$tags , $post );
4749}
4750
4751
4752sub declared_env {
4753    local($decl, $_, $deferred) = @_;
4754    local($after_cell,$pre,$post);
4755    local($decls) = $declarations{$decl};
4756    $decls =~ m|</.*$|;
4757    ($pre,$post) = ($`,$&);
4758    if ($USING_STYLES) {
4759	$env_style{$decl} = " " unless ($env_style{$decl});
4760	$pre =~ s/>$/$env_id>/ if ($env_id);
4761    }
4762    local($closing_tag) = 1 if ($pre =~ /^<>$/);
4763    $pre = $post = '' if $closing_tag;
4764    local($closures,$reopens);
4765
4766    local(@save_open_tags) = @$open_tags_R
4767	unless ($closing_tag || $deferred);
4768    local($open_tags_R) = [ @save_open_tags ]
4769	unless ($closing_tag || $deferred );
4770
4771    if ($post =~ /$block_close_rx/) {
4772	local($last_tag) = pop (@$open_tags_R);
4773	local($ldecl) = $declarations{$last_tag};
4774	if ($ldecl =~ m|</.*$|) { $ldecl = $& }
4775	if (($last_tag)&&!($ldecl =~ /$block_close_rx/)) {
4776	    # need to close tags, for re-opening inside
4777	    push (@$open_tags_R, $last_tag);
4778	    ($closures,$reopens) = &preserve_open_tags();
4779	    $pre = join('', $closures, "\n", $pre, $reopens);
4780	    $post = join('', $closures, $post, $reopens);
4781	} elsif ($last_tag) {
4782	    $pre = "\n".$pre;
4783	    push (@$open_tags_R, $last_tag);
4784	    undef $ldecl;
4785	} else {
4786	}
4787
4788	if ($deferred) {
4789	    if (defined $ldecl) {
4790		print STDOUT "\n<<$decl>" if $VERBOSITY > 2;
4791		unshift(@$open_tags_R, $decl);
4792	    } else {
4793		print STDOUT "\n<$decl>" if $VERBOSITY > 2;
4794		push(@$open_tags_R, $decl);
4795	    }
4796	    return ( $pre . $_ );
4797	} else {
4798	    if (defined $ldecl) {
4799		print STDOUT "\n<<$decl>" if $VERBOSITY > 2;
4800		unshift(@$open_tags_R, $decl);
4801	    } else {
4802		print STDOUT "\n<$decl>" if $VERBOSITY > 2;
4803		push(@$open_tags_R, $decl);
4804	    }
4805	}
4806    } elsif ($post =~/$all_close_rx/) {
4807	($closures,$reopens) = &preserve_open_tags();
4808	($pre,$post) = &minimize_open_tags($decl,1);
4809	$pre = join('', $closures, $pre);
4810    } elsif ($closing_tag) {
4811	$prev_open = $pre;
4812	($pre,$post) = &minimize_open_tags($decl,1);
4813	$pre =~ s/<\/?>//g; $post =~ s/<\/?>//;
4814    } else {
4815	($pre,$post) = &minimize_open_tags($decl);
4816    }
4817    $_ =~ s/^\s+//s; #RRM:28/4/99 remove spaces at the beginning
4818    $_ = &translate_environments($_);
4819    $_ = &translate_commands($_) if (/\\/);
4820    if ($post =~ /$block_close_rx/) {
4821	s/^\n?/\n/o;
4822	if (defined $ldecl) {
4823	    $post = &close_all_tags();
4824	} else {
4825	    $post = "\n";
4826	}
4827    } elsif ($post =~/$all_close_rx/) {
4828    } else { $post = '' };
4829
4830    join('', $pre, $_, $post
4831	   , ($closing_tag ? '' : &balance_tags()) );
4832}
4833
4834sub do_cmd_centering{&declared_env('center',$_[0],$tex2html_deferred)}
4835sub do_cmd_raggedright{&declared_env('flushleft',$_[0],$tex2html_deferred)}
4836sub do_cmd_raggedleft{&declared_env('flushright',$_[0],$tex2html_deferred)}
4837
4838sub do_env_verse { &declared_env('verse',@_) }
4839sub do_env_center { &declared_env('center',@_) }
4840sub do_env_quote { &declared_env('quote', @_) }
4841sub do_env_quotation { &declared_env('quote', @_) }
4842sub do_env_tex2html_preform { &declared_env('preform', @_) }
4843sub do_env_tex2html_ord { &declared_env('ord', @_) }
4844sub do_env_tex2html_unord { &declared_env('unord', @_) }
4845sub do_env_tex2html_desc { &declared_env('desc', @_) }
4846
4847
4848# Modifies $contents
4849sub process_command {
4850    # MRO: modified to use $_[1]
4851    # local ($cmd_rx, *ref_contents) = @_;
4852    local ($cmd_rx) = @_;
4853    local($ref_before, $cmd , $pc_after);
4854    local($cmd_sub, $cmd_msub, $cmd_trans, $mathentity);
4855    local (@open_font_tags,@open_size_tags);
4856    $_[1] = &convert_iso_latin_chars($_[1])
4857	unless (($cmd =~ /(Make)?([Uu]pp|[Ll]ow)ercase/)||
4858	    ((!$cmd)&&($_[1] =~ /^\\(Make)?([Uu]pp|[Ll]ow)ercase/s)));
4859
4860    local(@ref_processed);
4861    for (;;) {			# Do NOT use the o option
4862	last unless ($_[1] =~ /$cmd_rx/ );
4863	print ".";
4864	#JCL(jcl-del) - use new regexp form which handles white space
4865	($ref_before, $cmd, $pc_after) = ($`, $1.$2, $4.$');
4866	push(@ref_processed,$ref_before);
4867#print "\nAFTER:$1.$2:".$4."\n" if ($cmd_rx eq $single_cmd_rx);
4868	print STDOUT "$cmd" if ($VERBOSITY > 2);
4869	print STDOUT "\nIN: $_[1]\n" if ($VERBOSITY > 6);
4870	#
4871	if ( $cmd = &normalize($cmd,$pc_after) ) {
4872	    print "PCT: process_command: cmd: $cmd\n" if ($VERBOSITY > 10) ;
4873	    ($cmd_sub, $cmd_msub, $cmd_trans, $mathentity) =
4874		("do_cmd_$cmd", "do_math_cmd_$cmd"
4875		, $declarations{$cmd}, $mathentities{$cmd});
4876	    if ($new_command{$cmd}||$renew_command{$cmd}) {
4877                # e.g. some \the$counter
4878		local($argn, $body, $opt) = split(/:!:/, $new_command{$cmd});
4879		&make_unique($body) if ($body =~ /$O/);
4880		if ($argn) {
4881		    do {
4882			local($before) = '';
4883			local($_) = "\\$cmd ".$pc_after;
4884			# &substitute_newcmd  may need what comes after the $cmd
4885			# from the value of $after
4886			#RRM: maybe best to pass it as a parameter ?
4887			my $keep_after = $after;
4888			$after = $pc_after;
4889			$pc_after = &substitute_newcmd;   # may change $after
4890			$pc_after =~ s/\\\@#\@\@/\\/o ;
4891			$pc_after .= $after;
4892			$after = $keep_after;
4893		    }
4894		} else {
4895		    $pc_after = $body . $pc_after;
4896		}
4897	    } elsif (defined &$cmd_sub) {
4898		# $ref_before may also be modified ...
4899		if ($cmd =~ /$sizechange_rx/o) {
4900		    $pc_after = &$cmd_sub($pc_after, $open_tags_R);
4901		} else {
4902		    $pc_after = &$cmd_sub($pc_after, $open_tags_R);
4903		};
4904	    } elsif ((defined &$cmd_msub)&&!$NO_SIMPLE_MATH) {
4905#print "\nMCMD:$cmd_msub :  ";
4906		# $ref_before may also be modified ...
4907		$pc_after = &$cmd_msub($pc_after, $open_tags_R);
4908		if ( !$math_mode ) {
4909		    $pc_after = "<MATH>" . $pc_after . "</MATH>";
4910		    ++$commands_outside_math{$cmd};
4911		};
4912	    } elsif ($cmd_trans) { # One to one transform
4913#print "\nCMD-DECL: $inside_tabular : $cmd_trans". join(',',@$open_tags_R);
4914		if ($inside_tabular) {
4915		    push (@ref_processed , "\\$cmd ")
4916		} else {
4917		    $cmd_trans =~ m|</.*$|;
4918		    $pc_after = $` . $pc_after unless ($` =~ /^<>/);
4919		    push(@$open_tags_R, $cmd)
4920			if ($cmd =~ /$fontchange_rx|$fontweight_rx|$sizechange_rx/o);
4921		}
4922	    } elsif ($mathentity) {
4923#print "\nM-ENT:$mathentity :  ";
4924		if ( $math_mode ) {
4925		    $pc_after = "&$mathentity#$cmd;" . $pc_after;
4926		} elsif ($NO_SIMPLE_MATH) {
4927		    $pc_after = "&$mathentity#$cmd;" . $pc_after;
4928#		    ++$commands_outside_math{$cmd};
4929		} else {
4930		    $pc_after = "<MATH>&$mathentity#$cmd;</MATH>" . $pc_after;
4931		    ++$commands_outside_math{$cmd};
4932		}
4933	    } elsif ($ignore{$cmd}) { # Ignored command
4934		print "\nignoring \\$cmd" if $VERBOSITY > 5;
4935		$pc_after = join('', " ", $pc_after) if ($cmd eq " "); # catches `\ '
4936		$pc_after = join(''," ", $pc_after)
4937		    if (($cmd eq ',')&&($pc_after =~ /^\-/s)&&($ref_before =~/\-$/s));
4938	    } elsif ($cmd =~ /^the(.+)$/){
4939		$counter = $1;
4940		local($tmp)="do_cmd_$cmd";
4941		if (defined &$tmp) { # Counter
4942		    $pc_after = &do_cmd_thecounter($pc_after);
4943		} else {
4944		    if (defined $failed) {
4945			$failed = 1;
4946#			$ref_before .= "$cmd";
4947			push(@ref_processed,$cmd);  # $ref_before .= "$cmd";
4948		    }
4949		    else {
4950			print "PCT: process_command: before unknow command (a) with $_\n" if ($VERBOSITY > 10) ;
4951			&declare_unknown_cmd($cmd) ;
4952		    }
4953#		    $ref_before .= "$cmd" if ($failed);
4954		}
4955	    } elsif ($cmd eq "\n") { push(@ref_processed," ");  # $ref_before .= " ";
4956	    } else {
4957		# Do not add if reading an auxiliary file
4958		if (defined $failed) {
4959		    $failed = 1;
4960		}
4961		else {
4962		    print "PCT: process_command: before unknow command (b) with $_\n" if ($VERBOSITY > 10) ;
4963		    &declare_unknown_cmd($cmd) ;
4964		}
4965	    }
4966	} else {
4967	    # &normalize should have already handled it adequately
4968	    # '\ ' (space) gets thru to here. Perhaps some others too ?
4969#	    print "\n ?? This should not happen: \\$cmd ??\n";
4970	}
4971#	$_[1] = join('', $ref_before, $pc_after);
4972	$_[1] = $pc_after;
4973	print STDOUT "\n-> $ref_before\n" if ($VERBOSITY > 6);
4974    }
4975    $_[1] = join('',@ref_processed).$_[1];
4976}
4977
4978sub declare_unknown_cmd {
4979    local($this_cmd) = @_;
4980    local($tmp) = "wrap_cmd_$cmd";
4981    do { ++$unknown_commands{$cmd};
4982	print STDOUT "\n*** Unknown command[1]: \\$cmd *** \n"
4983	    if ($VERBOSITY > 2);
4984    } unless ($AUX_FILE||(defined &$tmp)||($image_switch_rx=~/\b\Q$cmd\E\b/));
4985}
4986
4987
4988# This makes images from the code for math-entities,
4989# when $NO_SIMPLE_MATH is set and the  math  extension is loaded.
4990#
4991sub replace_math_constructions {
4992    local($math_mode) = @_;
4993    &make_math_box_images($math_mode) if (/<BOX>/);
4994    &make_math_entity_images($math_mode) if (/\&\w+#\w+;/);
4995}
4996
4997sub make_math_box_images {
4998    local($math_mode) = @_;
4999    local($pre,$this,$post,$tmp) = ('','','');
5000    local($slevel,$blevel) = 0;
5001
5002    while (/<BOX>/) {
5003	$pre .= $`; $tmp = $`; $this = ''; $post = $';
5004	# compute the super/sub-scripting level for each entity
5005	$tmp =~ s/<(\/?)SU[BP]>/
5006	    if ($1) { $slevel--} else { $slevel++};''/eog;
5007
5008	$tmp = $post;
5009	if ($tmp =~ /<(\/?)BOX>/o ) {
5010	    if ($1) { $this = $`; $post = $' }
5011	    else { $failed = 1 } # nested box, too complicated !
5012	} else {
5013	    &write_warnings("\nLost end of a <BOX> ?");
5014	    $failed = 1;
5015	}
5016	last if ($failed);
5017
5018	($this,$_) = &process_box_in_latex(
5019		    $math_mode, $slevel, $this, $post);
5020	$_ =~ s/^\s*//; # remove any leading spaces
5021	$pre .= $this ."\001";
5022    }
5023    return  if ($failed);
5024    $_ = $pre . $_;
5025}
5026
5027sub make_math_entity_images {
5028    local($math_mode) = @_;
5029    local($pre,$this,$post,$tmp) = ('','','');
5030    local($slevel) = 0;
5031    # compute the super/sub-scripting level for each entity
5032    while (/\&\w+#(\w+);/) {
5033	$pre .= $`; $tmp = $`; $this = $1; $post = $';
5034	$tmp =~ s/<(\/?)SU[BP]>/
5035	    if ($1) { $slevel--} else { $slevel++};''/eog;
5036	($this,$_) = &process_entity_in_latex(
5037		$math_mode, $slevel, $this, $post);
5038	$_ =~ s/^\s*//; # remove any leading spaces
5039	$pre .= $this ."\001";
5040    }
5041    $_ = $pre . $_;
5042}
5043
5044
5045#RRM:  Revert a math-entity to create image using LaTeX, together with
5046# any super/sub-scripts (possibly nested or with \limits ).
5047# Must also get the correct  \display/text/(script)script  style.
5048#
5049sub process_entity_in_latex {
5050    local($mode,$level,$entity,$after) = @_;
5051    local($math_style,$supsub,$rest) = ('','','');
5052    $level++ if ($mode =~/box/); # for top/bottom of inline fractions, etc.
5053
5054    if ($level) {
5055	$math_style = "\\". (($level > 1) ? "script" : "")."scriptstyle"
5056    } else {
5057	$math_style = "\\displaystyle" unless ($mode =~ /inline/);
5058    }
5059    while ($after =~ s/^\s*((\\limits|\&limits;)?\s*<SU(P|B)>)\s*/$supsub .= $1;''/eo) {
5060	local($slevel) = 1;
5061	local($aftersupb) = '';
5062	while ($slevel) {
5063	    $after =~ s/(<(\/)SU(B|P)>)/($2)? $slevel-- : $slevel++;''/oe;
5064	    $supsub .= $`.$&;
5065	    $aftersupb = $';
5066	}
5067	$after = $aftersupb;
5068    }
5069
5070    local($latex_code) = "\$$math_style\\$entity$supsub\$";
5071
5072    $global{'max_id'}++;
5073    ( &process_undefined_environment('tex2html_wrap_inline'
5074	     ,$global{'max_id'}, $latex_code ) , $after);
5075}
5076
5077sub process_box_in_latex {
5078    local($mode,$level,$inside,$after) = @_;
5079    local($math_style,$which,$pre,$post,$tmp) = ('','',"\{","\}");
5080
5081    if ($level) {
5082	$math_style = "\\". (($level > 1) ? "script" : "")."scriptstyle"
5083    } else {
5084	$math_style = "\\displaystyle" unless ($mode =~ /inline/);
5085    }
5086
5087    if ($inside =~ /<((LEFT)|(RIGHT))>/ ) {
5088	$pre = "\\left"; $post = "\\right";
5089	if ($2) {
5090	    $tmp = $`; $inside = $';
5091	    $pre .= (($tmp) ? $tmp : ".") . "\{";
5092	    if ( $inside =~ /<RIGHT>/ ) {
5093		$tmp = $';
5094		$inside = $`;
5095		$post = "\}". (($tmp) ? $tmp : ".");
5096	    }
5097	} else {
5098	    $pre .= ".\{"; $tmp = $'; $inside = $`;
5099	    $post = "\}". (($tmp) ? $tmp : ".");
5100	}
5101    }
5102    if ( $inside =~ /<((OVER)|(ATOP)|(CHOOSE))>/ ) {
5103	$pre .= $`;
5104	$post = $' . $post ;
5105	if ($2) { $which = "over " }
5106	elsif ($3) { $which = "atop " }
5107	elsif ($4) { $which = "atopwithdelims\(\)" }
5108    }
5109
5110    local($latex_code) = join('', "\$" , $math_style , " ", $pre
5111	  , (($which)? "\\$which" : "") , $post , "\$" );
5112
5113    if ($after =~ s/<SUP ALIGN=\"CENTER\">([^<]*)<\/SUP>/
5114	$tmp =$1;''/eo ) {
5115	$latex_code = join('', "\\stackrel" , $latex_code
5116			   , "\{" , $tmp , "\}" );
5117    }
5118
5119    $global{'max_id'}++;
5120    ( &process_undefined_environment('tex2html_wrap_inline'
5121	     ,$global{'max_id'}, $latex_code ) , $after);
5122}
5123
5124####################### Processing Meta Commands ############################
5125# This is a specialised version of process_command above.
5126# The special commands (newcommand, newenvironment etc.)
5127# must be processed before translating their arguments,
5128# and before we cut up the document into sections
5129# (there might be sectioning commands in the new definitions etc.).
5130# \newtheorem commands are treated during normal processing by
5131# generating code for the environments they define.
5132
5133sub substitute_meta_cmds {
5134    local ($next_def);
5135    local ($cmd, $arg, $argn, $opt, $body, $before, $xafter);
5136    local ($new_cmd_no_delim_rx, $new_cmd_rx, $new_env_rx, $new_cmd_or_env_rx);
5137    local ($new_end_env_rx);
5138    &tokenize($meta_cmd_rx);	#JCL(jcl-del) - put delimiter after meta command
5139    print "\nProcessing macros ..." if (%new_command || %new_environment);
5140    # First complete any replacement left-over from the previous part.
5141    if ($UNFINISHED_ENV) {
5142	s/$UNFINISHED_ENV/$REPLACE_END_ENV/;
5143	$UNFINISHED_ENV = '';
5144	$REPLACE_END_ENV = '';
5145    }
5146
5147    local(@processed);
5148    local($processed, $before, $after)=('', '', $_);
5149    while ($after =~ /$meta_cmd_rx$EOL/o) {	# ... and uses the delimiter
5150	($cmd, $after) = ($1.$2, $');
5151	$before .= $`;
5152#	$next_def = '';
5153	if (!($before =~ /$meta_cmd_rx$EOL/)) {
5154	    push(@processed, $before); $before = '';
5155	}
5156
5157	print ",";
5158#	$next_def = "\\$cmd" unless (($cmd =~ /renewcommand/));
5159	local($cmd_sub) = "get_body_$cmd";
5160	if (defined &$cmd_sub) {
5161#	    $processed = &$cmd_sub(*after);
5162	    $processed = &$cmd_sub(\$after);
5163#	    if ($processed) { $after = $before . $processed; }
5164#	    $next_def = ''
5165#		if (($PREAMBLE > 1)&&($cmd =~ /(re)?newcommand/));
5166#	    &add_to_preamble($cmd, $next_def)
5167#		unless ($next_def =~ /^\s*$/);
5168### new style of handling meta-commands
5169	    if ($processed) { push(@processed, "\\".$processed) }
5170	}
5171	elsif ($before) {
5172	    # this shouldn't happen !!
5173	    print STDERR "\nCannot handle \\$cmd , since there is no $cmd_sub ";
5174	    $after = $before . $cmd . $after;
5175	    $before = '';
5176	} else {
5177	    push(@processed, "\\$cmd ") if $cmd;
5178	}
5179    }
5180    print "\nmeta-commands: ". (0+@processed) ." found "
5181	if ((@processed)&&($VERBOSITY > 1));
5182    $_ = join('',@processed, $after); undef @processed;
5183    if ($PREAMBLE) {
5184	# MRO: replaced $* with /m
5185        s/((\n$comment_mark\d*)+\n)//gm;
5186        s/(\\par\b\s*\n?)+/\\par\n/gm;
5187        s/(\\par\b\n?)+/\\par\n/gm;
5188    }
5189
5190    # hard-code the new-command replacements for these
5191    $new_command{'begingroup'} = "0:!:\\begin<<0>>tex2html_begingroup<<0>>:!:}";
5192    $new_command{'endgroup'} = "0:!:\\end<<0>>tex2html_begingroup<<0>>:!:}";
5193    $new_command{'bgroup'} = "0:!:\\begin<<0>>tex2html_bgroup<<0>>:!:}";
5194    $new_command{'egroup'} = "0:!:\\end<<0>>tex2html_bgroup<<0>>:!:}";
5195
5196    # All the definitions have now moved to the $preamble and their bodies
5197    # are stored in %new_command and %new_environment
5198    #
5199    # Now substitute the new commands and environments:
5200    # (must do them all together because of cross definitions)
5201    $new_cmd_rx = &make_new_cmd_rx(keys %new_command);
5202    $new_cmd_no_delim_rx = &make_new_cmd_no_delim_rx(keys %new_command);
5203    $new_env_rx = &make_new_env_rx;
5204    $new_end_env_rx = &make_new_end_env_rx;
5205#    $new_cnt_rx = &make_new_cnt_rx(keys %new_counter);
5206    $new_cmd_or_env_rx = join("|", $new_cmd_no_delim_rx." ", $new_env_rx);
5207#    $new_cmd_or_env_rx = join("|", $new_cmd_no_delim_rx." ", $new_env_rx, " ".$new_cnt_rx);
5208    $new_cmd_or_env_rx =~ s/^ \||\|$//;
5209
5210    print STDOUT "\nnew commands:\n" if ($VERBOSITY > 2);
5211    while (($cmd, $body) = each %new_command) {
5212	unless ($expanded{"CMD$cmd"}++) {
5213	    print STDOUT ".$cmd " if ($VERBOSITY > 2);
5214	    $new_command{$cmd} = &expand_body;
5215	    print STDOUT " ".$new_command{$cmd}."\n" if ($VERBOSITY > 4);
5216	    &write_mydb("new_command", $cmd, $new_command{$cmd});
5217	}
5218    }
5219
5220    print STDOUT "\nnew environments:\n" if ($VERBOSITY > 2);
5221    while (($cmd, $body) = each %new_environment) {
5222	unless ($expanded{"ENV$cmd"}++) {
5223	    print STDOUT ".$cmd" if ($VERBOSITY > 2);
5224	    $new_environment{$cmd} = &expand_body;
5225	    &write_mydb("new_environment", $cmd, $new_environment{$cmd});
5226	}
5227    }
5228
5229    print STDOUT "\nnew counters and dependencies:\n" if ($VERBOSITY > 2);
5230    &clear_mydb("dependent") if ($DEBUG);     #avoids appending to a previous version
5231    while (($cmd, $body) = each %dependent) {
5232	print STDOUT ".($cmd,$body)" if ($VERBOSITY > 2);
5233        &write_mydb("dependent", $cmd, $dependent{$cmd});
5234    }
5235    &clear_mydb("img_style") if ($DEBUG);     #avoids appending to a previous version
5236    while (($cmd, $body) = each %img_style) {
5237        &write_mydb("img_style", $cmd, $img_style{$cmd});
5238    }
5239
5240    &clear_mydb("depends_on") if ($DEBUG);     #avoids appending to a previous version
5241    while (($cmd, $body) = each %depends_on) {
5242	print STDOUT ".($cmd,$body)" if ($VERBOSITY > 2);
5243        &write_mydb("depends_on", $cmd, $depends_on{$cmd});
5244    }
5245
5246
5247    &clear_mydb("styleID") if ($DEBUG);     #avoids appending to a previous version
5248    while (($cmd, $body) = each %styleID) {
5249        &write_mydb("styleID", $cmd, $styleID{$cmd});
5250    }
5251
5252    &clear_mydb("env_style") if ($DEBUG);     #avoids appending to a previous version
5253    while (($cmd, $body) = each %env_style) {
5254        &write_mydb("env_style", $cmd, $env_style{$cmd});
5255    }
5256    &clear_mydb("txt_style") if ($DEBUG);     #avoids appending to a previous version
5257    while (($cmd, $body) = each %txt_style) {
5258        &write_mydb("txt_style", $cmd, $txt_style{$cmd});
5259    }
5260
5261    print STDOUT "\ntheorem counters:\n" if ($VERBOSITY > 2);
5262    &clear_mydb("new_theorem") if ($DEBUG);     #avoids appending to a previous version
5263    while (($cmd, $body) = each %new_theorem) {
5264	print STDOUT ".($cmd,$body)" if ($VERBOSITY > 2);
5265        &write_mydb("new_theorem", $cmd, $new_theorem{$cmd});
5266    }
5267
5268
5269    print "+";
5270    if (length($new_env_rx)) {
5271	local(@pieces);
5272        print STDOUT "\nsubstituting new environments: $new_env_rx\n" if ($VERBOSITY > 3);
5273#	while (/\n?$new_env_rx/ && (($before, $cmd, $after) = ($`, $2, $'))) {
5274	while (/$new_env_rx/ && (($before, $cmd, $after) = ($`, $2, $'))) {
5275	    print STDOUT ",";
5276	    print STDOUT "{$cmd}" if ($VERBOSITY > 1);
5277	    if (!($before =~ /$new_env_rx/)) {
5278		push (@pieces, $before); $before = ''; print "{}";
5279	    }
5280	    $_ = join('',$before, &substitute_newenv);
5281	}
5282	print "\n ".(0+@pieces). " new environments replaced\n" if (@pieces);
5283	$_ = join('', @pieces, $_); undef @pieces;
5284    }
5285
5286
5287    print "+";
5288    if (length($new_cmd_rx)) {
5289	print STDOUT "\ntokenizing: $new_cmd_rx\n" if ($VERBOSITY > 2);
5290	&tokenize($new_cmd_rx); # Put delimiter after the new commands
5291
5292	# and use the delimiter.
5293	print STDOUT "\nsubstituting new commands: $new_cmd_rx\n" if ($VERBOSITY > 2);
5294	print STDOUT "\ninitial size: ".length($after) if ($VERBOSITY > 1);
5295	# store processed pieces in an array
5296	local($this_cmd, @pieces);
5297	# speed-up processing of long files by splitting into smaller segments
5298	# but don't split within the preamble, else \newenvironment may break
5299	local($pre_segment,@segments); &make_sections_rx;
5300	local($within_preamble,$this_section) = 1 if ($PREAMBLE>1);
5301	while (/$sections_rx/) {
5302	    $pre_segment .= $`; $_ = $'; $this_section = $&;
5303	    do {
5304		push(@segments,$pre_segment);
5305		$pre_segment = '';
5306	    } unless ($within_preamble);
5307	    $within_preamble = 0 if ($within_preamble && ($pre_segment =~
5308		    /\\(startdocument|begin\s*($O\d+${C})\s*document\s*\2)/));
5309	    $pre_segment .= $this_section;
5310	}
5311	push(@segments,$pre_segment.$_);
5312	local($replacements,$seg) ; $before = ''; # count the segments
5313	local($within_preamble) = 1 if ($PREAMBLE>1);
5314	foreach $after (@segments) {
5315	  while ($after =~ /(\\(expandafter|noexpand)\b\s*)?$new_cmd_no_delim_rx\b\s?/) {
5316	    ($before, $xafter, $cmd, $after) = ($`, $2, $3, $');
5317	    $within_preamble = 0
5318		if ($before =~ /\\(startdocument|begin\s*($O\d+${C})\s*document\s*\2)/);
5319	    push(@pieces, $before);
5320	    print "."; ++$replacements;
5321	    print STDOUT "$cmd" if ($VERBOSITY > 2);
5322	    if ($xafter =~ /no/) { $this_cmd = "\\\@#\@\@".$cmd  }
5323	    elsif (($xafter =~ /after/)&&($after =~ /^\s*\\/)) {
5324		local($delayed) = $cmd;
5325		local($nextcmd);
5326		$after =~ s/^\s*\\([a-zA-Z]+|.)/$nextcmd = $1;''/eo;
5327		($cmd,$nextcmd) = ($nextcmd, "do_cmd_$nextcmd");
5328		if (defined &$nextcmd) { $after = &$nextcmd($after); }
5329		elsif ($new_command{$cmd}) {
5330		    local($argn, $body, $opt) = split(/:!:/, $new_command{$cmd});
5331		    &make_unique($body) if ($body =~ /$O/);
5332		    if ($argn) {
5333			do {
5334			    local($before) = '';
5335			    $after = join('',&substitute_newcmd, $after);
5336			    $after =~ s/\\\@#\@\@/\\/o ;
5337			};
5338		    } else { $after = $body . $after; }
5339		} else { print "\nUNKNOWN COMMAND: $cmd "; }
5340		$cmd = $delayed;
5341		if ($new_command{$cmd}) {
5342		    if ($renew_command{$cmd}) {
5343#			# must wrap it in a deferred environment
5344#			$this_cmd = join('', &make_deferred_wrapper(1)
5345#				,"\\$cmd".(($cmd =~ /\w$/)? " ":'')
5346#				, &make_deferred_wrapper(0));
5347#			push(@pieces, $this_cmd); $this_cmd = '';
5348			push(@pieces, "\\$cmd".(($cmd =~ /\w$/)? " ":''));
5349			$this_cmd = '';
5350		    } elsif ($provide_command{$cmd}&&$within_preamble) {
5351			# leave it alone
5352			push(@pieces, "\\$cmd".(($cmd =~ /\w$/)? " ":''));
5353			$this_cmd = '';
5354		    } else {
5355			# do the substitution
5356			$this_cmd = &substitute_newcmd;
5357		    }
5358		}
5359	    } elsif ($renew_command{$cmd}) {
5360		# leave it alone
5361		push(@pieces, "\\$cmd".(($cmd =~ /\w$/)? " ":''));
5362		$this_cmd = '';
5363	    } elsif (($provide_command{$cmd})&&($within_preamble)) {
5364		# leave it alone
5365		push(@pieces, "\\$cmd".(($cmd =~ /\w$/)? " ":''));
5366		$this_cmd = '';
5367	    } else {
5368		# do the substitution
5369		$this_cmd = &substitute_newcmd if ($new_command{$cmd});
5370	    }
5371	    if ($this_cmd =~ /(\\(expandafter|noexpand)\s*)?$new_cmd_no_delim_rx\b\s?/)
5372	        { $after = $this_cmd . $after }
5373	    elsif ($this_cmd) { push(@pieces, $this_cmd) }
5374	  }
5375	  push(@pieces, $after);
5376	}
5377	print " $replacements new-command replacements\n"
5378	    if (($VERBOSITY>1) && $replacements);
5379	# recombine the processed pieces
5380	$_ = join('', @pieces); undef @pieces;
5381        print STDOUT ", resulting size: ".length($_)." " if ($VERBOSITY > 1);
5382	$_ =~ s/\\\@#\@\@/\\/go;
5383    }
5384
5385    print STDOUT "\n *** substituting metacommands done ***\n" if ($VERBOSITY > 3);
5386}
5387
5388sub insert_command_expansion {
5389    ($xafter, $cmd) = @_;
5390#   push(@pieces, $_[1]);
5391    print ".$cmd";
5392    print STDOUT "$_[3]" if ($VERBOSITY > 2);
5393#   $xafter = $_[2];
5394#   $cmd = $_[3];
5395    if ($xafter =~ /no/) { $this_cmd = "\\\@#\@\@".$cmd }
5396    elsif (($xafter =~ /after/)&&($after =~ /^\s*\\/)) {
5397	local($delayed,$nextcmd) = ($_[3],'');
5398
5399	$after =~ s/^\s*\\([a-zA-Z]+|.)/$nextcmd = $1;''/eo;
5400	($cmd,$nextcmd) = ($nextcmd, "do_cmd_$nextcmd");
5401	if (defined &$nextcmd) { $after = &$nextcmd($after); }
5402	elsif ($new_command{$cmd}) {
5403	    local($argn, $body, $opt) = split(/:!:/, $new_command{$cmd});
5404	    &make_unique($body) if ($body =~ /$O/);
5405	    if ($argn) {
5406		do {
5407		    local($before) = '';
5408		    $after = join('',&substitute_newcmd, $after);
5409		    $after =~ s/\\\@#\@\@/\\/o ;
5410		};
5411	    } else { $after = $body . $after; }
5412	} else { print "\nUNKNOWN COMMAND: $cmd "; }
5413	$cmd = $delayed;
5414	$this_cmd = &substitute_newcmd if ($new_command{$cmd});
5415    } else {
5416	$this_cmd = &substitute_newcmd if ($new_command{$cmd});
5417    }
5418#   if ($this_cmd =~ /(\\(expandafter|noexpand)\s*)?$new_cmd_no_delim_rx\s?/){
5419#	$after = $this_cmd . $after
5420#   } else { push(@pieces, $this_cmd); }
5421    $this_cmd;
5422}
5423
5424
5425sub expand_body {
5426    return unless length($new_cmd_or_env_rx);
5427    local($_) = $body;
5428    local($cmd,$saveafter,$avoid_looping);
5429    # Uses $before, $body, $arg, etc. of the caller, but not $cmd.
5430    # Uses $new_cmd_rx (resp. $new_cmd_no_delim_rx) and $new_env_rx
5431    # set in the caller, of which one might be empty.
5432
5433    # Puts delimiter after the new commands ...
5434    &tokenize($new_cmd_rx) if length($new_cmd_rx);
5435
5436    while (/$new_cmd_or_env_rx/) {
5437	# $new_cmd_rx binds $1, and $new_env_rx binds $3.
5438	($before,$cmd,$after,$saveafter) = ($`,$1.$3,$',$');
5439	if (length($new_command{$cmd})) { # We have a command
5440	    # this tokenizes again
5441	    local($replace) = &substitute_newcmd; # sets $_, changes $after
5442	    if (!($replace)) {
5443		# protect name of unexpanded macro
5444		$_ = join('', $before ,"\\@#@@", $cmd, $saveafter );
5445	    } else {
5446		$_ = join('', $before , $replace, $after );
5447	    }
5448	} elsif (length($new_environment{$cmd})) {
5449	    $_ = join('',$before, &substitute_newenv);
5450	}
5451	last if $avoid_looping;
5452    }
5453    # remove protection from unreplaced macro names
5454    s/\\\@#\@\@/\\/go;
5455
5456    # remove trivial comments
5457    s/(\\\w+)$comment_mark\d*\n[ \t]*/$1 /go;
5458    s/$comment_mark\d*\n[ \t]*//go;
5459#    s/($O\d+$C)?($comment_mark\n)[ \t]*/($1 ? $1.$2 : '')/eg;
5460
5461    $_;
5462}
5463
5464
5465sub substitute_newcmd {
5466    # Modifies $after in the caller
5467    # Get the body from the new_command array
5468    local($tmp,$cnt,$saved, $arg, $isword) = ('',0,$cmd);
5469    local($argn, $_, $opt) = split(/:!:/, $new_command{$cmd});
5470    $avoid_looping = 1 if ($new_command{$cmd} =~ /\\$cmd\b/);
5471
5472    &tokenize($new_cmd_rx); # must do it again for newly inserted cmd bodies
5473    print STDOUT "\nNEW:$cmd:$_" if ($VERBOSITY > 5);
5474    foreach $i (1..$argn) {
5475	$arg = $isword = '';
5476	if ($i == 1 && $opt ne '}') {
5477	    $arg = ($after =~ s/$optional_arg_rx//o) ? $1 : $opt;
5478	}
5479	else {
5480	    # Get the next argument, if not in braces, get next character
5481	    #RRM: allow also for processed braces, in case substitution
5482	    #     was delayed; e.g. by \renewcommand
5483	    if (!(($after =~ s/$next_pair_rx/$arg = $2;''/e)
5484		  ||($after =~ s/$next_pair_pr_rx/$arg = $2;''/e))) {
5485		$after =~ s/^\s*(\\[a-zA-Z]+|.)/$arg = $1;''/e;
5486	    }
5487	    if ($arg eq '#') {
5488		&write_warnings("\nSubstitution of arg to $cmd delayed.");
5489		$_ = "\\\@#\@\@$saved";
5490		return ();
5491	    };
5492	}
5493	$arg =~ s/(^|\G|[^\\])\\\#/$1$hash_mark/gs;
5494	$arg =~ s/\#/$param_mark/gs;
5495
5496	#RRM: Substitute the arguments in the body one at a time
5497	#     else multiple instances would fail in  &make_unique
5498
5499	# First protect ## parameters in TeX-like substitutions
5500	# suggested by Dirk Pleiter (Berlin)
5501	s/((^|[^\\])(\\\\)*)\#\#$i/$1$protected_hash/gs;
5502	$tmp = $_;
5503	$cnt = $tmp =~ s/\#$i//g ;
5504	$isword = 1 if ($arg =~ /^\w/);
5505	if ($cnt > 1 ) {
5506	    $tmp = $_;
5507	    while ($cnt > 1) {
5508		if ( s/(\\\w+)?\#$i/(($1&&$isword)? $1.' ': '').$arg/e) {
5509		    &make_unique($_) if ($arg =~ /$O/ );
5510		    &make_unique_p($_) if ($arg =~ /$OP/ );
5511		}
5512		$cnt--;
5513	    }
5514	    $tmp = $_;
5515	}
5516#	s/(\\\w+)?\#$i/(($1&&$isword)? $1.' ': '').$arg/e ;
5517	s/(\\\w+)?\#$i/$1.(($1&&$isword)? ' ': '').$arg/e ;
5518	print "\n *** substitution: $arg \nfor \#$i in \\$cmd did not take ***\n"
5519	   if (/\#$i/);
5520	&write_warnings("incomplete substitution in a \\$cmd command:\n$_") if (/\#$i/);
5521	s/$protected_hash/\#$i/g;
5522    }
5523    s/$param_mark/\#/g;
5524    s/$hash_mark/\\\#/g;
5525    s/(\\\w+)$/$1 /s;
5526
5527    # Make the body unique (give unique id's to the brackets),
5528    # translate, and return it
5529    &make_unique($_);
5530    if ($avoid_looping) {
5531	s/\\$cmd\b/\\csname $cmd\\endcsname/g;
5532	print STDERR "\n *** possible looping with new-command \\$cmd ***\n";
5533	&write_warnings("\npossible looping with new-command \\$cmd ");
5534    }
5535    print STDOUT "\nOUT:$cmd:$_" if ($VERBOSITY > 5);
5536
5537# Insert a space to prevent letters from clashing together with a
5538# letter command. Consider this:
5539# New command substitution is restricted to commands introduced by
5540# \newcommand etc. (so-called meta commands), but it is not done
5541# for already defined commands, eg. \large.
5542# But new command, as well as new environment, substitution is done
5543# prior to any other substitution.
5544# So \newcommand{\this}{...} {\large\this b} will get expanded the
5545# following way:
5546# 1. \newcommand{\this}{...}
5547#    is handled by &substitute_meta_cmds, it gets the definition
5548#    of \this and stores it within a table, %new_command.
5549#    After all new commands are recognized, &expand_body is called
5550#    to expand one command body from each other. That's O(n*n)!
5551# 2. A regular expression $new_cmd_rx is built containing a pattern
5552#    that matches all occurrences of a properly delimited \this
5553#    macro. When matching, ensuing white space gets lost.
5554#    (But only for letter commands, see also &make_new_cmd_rx.)
5555#    Another regular expression called $new_cmd_no_delim_rx is built
5556#    which matches exact the \this, and would also match the prefix
5557#    of \thisx.
5558# 3. The *whole* text is tokenized using $new_cmd_rx, with separates
5559#    \this from the ensuing text by one white space.
5560# 4. Then $new_cmd_no_delim_rx together with the delimiting space
5561#    is used to substitute \this with its body.
5562# 5. The following situations may occur:
5563#  a) ... is some text (no macros) => {\large<text>yyy}
5564#     Then we must prevent that the text clashes into \large.
5565#     This is only dangerous when <text> begins with a letter.
5566#  b) ... contains another, not expanded new command.
5567#     This happens during &expand_body.
5568#     In this case, make sure to &tokenize the body before giving
5569#     the result to the caller. Also take care that leading letters
5570#     of the body cannot clash into \large.
5571#  e) ... contains a macro not known as new command:
5572#     Make sure that the macro cannot clash with the ensuing yyy.
5573#  f) ... is empty:
5574#     Make sure that \large cannot clash with yyy.
5575# 6. We prevent clashing by inserting a delimiting blank.
5576#    Out of the scetched situation, there are three conditions to
5577#    take care of:
5578#  a) empty body, left a letter command, right a letter => blank
5579#  b) body starts with letter, left a letter command    => blank
5580#  c) body ends with letter command, right a letter     => blank
5581#  d) else => no blank, clash all together, it will work.
5582# 7. With this rules, the expansion should work quite well,
5583#    concerning letter/non-letter commands and white space
5584#    handling.
5585# 8. Deficiencies:
5586# 8.1 Consider \this<CR>that. It's handled this way:
5587#  a) The \this swallows the <CR> in LaTeX, but what LaTeX2HTML does
5588#     is to &tokenize the expression into \this <CR>that.
5589#  b) If ... is some text, it results in <text><CR>that.
5590#  c) If ... is a macro (or command, or control sequence, these
5591#     terms are often mixed up, but effectively mean the same),
5592#     then if the macro later takes at least one argument, the <CR>
5593#     might get swallowed, this depends on the grace of $next_pair_rx
5594#     resp. $next_pair_pr_rx.
5595#     If the macro takes no arguments, the <CR> remains in the text.
5596#  d) If ... ends in another new command, the problem repeats.
5597# 8.2 The new commands are substituted in a very insensitive way.
5598#     If \this occurs within an environment which sees \this
5599#     totally different, there's no chance to substitute \this in
5600#     a different way.
5601# 8.3 In relation to 8.2 a similar problem arises when the meta
5602#     command, or several meta commands redefining \this, occur
5603#     amongst several \this macros.
5604# 8.4 In raw TeX like environments it is not possible to revert the
5605#     expansion of \this, but \this probably *must* occur in its
5606#     raw form.
5607
5608# Handle the cases as depicted in the description of new command
5609# substitution.
5610    local($befdel,$aftdel);
5611    $befdel = ' '
5612	if ($before=~/(^|[^\\])\\[a-zA-Z]+$/ && /^$/ && $after=~/^[a-zA-Z]/) ||
5613	    ($before=~/(^|[^\\])\\[a-zA-Z]+$/ && /^[a-zA-Z]/);
5614    $aftdel = ' '
5615	if /(^|[^\\])\\[a-zA-Z]+$/s && $after=~/^[a-zA-Z]/;
5616    join('', $befdel, $_, $aftdel);
5617}
5618
5619#RRM:  use this to test whether a specific command is substituting correctly
5620sub trace_cmd {
5621    local($this) = @_;
5622    if ($cmd eq $this) { print "\n$1=>$id:$2::"}
5623}
5624
5625# Make the text unique (give unique id's to the brackets).
5626# The text shouldn't contain processed brackets.
5627sub make_unique {
5628    # MRO: Change to references $_[0]
5629    # local(*_) = @_;
5630    my $id = $global{'max_id'};
5631    # MRO: replaced $* by /m
5632    # this looks quite funny but is optimized
5633    1 while($_[0] =~ s/$O(\d+)$C([\w\W]*)$O\1$C/$id++;"\000$id $2\000$id "/geom);
5634    $_[0] =~ s/\000(\d+) /$O$1$C/gom;
5635    $global{'max_id'} = $id;
5636}
5637
5638#RRM: this shouldn't be needed, but just in case...
5639sub make_unique_p {
5640    # MRO: Change to references $_[0]
5641    my $id = $global{'max_id'};
5642    # MRO: replaced $* by /m
5643    # this looks quite funny but is optimized
5644    1 while($_[0] =~ s/$OP(\d+)$CP([\w\W]*)$OP\1$CP/$id++;"\000$id $2\000$id "/geom);
5645    $_[0] =~ s/\000(\d+) /$OP$1$CP/gom;
5646    $global{'max_id'} = $id;
5647}
5648
5649
5650sub substitute_newenv {
5651    # Modifies $cmd and $after in the caller
5652    # Get the body from the new_environment array
5653    local($argn, $begdef, $enddef, $opt) = split(/:!:/, $new_environment{$cmd});
5654    local($arg,$new_def_rx,$tmp,$cnt);
5655
5656    # Note that latex allows argument substitution only in the
5657    # \begin part of the new definition
5658    foreach $i (1..$argn) {	# Process the arguments
5659	if (($i == 1) && ($opt ne '}')) {
5660	    $after =~ s/$optional_arg_rx/$arg = $1;''/eo;
5661	    $arg = $opt unless $arg;
5662	}
5663	else {
5664	    $after =~ s/$next_pair_rx/$arg = $2;''/eo;
5665	}
5666	$arg =~ s/(^|[^\\])\\\#/$1$hash_mark/g;
5667	$arg =~ s/\#/$param_mark/g;
5668
5669        #RRM: multiple instances can fail later in  &make_unique
5670#       s/\#$i/$arg/g;          # Substitute the arguments in the body
5671        #RRM: ...so do one at a time and  &make_unique_p
5672        $tmp = $begdef;
5673        $cnt = $tmp =~ s/\#$i//g ;
5674        if ($cnt > 1) {
5675            $tmp = $begdef;
5676            while ($cnt > 1) {
5677		if ( $begdef =~ s/\#$i/$arg/) {
5678		    &make_unique($begdef) if ($arg =~ /$O/ );
5679		    &make_unique_p($begdef) if ($arg =~ /$OP/ );
5680		}
5681                $cnt--;
5682            }
5683            $tmp = $_;
5684        }
5685        $begdef =~ s/\#$i/$arg/ ;
5686        print "\n *** substitution: $arg \nfor \#$i in {$cmd} did not take ***\n"
5687           if ($begdef =~ /\#$i/);
5688	&write_warnings("incomplete substitution in a {$cmd} environment:\n$begdef")
5689	    if ($begdef =~ /\#$i/);
5690    }
5691    $begdef =~ s/$param_mark/\#/g;
5692    $begdef =~ s/$hash_mark/\\\#/g;
5693    $begdef =~ s/(\\\w+)$/$1 /s;
5694
5695    # Make the body unique (Give unique id's to the brackets),
5696    # translate, and return it
5697#RRM: when are these needed ?
5698#    $_ = &revert_to_raw_tex($_);
5699#    &pre_process;
5700
5701    &make_unique($begdef);		# Make bracket IDs unique
5702    print STDOUT "\nBEGIN:$cmd:$begdef" if ($VERBOSITY > 4);
5703
5704    # Now substitute the \end part:
5705#RRM: when are these needed ?
5706#    $_ = &revert_to_raw_tex($enddef);
5707#    &pre_process;
5708
5709    &make_unique($enddef);		# Make bracket IDs unique
5710    print STDOUT "\nEND:$cmd:$enddef" if (($enddef)&&($VERBOSITY > 4));
5711    $enddef =~ s/(\\\w+)$/$1 /s;
5712
5713    local($new_end_def_rx) = &make_end_env_rx($cmd);
5714    if (($enddef)&&!($after =~ s/\n?$new_end_def_rx/$enddef/ )) {
5715        $UNFINISHED_ENV = $new_end_def_rx;
5716        $REPLACE_END_ENV = $enddef;
5717    };
5718    join('',$begdef,$after);
5719}
5720
5721sub substitute_pars {
5722    s/((\%|$comment_mark\d*)|.)(\r*\n[ \t]*){2,}[ \t]*/$1\n\\par \n/og;
5723#    s/((\%|$comment_mark\d*)|\d|.)[\r\n\015]{2,}/print "\nPAR:".$`.$&;"$1\n\\par \n"/egs;
5724}
5725
5726sub do_cmd_end { #RRM:  catches the end of any unclosed environments
5727    local($_) = @_;
5728    &missing_braces unless (
5729	(s/$next_pair_pr_rx//o)||(s/$next_pair_rx//o));
5730    s/^\n//;
5731    $_;
5732}
5733
5734# Removes the definition from the input string,
5735# adds to the preamble unless it is part of the preamble already
5736# and stores the body in %new_command;
5737sub get_body_newcommand {
5738    local($newed, $n_after) = &process_body_newcommand(0,@_);
5739    (($PREAMBLE)? "newed".$newed : '');
5740}
5741
5742sub process_body_newcommand {
5743#    local($renewed,*_) = @_;
5744    local($renewed,$after_R) = @_;
5745    local($_) = $$after_R;
5746    local($no_change) = $_;
5747    local($argn,$newcmd,$cmd_br,$body,$body_br,$tmp,$tmp1,$opt,$pat);
5748    local($new_cmd) = 'command';
5749    if ($renewed =~ /provide/||$renewed == 2) {
5750	# $newcmd = &missing_braces unless (
5751	($newcmd,$pat) = &get_next(1) unless (
5752	        (s/$next_pair_pr_rx/$pat=$&;$newcmd=$2;''/e)
5753	        ||(s/$next_pair_rx/$pat=$&;$newcmd=$2;''/e));
5754	if (!$pat) {
5755	    local($br_id) = ++$global{'max_id'};
5756	    $pat = "$O$br_id$C".$newcmd."$O$br_id$C";
5757	}
5758    } else {
5759	($newcmd,$pat) = &get_next(1); # Get command name
5760    }
5761    $pat =~ s/\\//; $new_cmd .= $pat;
5762    $newcmd =~ s/^\s*\\//;
5763    ($argn,$pat) = &get_next(0);	# Get optional no. of args
5764    $argn = 0 unless $argn; $new_cmd .= $pat if $argn;
5765    local($cmd) = $newcmd;
5766
5767    # Get the body of the code and store it with the name and number of args
5768    # UNLESS THE COMMAND IS ALREADY DEFINED
5769    # ...in which case $ALLOW_REDEFINE must also have been set.  # RRM
5770    # (This is the mechanism with which raw html can be ignored in a Latex document
5771    # but be recognised as such by the translator).
5772    $opt = '}';			# Flag for no optional arg
5773    local($bodyA) = '';
5774    if (/^\[/) {
5775	($opt,$pat) = &get_next(0);
5776	$new_cmd .= $pat;
5777	$bodyA .= "\n".'($dummy, $pat) = &get_next_optional_argument;' .
5778                    "\n". '$args .= $pat;';
5779    }
5780    local($nargs) = $argn;
5781    while ($nargs > 0) { $nargs--;
5782	$bodyA .=
5783	    "\n".'$args .= $`.$& if ((s/$next_pair_pr_rx//o)||(s/$next_pair_rx//o));';
5784    }
5785    if ($renewed =~ /provide/||$renewed == 2 ) {
5786        $body = &missing_braces unless (
5787	        (s/$next_pair_pr_rx/$pat=$&;$body=$2;''/e)
5788	        ||(s/$next_pair_rx/$pat=$&;$body=$2;''/e));
5789	$new_cmd .= $pat;
5790    } else {
5791	($body,$pat) = &get_next(4);  #get the body
5792	$new_cmd .= $pat;
5793    }
5794
5795    local($thisone);
5796#    $thisone = 1 if ($cmd =~ /div|vec/);  # for debugging
5797
5798    $tmp = "do_cmd_$cmd";
5799    local($wtmp) = "wrap_cmd_$cmd";
5800    if ((defined &$tmp)||(defined &$wtmp)){
5801	# command already exists, so \providecommand  does nothing
5802	# but may still be needed in  images.tex
5803	$$after_R = $_;
5804	return ($new_cmd) if ($renewed =~ /provide/);
5805
5806	print "\n*** redefining \\$cmd ***\n";
5807	&write_warnings("\nredefining command \\$cmd ");
5808	if (!$ALLOW_REDEFINE) {
5809	    print "*** overriding previous meaning ***\n";
5810	    &write_warnings("\nprevious meaning of \\$cmd will be lost");
5811	}
5812#	local($code) = "undef \&$tmp"; eval ($code);
5813#	if ($@) {print "\n*** undef \&$cmd failed \n"}
5814	if ((!$PREAMBLE)||($renewed>1)) {
5815	    $new_command{$cmd} = join(':!:',$argn,$body,$opt);
5816#	    local($code) = "sub $tmp\{\&replace_new_command(\"$cmd\");\}";
5817#	    eval $code;
5818#	    print STDERR "\n*** sub do_cmd_$cmd failed:\nPERL: $@\n" if ($@);
5819#	    &replace_new_command($cmd);
5820	}
5821
5822	$renew_command{$cmd} = 1;
5823	&write_mydb("renew_command", $cmd, $renew_command{$cmd});
5824        local($padding) = " ";
5825        $padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
5826        # Generate a new subroutine
5827        local($codeA) = "sub wrap_cmd_$cmd {" . "\n"
5828            .'local($cmd, $_) = @_; local ($args, $dummy, $pat) = "";'
5829            . $bodyA
5830	    . (($thisone)? "\nprint \"\\nwrap $cmd:\".\$args.\"\\n\";" : '')
5831            . "\n".'(&make_deferred_wrapper(1).$cmd.'
5832            . "\"$padding\"".'.$args.&make_deferred_wrapper(0),$_)}'
5833            . "\n";
5834        print "\nWRAP_CMD: $codeA " if ($thisone); # for debugging
5835        eval $codeA;
5836        print STDERR "\n\n*** sub wrap_cmd_$cmd  failed: $@\n" if ($@);
5837	$raw_arg_cmds{$cmd} = 1;
5838
5839    } elsif (($ALLOW_REDEFINE)&&($PREAMBLE < 2)) {
5840	print "\n*** redefining \\$cmd ***\n";
5841	&write_warnings("\ncommand \\$cmd had no previous definition")
5842	    if (!($new_command{$cmd}));
5843    }
5844    if ($renewed && ($PREAMBLE > 1) &&($new_command{$cmd})) {
5845	$raw_arg_cmds{$cmd} = 1 ;
5846	$renew_command{$cmd} = 1;
5847        local($padding) = " ";
5848        $padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
5849        # Generate a new subroutine
5850        local($codeA) = "sub wrap_cmd_$cmd {" . "\n"
5851            .'local($cmd, $_) = @_; local ($args, $dummy, $pat) = "";'
5852            . $bodyA
5853	    . (($thisone)? "\nprint \"\\nwrap $cmd:\".\$args.\"\\n\";" : '')
5854            . "\n".'(&make_deferred_wrapper(1).$cmd.'
5855	    . "\"$padding\"".'.$args.&make_deferred_wrapper(0),$_)}'
5856            . "\n";
5857        print "\nWRAP_CMD: $codeA " if ($thisone); # for debugging
5858        eval $codeA;
5859        print STDERR "\n\n*** sub wrap_cmd_$cmd  failed: $@\n" if ($@);
5860
5861	&write_mydb("renew_command", $cmd, $renew_command{$cmd});
5862    } elsif ($renewed) {
5863        $new_command{$cmd} = join(':!:',$argn,$body,$opt);
5864    } else {
5865	$new_command{$cmd} = join(':!:',$argn,$body,$opt)
5866	    unless (($PREAMBLE > 1)&&($renew_command{$cmd}));
5867    }
5868
5869    local($this_cmd);
5870    $this_cmd = join(''
5871	, "command{\\$cmd}"
5872	, ($argn ? "[$argn]" :'')
5873	, (($opt =~ /^}$/) ? '' : "[$opt]" )
5874	, "{", $body , "}" );
5875    $this_cmd = &revert_to_raw_tex($this_cmd);
5876    if ($renewed) {
5877	if ($renewed=~/provide/){
5878	    $provide_command{$cmd} = 1;
5879	    &write_mydb("provide_command", $cmd, $provide_command{$cmd});
5880#	} else {
5881#	    print "\n ** marking $cmd as renewed **";
5882#	    $renew_command{$cmd} = 1;
5883	};
5884	if ((!$PREAMBLE)&&($renewed>1)) {
5885#	    local($this_cmd) = join(''
5886#		, "\n\\renewcommand{\\$cmd}"
5887#		, ($argn ? "[$argn]" :'')
5888#		, (($opt =~ /^}$/) ? '' : "[$opt]" )
5889#		, "{", $body , "}\n" );
5890#	    $latex_body .= &revert_to_raw_tex($this_cmd);
5891	    $latex_body .= "\n\\renew". $this_cmd."\n";
5892	} else {
5893##	    &add_to_preamble('command',"\\" . $this_cmd);
5894	}
5895    } else {
5896	&add_to_preamble('command',"\\new" . $this_cmd)
5897	    unless ($PREAMBLE);
5898    }
5899    undef $body;
5900    if ($renewed == 2) {
5901	# there is no output to return
5902	$$after_R = $_;
5903	return();
5904    }
5905
5906    if (!$PREAMBLE) {
5907	$$after_R = $_;
5908	return ($new_cmd) if ($renewed);
5909#	    $cmd_br =~ s/\\//;
5910#	( join ('', &make_deferred_wrapper(1)
5911#	    , "\\". ($renewed ? (($renewed =~ /provide/)? 'provid' : 'renew')
5912#		: 'new')."edcommand"
5913#	    , $cmd_br , ($argn ? "[$argn]" :'')
5914#	    , ( ($opt =~ /^\}$/ ) ? '' : "[$opt]" ) , $body_br
5915#	    , &make_deferred_wrapper(0)) , $_ );
5916	$new_cmd = join('', "command{\\$cmd}"
5917			 , ($argn ? "[$argn]" :'')
5918			 , (($opt =~ /^\}$/) ? '' : "[$opt]" )
5919			 , "{", $body , "}" );
5920	$new_cmd = &revert_to_raw_tex($new_cmd);
5921	&add_to_preamble('command', "\\provide".$new_cmd );
5922	$$after_R = $_;
5923	return();
5924    }
5925    $new_cmd =~ s/\\$cmd([\d\W]|$)/$cmd$1/s;
5926    $$after_R = $_;
5927    $new_cmd;
5928}
5929
5930sub replace_new_command {
5931    local($cmd) = @_;
5932    local($argn, $body, $opt) = split(/:!:/, $new_command{$cmd});
5933    do { ### local($_) = $body;
5934	 &make_unique($body);
5935	 } if ($body =~ /$O/);
5936    $body =~ s/(^|[^\\])\~/$1\\nobreakspace /g;
5937    if ($argn) {
5938	do {
5939	    local($before) = '';
5940	    local($after) = "\\$cmd ".$_;
5941	    $after = &substitute_newcmd;   # may change $after
5942	    $after =~ s/\\\@#\@\@/\\/o ;
5943	};
5944    } elsif ($body =~ /\\/) {
5945	$body = &translate_commands($body);  # ???
5946	$_ = $body . $_;
5947    } else { $_ = $body . $_; }
5948    $_;
5949}
5950
5951sub get_body_let {
5952#    local(*_) = @_;
5953    local($_) = @_;
5954    local($cmd,$body,$replace,$tmp,$pat);
5955    ($cmd,$body) = &get_next_tex_cmd;
5956    s/^\s*=?\s*/$body .= $&;''/e;
5957    ($replace,$pat) = &get_next_tex_cmd;
5958#    return() if ($replace eq $cmd);
5959    $body .= $pat;
5960    $body = &revert_to_raw_tex($body);
5961    &add_to_preamble('', "\\let ".$body );
5962    $_[0] = $_;
5963    if (($replace eq $cmd)||($cmd="\\")||($cmd =~/(style|size)$/)) {
5964	"let ".$body
5965    } else {
5966	$new_command{$cmd} = join(':!:','',"\\$replace ",'}');
5967	'';
5968    }
5969}
5970
5971
5972#  do not remove the \renewcommand code, since it may be needed
5973#  within images. Instead replace it with \renewedcommand;
5974#  This will be reverted in &revert_to_raw_tex
5975sub get_body_renewcommand {
5976    local($ALLOW_REDEFINE) = 1;
5977    local($renew, $n_after) = &process_body_newcommand(1,@_);
5978    ($renew ? 'renewed' . $renew : '');
5979}
5980
5981sub do_cmd_renewedcommand {
5982    local($_) = @_;
5983    local($ALLOW_REDEFINE) = 1;
5984    &process_body_newcommand(2,\$_);
5985    $_ ;
5986}
5987
5988sub get_body_providecommand {
5989    local($provide, $n_after) = &process_body_newcommand('provide',@_);
5990    (($PREAMBLE && $provide) ? 'provided'.$provide : '');
5991}
5992
5993sub do_cmd_providedcommand{ &do_cmd_renewedcommand(@_) }
5994
5995sub get_body_DeclareRobustCommand {
5996    local($provide, $n_after) = &process_body_newcommand('provide',@_);
5997    (($PREAMBLE && $provide) ? 'provided'.$provide : '');
5998}
5999
6000sub get_body_DeclareMathOperator {
6001    local($after_R) = @_;
6002    local($_) = $$after_R;
6003    my $star;
6004    s/^\\DeclareMathOperator\s*(\*|star)/$star = $1;''/s;
6005    my ($mcmd,$patA) = &get_next(1);
6006    my ($mop,$patB) = &get_next(1);
6007    if ($star) {
6008	$patA .= "${O}0$C\\mathop${O}1$C\\mathrm${patB}${O}1$C${O}0$C".$_;
6009    } else {
6010	$patA .= "${O}0$C${O}1$C\\mathrm${patB}${O}1$C${O}0$C".$_;
6011    }
6012    local($provide, $n_after) = &process_body_newcommand('provide',\$patA);
6013    $$after_R = $patA;
6014    (($PREAMBLE && $provide) ? 'provided'.$provide : '');
6015}
6016
6017sub get_body_DeclareMathOperatorstar {
6018    local($after_R) = @_;
6019    local($_) = $$after_R;
6020    my $star;
6021    s/^\\DeclareMathOperator\s*(\*|star)/$star = $1;''/s;
6022    my ($mcmd,$patA) = &get_next(1);
6023    my ($mop,$patB) = &get_next(1);
6024    $patA .= "${O}0$C\\mathop${O}1$C\\mathrm${patB}${O}1$C${O}0$C".$_;
6025    local($provide, $n_after) = &process_body_newcommand('provide',\$patA);
6026    $$after_R = $patA;
6027    (($PREAMBLE && $provide) ? 'provided'.$provide : '');
6028}
6029
6030
6031# Removes the definition from the input string, adds to the preamble
6032# and stores the body in %new_environment;
6033sub get_body_newenvironment {
6034    local($newed,$after) = &process_body_newenvironment(0,@_);
6035    ( $PREAMBLE ? "newed".$newed : '');
6036}
6037
6038sub process_body_newenvironment {
6039#    local($renew,*_) = @_;
6040    local($renew,$after_R) = @_;
6041    local($_) = $$after_R;
6042    local($no_change) = $_;
6043    local($argn,$env,$begin,$end,$tmp,$opt,$pat);
6044    local($new_env) = 'environment';
6045    if ($renew == 2) {
6046        $env = &missing_braces unless (
6047	        (s/$next_pair_pr_rx/$pat=$&;$env=$2;''/e)
6048	        ||(s/$next_pair_rx/$pat=$&;$env=$2;''/e));
6049	$new_env .= $pat;
6050    } else {
6051	($env,$pat) = &get_next(1);	# Get the environment name
6052	$env =~ s/^\s*\\//; $new_env .= $pat;
6053    }
6054    ($argn,$pat) = &get_next(0);	# Get optional no. of args
6055    $argn = 0 unless $argn; $new_env .= $pat if $argn;
6056
6057    # Get the body of the code and store it with the name and number of args
6058    # UNLESS THE COMMAND IS ALREADY DEFINED (see get_body_newcommand)
6059    # ...in which case $ALLOW_REDEFINE must also have been set.  # RRM
6060    $opt = '}';			# Flag for no optional arg
6061    if (/^\[/) {
6062	($opt,$pat) = &get_next(0);
6063	$new_env .= $pat;
6064    }
6065    $tmp = "do_env_$env";
6066
6067    if ($renewed == 2 ) {
6068        $begin = &missing_braces unless (
6069	        (s/$next_pair_pr_rx/$pat=$&;$begin=$2;''/e)
6070	        ||(s/$next_pair_rx/$pat=$&;$begin=$2;''/e));
6071	$new_env .= $pat;
6072	$end = &missing_braces unless (
6073	        (s/$next_pair_pr_rx/$pat=$&;$end=$2;''/e)
6074	        ||(s/$next_pair_rx/$pat=$&;$end=$2;''/e));
6075	$new_env .= $pat;
6076    } else {
6077	($begin,$pat) = &get_next(1); $new_env .= $pat;
6078	($end,$pat) = &get_next(1); $new_env .= $pat;
6079    }
6080    if ((defined &$tmp)&&($ALLOW_REDEFINE)) {
6081	print STDOUT "\n*** redefining environment {$env} ***\n";
6082	&write_warnings("\nredefined environment {$env} ");
6083    }
6084    $new_environment{$env} = join(':!:', $argn, $begin, $end, $opt)
6085	unless ((defined &$tmp)&&(! $ALLOW_REDEFINE));
6086
6087    if (!$PREAMBLE) {
6088	$new_env = join ('',
6089	    , "environment{$env}"
6090	    , ($argn ? "[$argn]" : '')
6091	    , (($opt ne '}')? "[$opt]" : '')
6092	    , "{$begin}{$end}"
6093	    );
6094	&revert_to_raw_tex($new_env);
6095	if ($renew == 2) {
6096	    $latex_body .= "\n\\".($renew ? 're':'').'new'.$new_env."\n";
6097	} else {
6098	    &add_to_preamble ('environment'
6099		, "\\".($renew ? 're':'').'new'.$new_env );
6100	}
6101	$$after_R = $_;
6102	return();
6103    }
6104    if ($new_env =~ /$sections_rx/) {
6105    	$new_env = join('', $`,'\csname ',$2,'\endcsname',$3,$');
6106    }
6107    $new_env =~ s/$par_rx/\\par /g;
6108    $$after_R = $_;
6109    $new_env;
6110}
6111
6112sub get_body_renewenvironment {
6113    local($ALLOW_REDEFINE) = 1;
6114    local($renewed, $after) = &process_body_newenvironment(1,@_);
6115    'renewed'.$renewed;
6116}
6117
6118sub do_cmd_renewedenvironment {
6119    local($ALLOW_REDEFINE) = 1;
6120    local($_) = @_;
6121    &process_body_newenvironment(2,\$_);
6122    $_;
6123}
6124
6125# Instead of substituting as with newcommand and newenvironment,
6126# or generating code to handle each new theorem environment,
6127# it now does nothing. This forces theorem environments to be passed
6128# to latex. Although it would be possible to handle theorem
6129# formatting in HTML as it was done previously it is impossible
6130# to keep the theorem counters in step with other counters (e.g. equations)
6131# to which only latex has access to. Sad...
6132sub get_body_newtheorem {
6133#    local(*_) = @_;
6134    local($after_R) = @_;
6135    local($_) = $$after_R;
6136    my ($orig, $body) = ($_, '');
6137    my ($title, $env, $ctr, $within, $cmd, $tmp, $begin, $end, $pat);
6138    my ($new_thm) = 'theorem';
6139    # Just chop off the arguments and append to $next_def
6140    ($env,$pat) = &get_next(1); $new_thm .= $pat;
6141    ($ctr,$pat) = &get_next(0); $new_thm .= $pat;
6142    ($title,$pat) = &get_next(1); $new_thm .= $pat;
6143    ($within,$pat) = &get_next(0); $new_thm .= $pat;
6144
6145    #check the style parameters
6146    my ($hfont,$bfont,$thm_style);
6147    my ($before_thm) = join('',@processed);
6148    my ($which,$cmds);
6149    while ($before_thm =~ /$theorem_cmd_rx/) {
6150	$which = $1;
6151	$before_thm = $';
6152	$before_thm =~ s/$next_pair_rx/$cmds = $2;''/e;
6153	$cmds =~ s/\\/\|/g;  # escape any backslash
6154	if ($which =~ /style/) { $thm_style = $cmds }
6155	elsif ($which =~ /header/) { $hfont = $cmds }
6156	elsif ($which =~ /body/)   { $bfont = $cmds }
6157    }
6158    $hfont = '['.$hfont.']';
6159    $bfont = '['.$bfont.']';
6160    $thm_style = '['.$thm_style.']';
6161    undef $before_thm;
6162
6163    if (!($ctr)) {
6164	# define the new counter
6165	$ctr = $env;
6166	do {
6167###	    local($_) = "\\arabic<<1>>$ctr<<1>>";
6168###	    $_ = join('',"\\the$within", "." , $_) if ($within);
6169	    $body = "\\arabic<<1>>$ctr<<1>>";
6170	    $body = join('',"\\the$within", "." , $body) if ($within);
6171	    &make_unique($body);
6172	    $cmd = "the$ctr";
6173	    $tmp = "do_cmd_$cmd";
6174	    do {
6175                $new_command{$cmd} = join(':!:',0,$body,'}')
6176	    } unless (defined &$tmp);
6177	    &write_mydb("new_command", $cmd, $new_command{$cmd});
6178	    eval "sub do_cmd_$cmd {\n"
6179		. 'local($_,$ot) = @_;'."\n"
6180		. 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'."\n"
6181		. '&translate_commands(' . "\"$body\"" . ");\n}\n";
6182	    print STDERR "\n*** sub $tmp failed:\n$@\n" if ($@);
6183	    $raw_arg_cmds{$cmd} = 1;
6184	    undef $body;
6185	};
6186	&do_body_newcounter($ctr);
6187    } else {
6188	do {
6189###	    local($_) = "\\arabic<<1>>$ctr<<1>>";
6190	    $body = "\\arabic<<1>>$ctr<<1>>";
6191	    &make_unique($body);
6192	    $cmd = "the$env";
6193	    $tmp = "do_cmd_$cmd";
6194	    do {
6195                $new_command{$cmd} = join(':!:',0,$body,'}')
6196	    } unless (defined &$tmp);
6197	    &write_mydb("new_command", $cmd, $new_command{$cmd});
6198	    eval "sub do_cmd_$cmd {\n"
6199		. 'local($_,$ot) = @_;'
6200		. 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'
6201		. '&translate_commands(' . "\"$body\"" . ");\n}\n";
6202	    print STDERR "\n*** sub $tmp failed:\n$@\n" if ($@);
6203	    $raw_arg_cmds{$cmd} = 1;
6204	    undef $body;
6205	};
6206    }
6207
6208    # record the counter dependency
6209    &addto_dependents($within,$ctr) if ($within);
6210
6211    # save the text-label in the %new_theorem hash
6212    $new_theorem{$env} = $title;
6213
6214    # define a new environment
6215    my ($id) = ++$global{'max_id'};
6216    $begin = "\\begin<<$id>>theorem_type<<$id>>"
6217	. "[$env][$ctr][$within]$thm_style$hfont$bfont\n";
6218    $id = ++$global{'max_id'};
6219    $end = "\\end<<$id>>theorem_type<<$id>>\n";
6220    $tmp = "do_env_$env";
6221    if ((defined &$tmp)&&($ALLOW_REDEFINE)) {
6222	print STDOUT "\n*** redefining theorem environment {$env} ***\n";
6223    }
6224    $new_environment{$env} = join(':!:', '', $begin, $end, '')
6225	unless ((defined &$tmp)&&(! $ALLOW_REDEFINE));
6226
6227    if (!$PREAMBLE) {
6228	my ($new_cmd) = join(''
6229	    , 'theorem{}' );
6230	&add_to_preamble('theorem', "\\new".$new_cmd );
6231	$$after_R = $_;
6232	return();
6233    }
6234    $$after_R = $_;
6235    'newed'.$new_thm;
6236}
6237
6238sub do_cmd_theoremstyle {
6239    local($_) = @_;
6240    local($thm_type);
6241    $thm_type = &missing_braces unless (
6242	(s/$next_pair_pr_rx/$thm_type=$2;''/e)
6243	||(s/$next_pair_rx/$thm_type=$2;''/e));
6244#   $THM_STYLE = $thm_type;
6245    $_;
6246}
6247sub do_cmd_theoremheaderfont {
6248    local($_) = @_;
6249    local($thm_type);
6250    $thm_type = &missing_braces unless (
6251	(s/$next_pair_pr_rx/$thm_type=$2;''/e)
6252	||(s/$next_pair_rx/$thm_type=$2;''/e));
6253#   $THM_HFONT = $thm_type;
6254    $_;
6255}
6256sub do_cmd_theorembodyfont {
6257    local($_) = @_;
6258    local($thm_type);
6259    $thm_type = &missing_braces unless (
6260	(s/$next_pair_pr_rx/$thm_type=$2;''/e)
6261	||(s/$next_pair_rx/$thm_type=$2;''/e));
6262#   $THM_BFONT = $thm_type;
6263    $_;
6264}
6265
6266sub do_env_theorem_type {
6267    local($_) = @_;
6268    local($dum,$env,$ctr,$within, $label, $name, $title, $text, $index);
6269    ($env, $dum) = &get_next_optional_argument;
6270    ($ctr, $dum) = &get_next_optional_argument;
6271    ($within, $dum) = &get_next_optional_argument;
6272
6273    local($thm_num, $thm_style);
6274    # defaults for plain theorem-style
6275    my ($hfont,$bfont) = ('','');
6276
6277    ($thm_style, $dum) = &get_next_optional_argument;
6278    ($hfont, $dum) = &get_next_optional_argument;
6279    $hfont =~ s/\|/\\/og;
6280    ($bfont, $dum) = &get_next_optional_argument;
6281    $bfont =~ s/\|/\\/og;
6282
6283    # the pre-defined alternative theorem-styles
6284    if ($thm_style =~ /definition/) {
6285	$bfont = '\normalfont' unless $bfont;
6286    } elsif ($thm_style =~ /remark/) {
6287	$hfont = '\itshape' unless $hfont;
6288	$bfont = '\normalfont' unless $bfont;
6289    }
6290
6291    # defaults for plain theorem-style
6292    $hfont = '\bfseries' unless $hfont;
6293    $bfont = '\itshape' unless $bfont;
6294
6295    ($name, $dum) = &get_next_optional_argument;
6296    $name = &translate_environments("${O}0$C".$name."${O}0$C") if $name;
6297    $name = &translate_commands($name) if ($name =~ /\\/);
6298
6299    $index = $section_commands{$ctr};
6300    if ($index) {
6301	# environment actually starts a new (sub-)section
6302	$curr_sec_id[$index]++;
6303	local($this) = &translate_commands("\\the$ctr");
6304	local($hash) = &sanitize($name." $this");
6305	local($section_tag) = join('', @curr_sec_id);
6306	$encoded_section_number{$hash} = join($;, $section_tag);
6307	&reset_dependents($ctr) if ($dependent{$ctr});
6308	$thm_num = &translate_commands("\\the$ctr");
6309	$thm_num =~ s/(\w)\.(\.\w)/$1$2/g;
6310
6311	# construct the sectioning title from the counter values
6312	$title = join( '', $new_theorem{$env}, " "
6313	    , &translate_commands("\\the$ctr") );
6314	$toc_section_info{join(' ',@curr_sec_id)} = \
6315	    "$current_depth$delim$CURRENT_FILE$delim$title"
6316		if ($current_depth <= $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH);
6317	$section_info{join(' ',@curr_sec_id)} = \
6318	    "$current_depth$delim$CURRENT_FILE$delim$title$delim";
6319	$title = join('',"<A NAME=\"SECTION$section_tag\"><B>"
6320		      , $title , "</B></A>" );
6321    } else {
6322	if ($ctr) {
6323	    print STDOUT "\nSTP:$ctr:+1" if ($VERBOSITY > 3);
6324	    $global{$ctr}++;
6325	    print STDOUT "=".$global{$ctr}." " if ($VERBOSITY > 3);
6326	    &reset_dependents($ctr) if ($dependent{$ctr});
6327	    $thm_num = "\\the$ctr ";
6328	} else { $thm_num = ''; }
6329
6330	# construct the full title from the counter values
6331	$title = $new_theorem{$env};
6332	if (($thm_style =~ /margin/)&&($HTML_VERSION > 2.1)) {
6333	    # don't use the number yet
6334	} elsif ($thm_style =~ /change/) {
6335	    $title = join(' ', $thm_num, "\\space", $title)
6336	} else {
6337	    $title = join(' ', $title, "\\space", $thm_num);
6338	}
6339
6340	if ($hfont) {
6341	    $title = join('',$O,++$global{'max_id'},$C,$hfont," "
6342		      , $title, $O,++$global{'max_id'},$C);
6343	    $title = &translate_environments($title);
6344	    $title = &translate_commands($title);
6345	} else {
6346	    $title = join('',"<B>",&translate_commands($title),"</B>");
6347	}
6348	$title =~ s/(\w)\.(\.\w)/$1$2/g;
6349    }
6350    # extract any name or label that may occur at the start
6351    s/^\s*(\\label(($O|$OP)\d+($C|$CP))([^<]*)\2)?\s*(\(([^\)]*)\))?/
6352	$label=$1; $text=$5; $name=$7 if ($7); ''/eo;
6353    if ($label) {
6354	$label = &anchor_label($text,$CURRENT_FILE,'');
6355	$label =~ s/$anchor_mark/$title/;
6356	$title = $label;
6357    }
6358    if ($name) {
6359	$name =~ s/^\s*|\s*$//g;
6360	$name = join('', " (", $name, ") ") if $name;
6361    }
6362    local($attribs, $border);
6363    if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
6364    elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
6365
6366    $_ = join('', $O,++$global{'max_id'},$C, $bfont
6367	    , " ", $_ ,$O,++$global{'max_id'},$C) if ($bfont);
6368
6369    my($cmd) = 'do_thm_'.$env;
6370    if (defined &$cmd) {
6371	$_ = &$cmd($ctr, $title, $_);
6372    } else {
6373	$_ = &translate_environments($_);
6374	$_ = &translate_commands($_);
6375    }
6376
6377    if ($thm_style =~ /margin/) {
6378	local($valign);
6379	$valign = ($NETSCAPE_HTML ? ' VALIGN="BASELINE"':'');
6380	if ($hfont) {
6381	    $thm_num = join('',$O,++$global{'max_id'},$C,$hfont," "
6382		      , $thm_num, $O,++$global{'max_id'},$C);
6383	    $thm_num = &translate_environments($thm_num);
6384	    $thm_num = &translate_commands($thm_num);
6385	} else {
6386	    $thm_num = join('',"<B>",&translate_commands($thm_num),"</B>");
6387	}
6388	$thm_num =~ s/(\w)\.(\.\w)/$1$2/g;
6389
6390	# code copied from  &make_table
6391	local($Tattribs);
6392	if ($attribs) {
6393	    if (!($attribs =~ /=/)) {
6394		$Tattribs = &parse_valuesonly($attribs,"TABLE");
6395	    } else {
6396		$Tattribs = &parse_keyvalues($attribs,"TABLE");
6397	    }
6398	    $Tattribs = ' '.$Tattribs if ($Tattribs);
6399	}
6400	$_ = join ('', "\n<P><DIV$env_id><TABLE"
6401		, (($border) ? " BORDER=\"$border\"" : '')
6402		, $Tattribs , ">\n<TR VALIGN=\"TOP\">"
6403		, "<TD$valign>", &translate_commands($thm_num)
6404		, "</TD>\n<TD>", $title, $name
6405		, (($thm_style =~ /break/)? "\n<BR>":" \&nbsp; \n")
6406		, $_ , "\n</TD></TR></TABLE></DIV>");
6407    } else {
6408	$_ = join('', "<P><DIV$env_id>"
6409		, $title, $name
6410		, (($thm_style =~ /break/)? "\n<BR>":" \&nbsp; \n")
6411		, $_
6412		,"</DIV><P></P>\n");
6413	if (($border||($attribs))&&($HTML_VERSION > 2.1 )) {
6414	    &make_table( $border, $attribs, '', '', '', $_ )
6415	} else { $_ }
6416    }
6417}
6418
6419# Modifies $_ in the caller and as a side-effect it modifies $next_def
6420# which is local to substitute_meta_cmds
6421sub get_next {
6422    local($what) = @_;
6423    local($next, $pat, $tmp);
6424    if ($what == 1) {
6425	($next, $tmp, $pat) = &get_next_argument;
6426    }
6427    elsif ($what == 2) {
6428	($next, $pat) = &get_next_tex_cmd;
6429    }
6430    elsif ($what == 3) {
6431	($next, $pat) = &get_next_def_arg;
6432    }
6433    elsif ($what == 4) {
6434	($next, $tmp, $pat) = &get_next_argument;
6435    }
6436    else {
6437	($next, $pat) =  &get_next_optional_argument;
6438    }
6439    do {
6440	$next_def .= &revert_to_raw_tex($pat) if $pat;
6441    } unless ($renewed); # don't add \renewcommand to preamble
6442#    $next =~ s/(^\s*)|(\s*$)//g unless ($what == 4); #don't lose white space on body
6443    $next =~ s/(^\s*)|(\s*$)//g unless ($what =~ /[14]/); #retain white space in body
6444    ($next, $pat);
6445}
6446
6447# The following get_next_<something> ARE ALL DESTRUCTIVE.
6448sub get_next_argument {
6449    local($next, $br_id, $pat);
6450    if (!(s/$next_pair_rx/$br_id=$1;$next=$2;$pat=$&;''/seo)) {
6451	print " *** Could not find argument for command \\$cmd ***\n";
6452	print "$_\n";
6453    };
6454    ($next, $br_id, $pat);
6455}
6456
6457sub get_next_pair_or_char_pr {
6458    local($next, $br_id, $pat, $epat);
6459    if ( /^\{([^\}]*)\}/o && (! $`)) {
6460	($next, $pat) = ($1, $&);
6461    } elsif ( (/^\s*([^\s\\<])/o && (! $`))) {
6462	($next, $pat) = ($1, $&);
6463    } elsif ( /$next_pair_pr_rx/o && (! $`)) {
6464	($next, $br_id, $pat) = ($2, $1, $&);
6465    };
6466    $epat = &escape_rx_chars($pat);
6467    s/$epat// if $pat;
6468    ($next, $br_id, $pat);
6469}
6470
6471sub get_next_optional_argument {
6472    local($next, $pat);
6473    s/$optional_arg_rx/$next=$1;$pat=$&;''/eo
6474	if (/\s*[[]/ && (! $`)); # if the first character is a [
6475    #remove trailing spaces and/or comments
6476    s/^($comment_mark(\d+\n?)?|$EOL)//gos;
6477
6478    # if  nested inside {}s  we need to get more tokens
6479    if ($pat) {
6480	# check for \item, indicating something has gone wrong
6481	if ($pat =~ /\\item\b/ ) {
6482	    print "\n*** optional argument badly formed:\n" . $pat . "\n\n";
6483	    $_ = $pat . $_;
6484	    return('','');
6485	}
6486	# check for being nested inside {}s
6487	local($found) = $pat;
6488	while ($found =~ s/$O(\d+)$C[\s\S]*$O\1$C//g) {
6489	    if ($found =~ /$O(\d+)$C/) {
6490		local($br_id) = $1;
6491		if (s/$O$br_id$C//) {
6492		    $found .= $`.$&;
6493		    $pat .= "]".$`.$&;
6494		    $next .= "]".$`.$&;
6495		    $_ = $';
6496		    s/^([^]]*)\]/$next.=$1;$pat.=$&;''/e;
6497		    $found .= $&;
6498		} else { last } # give up if no closing brace
6499	    }
6500	}
6501    } else {
6502	s/^\s*\[\]/$pat=$&;''/e; # This is not picked by $optional_arg_rx
6503    }
6504    ($next, $pat);
6505}
6506
6507#JCL(jcl-del) - use new form of $single_cmd_rx.
6508sub get_next_tex_cmd {
6509    local($next, $pat);
6510    s/^\s*\=?\s*$single_cmd_rx/$4/;
6511    ($next, $pat) = ($1.$2,"\\".$1.$2);
6512}
6513
6514sub get_next_def_arg {
6515    local($next, $pat);
6516
6517    # Sets is_simple_def for caller.  Start by turning it off, then
6518    # turn it on if we find one of the "simple" patterns.
6519
6520    # This has got to be hit-or-miss to an extent, given the
6521    # thoroughly incestuous relationship between the TeX macroprocessor
6522    # ('mouth') and typesetting back-end ('stomach').  Anything which
6523    # even does catcode hacking is going to lose BAD.
6524
6525    s/^\s*//so;			# Remove whitespace
6526
6527    $is_simple_def = 0;
6528
6529    # no arguments
6530
6531    if (/^$O/ && (! $`)) { $next=0; $pat=''; $is_simple_def=1; }
6532
6533    # 'simple' arguments
6534
6535    if (! $is_simple_def && /$tex_def_arg_rx/o && (! $`)) {
6536	s/$tex_def_arg_rx/$next=$1; $pat=$&; $is_simple_def=1; $2/seo; }
6537
6538    # MESSY arguments
6539
6540    if (! $is_simple_def) {
6541 	print "Arguments to $cmd are too complex ...\n";
6542	print "It will not be processed unless used in another environment\n";
6543	print "which is passed to LaTeX whole for processing.\n";
6544
6545	s/^[^<]*(<[^<]+)*<</$next=''; $pat=$&; $O/seo;
6546    }
6547
6548    $pat =~ s/$O$//so;
6549
6550    ($next, $pat);
6551}
6552
6553#### Key-value parsing added by RRM
6554#
6555#   This cleans-up the key-value pairs for a given tag,
6556#   by removing unnecessary spaces and commas, inserting quotes
6557#   around the value and puts a preceding space.
6558#   The key becomes upper-case, while the value becomes lower-case.
6559#   If specific `tags' are provided, then checking is done to verify
6560#   that the keys and values are valid for these tags, eliminating
6561#   any that are not; unmatched keys or values are handled as well.
6562#   If no tags are provided, then just a list of pairs is returned.
6563#
6564sub parse_keyvalues {
6565    local($_,@tags) = @_;
6566    local($key,$KEY,$attribs,$atts,%attributes)=('','','','');
6567
6568    # beware active " in german
6569    local($is_german);
6570    if (s/\&#34;/'/g) {
6571	$is_german=1;
6572	s/(^|[\s,=])(\&\#\d\d\d;)/$1'$2/g
6573    }
6574    local($saved) = &revert_to_raw_tex(&translate_commands($_));
6575    print "\nATTRIBS: $saved\n" if ($VERBOSITY > 6);
6576
6577    $saved =~ s/$percent_mark/%/g;
6578    $saved =~ s/((^|[\s,=])')\\\W\{(\w)\}/$1$3/g
6579	if $is_german;  #unwanted accents, from active "
6580    if (@tags) {
6581	foreach $tag (@tags) {
6582	    $_ = $saved;
6583	    local($name)= $tag."_attribs";
6584	    $taglist = $$name;
6585	    $name .= "_rx_list";
6586	    $taglist .= $$name;
6587	    $taglist =~ s/,,/,/;
6588#	    s/(^|,)\s*([a-zA-Z]+)\s*\=\s*"?([\#\%\w\d]+)"?\s*/$attributes{$2}="$3";''/eg;
6589#	    s/(^|,)\s*([a-zA-Z]+)\s*\=\s*(\"([^"]*)\"|\'([^\']*)\'|([#%\w\d]*))\s*/
6590#	    s/(^|,)\s*([a-zA-Z]+)\s*\=\s*(\"([^"]*)\"|\'([^\']*)\'|([#%&@;:+-\/\w\d]*))\s*/
6591	    s/(^|,)\s*([a-zA-Z]+)\s*\=\s*(\"([^"]*)\"|\'([^\']*)\'|([^<>,=\s]*))\s*/
6592		$attributes{$2}=($4?$4:($5?$5:$6));' '/eg;
6593	    foreach $key (keys %attributes){
6594		$KEY = $key;
6595		$KEY =~ tr/a-z/A-Z/;
6596		if ($taglist =~ /,$KEY,/i) {
6597		    local($keyname) = $tag."__".$KEY;
6598		    local($keyvalues) = '';
6599		    if ($$keyname) {
6600			$keyvalues = $$keyname;
6601			$atts = $attributes{$key};
6602			if ($keyvalues =~ /\,$atts\,/i ) {
6603#			    $atts =~ tr/A-Z/a-z/;
6604			    $attribs .= " $KEY=\"$atts\"";
6605			    print "\n$KEY=$atts " if ($VERBOSITY > 3);
6606			} else { &invalid_tag($tag,$KEY,$atts); }
6607		    } else {	# test for a regular expression
6608		        $keyname = $keyname."_rx";
6609			if ($$keyname) {
6610			    $keyvalues = $$keyname;
6611			    $atts = $attributes{$key};
6612			    if ($atts =~ /$keyvalues/) {
6613#				$atts =~ tr/A-Z/a-z/;
6614				$attribs .= " $KEY=\"$atts\"";
6615				print "\n$KEY=$atts " if ($VERBOSITY > 3);
6616			    } else { &invalid_tag($tag,$KEY,$atts) }
6617			} else {
6618			    $atts = $attributes{$key};
6619#			    $atts =~ tr/A-Z/a-z/;
6620			    $attribs .= " $KEY=\"$atts\"";
6621			    print "\n$KEY=$atts " if ($VERBOSITY > 3);
6622			}
6623		    }
6624		} else {
6625		    print "\n$key not in $taglist for $tag" if ($VERBOSITY > 3);
6626		}
6627	    }
6628	}
6629        s/(^|\s,)\'([^\s,]*)\'(\s|$)/$1$2 /g if $is_german;
6630	$attribs .= &parse_valuesonly($_,@tags);
6631    } else {
6632	# with no tags provided, just list the key-value pairs
6633	$_ = $saved;
6634	s/\s*(\w+)\s*=\s*\"?(\w+)\"?\s*,?/$attributes{$1}=$2;''/eg;
6635	foreach $key (keys %attributes){
6636	    $KEY = $key;
6637	    $KEY =~ tr/a-z/A-Z/;
6638	    $atts = $attributes{$key};
6639	    $atts =~ tr/A-Z/a-z/;
6640	    $attribs .= " $KEY=\"$atts\"";
6641	}
6642    }
6643    $attribs;
6644}
6645
6646sub invalid_tag {
6647    local($tag,$key,$value) = @_;
6648    &write_warnings("$key=$value is an invalid value in the <$tag> tag\n");
6649}
6650
6651# RRM
6652#   This creates key-value pairs from values only,
6653#   by checking whether the data matches any key to the provided tags.
6654#   Only the first match found is retained.
6655#   Attributes with no values are also recognised here.
6656#
6657sub parse_valuesonly {
6658    local($values,@tags) = @_;
6659    local($i,$tag,$key,$KEY,$attribs,$atts)=(0,'','','','','');
6660    local($saved) = &revert_to_raw_tex(&translate_commands($values));
6661    $saved =~ s/$percent_mark/%/g;
6662    foreach $tag (@tags) {
6663	local($name)= $tag."_attribs";
6664	$taglist = $$name;
6665	$values = $saved;
6666        $values =~ s/\s*\"?([^,\s\"]+)\"?\s*,?/$i++;$attributes{$i}=$1;''/eg;
6667        local($j) = 0;
6668	while ($j < $i) {
6669	    $j++;
6670	    $key = $attributes{$j};
6671	    if ($taglist =~ /,$key,/i) {
6672		$KEY = $key;
6673		$KEY =~ tr/a-z/A-Z/;
6674		$attribs .= " $KEY";
6675		print " $KEY" if ($VERBOSITY > 3);
6676	    } else {
6677		$atts = $attributes{$j};
6678		$key = &find_attribute($key,$tag);
6679	        if ($key) {
6680		    $KEY = $key;
6681		    $KEY =~ tr/a-z/A-Z/;
6682		    $atts =~ tr/A-Z/a-z/;
6683	            $attribs .= " $KEY=\"$atts\"";
6684		    print " $KEY = $atts" if ($VERBOSITY > 3);
6685		} else { }
6686	    }
6687	}
6688    }
6689    $attribs;
6690}
6691
6692# RRM
6693#   Extracts key-value pairs using a supplied (comma-separated) list.
6694#   When no list is given, it checks for a pre-defined list for the tag.
6695#
6696sub extract_attributes {
6697    local($tag,$taglist,$_) = @_;
6698    local($key,$attribs,$unused,%attributes);
6699    if (! ($taglist)) {
6700	local($name) = "$tag"."_attribs";
6701	if ($$name) { $taglist = $$name }
6702    }
6703    s/\s*(\w+)\s*=\s*\"?(\w+)\"?\s*,?/$attributes{$1}=$2;''/eg;
6704    foreach $key (keys %attributes){
6705	if ($taglist =~ /\,$key\,/) {
6706	    $attribs .= " $key=\"$attributes{$key}\"";
6707	    &write_warnings("valid attribute $key for $tag\n");
6708	} else {
6709	    &write_warnings("unknown attribute $key for $tag\n");
6710	    $unused .= " $key=\"$attributes{$key}\"";
6711	}
6712    }
6713    ($attribs,$unused);
6714}
6715
6716# RRM
6717#   Finds the attribute of a given tag, for which a given value is valid.
6718#   Requires variables: <tag>_<key> to be a comma-separated list of keys.
6719#   So far it cannot recognise data-types, only names.
6720#
6721sub find_attribute {
6722    local($key,$attrib,$tag) = ('',@_);
6723    local($name) = $tag."_attribs";
6724    local($attrib_list)=$$name;
6725    if ($attrib_list) {
6726	$attrib_list =~ s/^\,//o;
6727	$attrib_list =~ s/\,$//o;
6728	local(@keys) = split(',',$attrib_list);
6729	local($attrib_vals) = '';
6730	foreach $key (@keys) {
6731	    $name = $tag."__".$key;
6732	    $attrib_vals = $$name;
6733	    return ($key) if ($attrib_vals =~ /\,$attrib\,/i );
6734	}
6735    }
6736    $name = $tag."_attribs_rx_list";
6737    $attrib_list=$$name;
6738    if (!($attrib_list)) { return(); }
6739    $attrib_list =~ s/^\,//o;
6740    $attrib_list =~ s/\,$//o;
6741    @keys = split(',',$attrib_list);
6742    foreach $key (@keys) {
6743	next if ($attribs =~ / $key=/);
6744	$name = $tag."__".$key."_rx";
6745	$attrib_vals = $$name;
6746	if ( $attrib =~ /^$attrib_vals$/ ) {
6747	    return ($key);
6748	}
6749    }
6750    0;
6751}
6752
6753# in case \HTML is defined differently in packages
6754sub do_cmd_HTML { &do_cmd_HTMLcode(@_) }
6755
6756sub do_cmd_HTMLcode {
6757    local($_) = @_;
6758    local($tag,$attribs,$dum);
6759    local($attribs, $dum) = &get_next_optional_argument;
6760    $tag = &missing_braces unless (
6761	(s/$next_pair_pr_rx/$tag = $2;''/eo)
6762	||(s/$next_pair_rx/$tag = $2;''/eo));
6763    $tag = &translate_commands($tag) if ($tag =~ /\\/);
6764    if (! $tag) {
6765	print "*** no tag given with \\HTML command, ignoring it";
6766	return($_);
6767    }
6768    local($afterHTML) = $_;
6769    local($value,$TAGattribs,$etag);
6770    if (defined $unclosed_tags_list{$tag}) {
6771    } elsif (defined $closed_tags_list{$tag}) {
6772	$value = &missing_braces unless (
6773	    (s/$next_pair_pr_rx/$value = $2;''/eo)
6774	    ||(s/$next_pair_rx/$value = $2;''/eo));
6775	$etag = "</$tag>";
6776	$afterHTML = $_;
6777    } else {
6778	print "\n*** <$tag> is not a valid tag for HTML $HTML_VERSION";
6779	print "\n rejecting: \\HTML".(($attribs)? "[$attribs]" : '')."{$tag}";
6780	return $_ ;
6781    }
6782    if ($dum) {
6783	$attribs = &translate_commands($attribs) if ($attribs=~/\\/);
6784        if ($attribs) {
6785            if (!($attribs =~ /=/)) {
6786                $TAGattribs = &parse_valuesonly($attribs,$tag);
6787            } else {
6788                $TAGattribs = &parse_keyvalues($attribs,$tag);
6789            }
6790        }
6791    } else { }  # default if no [...]
6792    local($needed) = join(','
6793	    , $closed_tags_list{$tag},$unclosed_tags_list{$tag});
6794    $needed =~ s/,,/,/g; $needed =~ s/^,|,$//g;
6795    if ($TAGattribs) {
6796	if ($needed) {
6797	    $needed =~ s/,,/,/g;
6798	    local($this, @needed);
6799	    (@needed) = split(',',$needed);
6800	    foreach $this (@needed) {
6801		next unless ($this);
6802		next if ($TAGattribs =~ /\b$this\b/);
6803		print "\n*** attribute $this required for <$tag> ***";
6804		print "\n rejecting: \\HTML".(($attribs)? "[$attribs]" : '')."{$tag}";
6805		return($value.$afterHTML);
6806	    }
6807	}
6808	$value = &translate_environments($value);
6809	$value = &translate_commands($value) if ($value =~ /\\/);
6810	$_ = join('', "<$tag", $TAGattribs, ">", $value, $etag);
6811   } elsif ($needed) {
6812	print STDOUT "\n*** attributes $needed are required for <$tag> ***";
6813	return($value.$after);
6814    } elsif ($value) {
6815	$value = &translate_environments($value);
6816	$value = &translate_commands($value) if ($value =~ /\\/);
6817	$_ = join('', "<$tag>", $value, $etag);
6818    } else {
6819	$_ = join('', "<$tag>", $etag);
6820    }
6821    $_.$afterHTML;
6822}
6823
6824sub do_cmd_HTMLget {
6825    local($_) = @_;
6826    local($which,$value,$hash,$dummy);
6827    local($hash, $dummy) = &get_next_optional_argument;
6828    $which = &missing_braces unless (
6829	(s/$next_pair_pr_rx/$which = $2;''/eo)
6830	||(s/$next_pair_rx/$which = $2;''/eo));
6831    if ($hash) {
6832	local($tmp) = "\%$hash";
6833	if (eval "defined \%{$hash}") { $! = '';
6834	    $value = ${$hash}{'$which'};
6835	} else { print "\nhash: \%$hash not defined" }
6836    } elsif ($which) {
6837	$value = ${$which};
6838    }
6839    $value.$_;
6840}
6841
6842sub do_cmd_HTMLset {
6843    local($_) = @_;
6844    local($which,$value,$hash,$dummy);
6845    local($hash, $dummy) = &get_next_optional_argument;
6846    $which = &missing_braces unless (
6847	(s/$next_pair_pr_rx/$which = $2;''/eo)
6848	||(s/$next_pair_rx/$which = $2;''/eo));
6849    $value = &missing_braces unless (
6850	(s/$next_pair_pr_rx/$value = $2;''/eo)
6851	||(s/$next_pair_rx/$value = $2;''/eo));
6852    if ($hash) {
6853	local($tmp) = "\%$hash";
6854	if (eval "defined \%{$hash}") { $! = '';
6855#	    eval "\$$hash{'$which'} = \"$value\";";
6856	    ${$hash}{'$which'} = $value;
6857	    print "\nHTMLset failed: $! " if ($!);
6858	} else { print "\nhash: \%$hash not defined" }
6859    } elsif ($which) { $! = '';
6860	eval "\${$which} = \"$value\";";
6861	print "\nHTMLset failed: $! " if ($!);
6862    }
6863    $_;
6864}
6865
6866sub do_cmd_HTMLsetenv { &do_cmd_HTMLset(@_) }
6867
6868####
6869
6870
6871# Appends $next_def to the preamble if it is not already there.
6872sub add_to_preamble {
6873    local($type, $next_def) = @_;
6874    local($name);
6875    if ($type =~ /def|include|special|graphicspath/) {
6876        local($pat) = &escape_rx_chars ($next_def);
6877#	$preamble .= $next_def . "\n" unless ($preamble =~ /$pat/);
6878	push(@preamble, $pat);
6879    }
6880    elsif ($type =~ /command|environment|theorem|counter/) {
6881	push(@preamble, $next_def );
6882    }
6883    else {
6884	($name) = $next_def =~ /$marker\s*({[^}]+})/; # matches type{name}
6885	$name = &escape_rx_chars($name);
6886#	$preamble .= $next_def . "\n" unless ($preamble =~ /$marker\s*$name/);
6887	push(@preamble, $name );
6888    }
6889}
6890
6891sub make_latex{
6892# This is the environment in which to process constructs that cannot be
6893# translated to HTML.
6894# The environment tex2html_wrap will be wrapped around any shorthand
6895# environments (e.g. $, \(, \[).
6896# The tex2html_wrap environment will be treated as an unrecognised
6897# evironment by the translator and its contents (i.e. the 'shorthand'
6898# environment) will be passed to latex for processing as usual.
6899    local($contents) = @_;
6900    local($preamble) = $preamble;
6901    local($aux_preamble) = $aux_preamble;
6902    while ($preamble =~ s/^(\@.*\n)/$prelatex .= $1;''/e) {}
6903    print "\nPRE-LATEX: $prelatex" if (($prelatex)&&($VERBOSITY > 1));
6904
6905    %newed_commands =
6906	 ( 'newedcommand' , 'newcommand'
6907	 , 'renewedcommand' , 'renewcommand'
6908	 , 'providedcommand' , 'providecommand'
6909	 , 'newedenvironment' , 'newenvironment'
6910	 , 'newedboolean' , 'newboolean'
6911	 , 'newedcounter' , 'newcounter'
6912	 , 'newedtheorem' , 'newtheorem'
6913	 , 'newedfont' , 'newfont' , 'newedif', 'newif'
6914	 );
6915
6916
6917    # Make the @ character a normal letter ...
6918    $preamble =~ s/\\par([^A-Za-z]|$)/\n$1/g;
6919    $preamble =~ s/(\\document(class|style)(\[[^\]]+\])?\{\w+\})/$1\n/;
6920    $preamble =~ s/(\\document(class|style)(\[[^\]]+\])?\{\w+\})/$1\n\\RequirePackage{ifthen}\n/
6921			 unless ($preamble =~/\{ifthen\}/);
6922#    $preamble =~ s/(\\document(class|style)(\[[^\]]+\])?\{\w+\})/$1\n\\makeatletter/;
6923    # ... and make it special again after the preamble
6924    # remove the  \begin/\end  for  tex2html_nowrap and tex2html_deferred environments
6925    $preamble =~s/\\(begin|end)\s*\{(tex2html_(nowrap|deferred|nomath|preform)[_a-z]*|imagesonly)\}//g;
6926    $preamble =~s/\n?\s?<tex2html_(end)?file>\#[^#]*\#//mg;
6927
6928    $preamble = "\\documentclass\{article\}%\n\\usepackage{html}\n\\usepackage[dvips]{color}\n"
6929	unless ($preamble);
6930    if (($LATEX_DUMP)&&(!($preamble =~ /\\usepackage\{ldump\}/))) {
6931	# MRO: replaced $* with /m
6932	$preamble =~ s/(\\document(class|style)[^\n]*\n)/$1\\usepackage\{ldump\}\n/m;
6933    }
6934    if ($preamble =~ /pstricks/) {
6935	if ($LOAD_LATEX_COLOR) {
6936	    $LOAD_LATEX_COLOR =~ s/\{color\}/\{pstcol\}/ ;
6937	} else {
6938	    $LOAD_LATEX_COLOR = "\n\\usepackage[dvips]{pstcol}\n";
6939	}
6940    } else {
6941	$LOAD_LATEX_COLOR = "\n\\usepackage[dvips]{color}";
6942    }
6943    $LATEX_COLOR = "\\pagecolor[gray]{.85}\\nobreak " unless $LATEX_COLOR;
6944    if ($preamble =~ /(^|\s*[^%])\s*\\documentstyle/) {
6945	# \usepackage is invalid in LaTeX 2.09 and LaTeX-2e compatibility mode
6946	$LATEX_COLOR = ''; $LOAD_LATEX_COLOR = '';
6947	# ... so is \providecommand
6948	$preamble =~ s/\\documentstyle[^{]*\{[^}]*\}\n?/
6949		$&."\n\\let\\providecommand\\newcommand\n"/eo;
6950    }
6951
6952    $preamble .= $LOAD_LATEX_COLOR."\n" unless ($preamble =~ /[,\{]color[,\}]/);
6953    $preamble .= "\n\n".$LATEX_COLOR."\n" unless ($preamble =~ /\\pagecolor/);
6954    do {
6955	if ($ISOLATIN_CHARS) { $INPUTENC = $INPUTENC || 'latin1' };
6956	$preamble .= "\n\\usepackage[".$INPUTENC."]\{inputenc\}\n";
6957	} unless ($preamble =~ /\\inputenc/);
6958
6959    $aux_preamble = '' unless (($aux_preamble)&&($contents =~ /\\(hyper)?(ref|cite)/));
6960
6961    $preamble =~ s/\\((provide|(re)?new)ed(command|counter|if|theorem|environment|font))\b/
6962			 "%\n\\".$newed_commands{$1}/eg;
6963    $preamble =~ s/(\\(re)?newcommand)\s*(\{(\\?)(\}|[^\}]+)\})/
6964		$1.(($4)? $3 : "{\\".$5.'}' )/eg;
6965
6966    $preamble =~s/$verbatim_mark(imagesonly)(\d+)#/$verbatim{$2}/eg; # for images.tex only
6967
6968#    local($key);
6969#    foreach $key (keys %newed_commands) {
6970#	$preamble .= "\n\\let\\$key\\".$newed_commands{$key}
6971#    }
6972    $preamble .= "\n";
6973
6974    local($paperwidth) = '';
6975    if ($PAPERSIZE) { $paperwidth = &adjust_textwidth($PAPERSIZE); }
6976    else { $paperwidth = &adjust_textwidth("a5"); }
6977    local($kern) = ($EXTRA_IMAGE_SCALE ? $EXTRA_IMAGE_SCALE/2 : ".5" );
6978    $kern = $kern * $MATH_SCALE_FACTOR;
6979    $prelatex . ($DEBUG ? "\\nonstopmode" : "\\batchmode") .
6980    "\n$preamble\n\n\\makeatletter\n$aux_preamble\n" .
6981    "\\makeatletter\n\\count\@=\\the\\catcode`\\_ \\catcode`\\_=8 \n" .
6982    "\\newenvironment{tex2html_wrap}{}{}%\n" .
6983    "\\catcode`\\<=12\\catcode`\\_=\\count\@\n" .
6984    "\\newcommand{\\providedcommand}[1]{\\expandafter\\providecommand\\csname #1\\endcsname}%\n" .
6985    "\\newcommand{\\renewedcommand}[1]{\\expandafter\\providecommand\\csname #1\\endcsname{}%\n" .
6986    "  \\expandafter\\renewcommand\\csname #1\\endcsname}%\n" .
6987    "\\newcommand{\\newedenvironment}[1]{\\newenvironment{#1}{}{}\\renewenvironment{#1}}%\n" .
6988    "\\let\\newedcommand\\renewedcommand\n" .
6989    "\\let\\renewedenvironment\\newedenvironment\n" .
6990    "\\makeatother\n" .
6991    "\\let\\mathon=\$\n\\let\\mathoff=\$\n" .
6992    "\\ifx\\AtBeginDocument\\undefined \\newcommand{\\AtBeginDocument}[1]{}\\fi\n" .
6993    "\\newbox\\sizebox\n" . "$paperwidth" .
6994    "\\newwrite\\lthtmlwrite\n" . "\\makeatletter\n" .
6995    "\\let\\realnormalsize=\\normalsize\n\\global\\topskip=2sp\n\\def\\preveqno{}" .
6996    "\\let\\real\@float=\\\@float \\let\\realend\@float=\\end\@float\n" .
6997    "\\def\\\@float{\\let\\\@savefreelist\\\@freelist\\real\@float}\n" .
6998#    "\\def\\\@float{\\\@dbflt}\n" .
6999    "\\def\\liih\@math{\\ifmmode\$\\else\\bad\@math\\fi}\n" .
7000    "\\def\\end\@float{\\realend\@float\\global\\let\\\@freelist\\\@savefreelist}\n" .
7001    "\\let\\real\@dbflt=\\\@dbflt \\let\\end\@dblfloat=\\end\@float\n" .
7002    "\\let\\\@largefloatcheck=\\relax\n" .
7003    "\\let\\if\@boxedmulticols=\\iftrue\n" .
7004    "\\def\\\@dbflt{\\let\\\@savefreelist\\\@freelist\\real\@dbflt}\n" .
7005    "\\def\\adjustnormalsize{\\def\\normalsize{\\mathsurround=0pt \\realnormalsize\n" .
7006    " \\parindent=0pt\\abovedisplayskip=0pt\\belowdisplayskip=0pt}%\n" .
7007    " \\def\\phantompar{\\csname par\\endcsname}\\normalsize}%\n" .
7008    "\\def\\lthtmltypeout#1{{\\let\\protect\\string \\immediate\\write\\lthtmlwrite{#1}}}%\n" .
7009    "\\newcommand\\lthtmlhboxmathA{\\adjustnormalsize\\setbox\\sizebox=\\hbox\\bgroup\\kern.05em }%\n" .
7010    "\\newcommand\\lthtmlhboxmathB{\\adjustnormalsize\\setbox\\sizebox=\\hbox to\\hsize\\bgroup\\hfill }%\n" .
7011    "\\newcommand\\lthtmlvboxmathA{\\adjustnormalsize\\setbox\\sizebox=\\vbox\\bgroup %\n".
7012    " \\let\\ifinner=\\iffalse \\let\\)\\liih\@math }%\n" .
7013    "\\newcommand\\lthtmlboxmathZ{\\\@next\\next\\\@currlist{}{\\def\\next{\\voidb\@x}}%\n" .
7014#    " \\expandafter\\box\\next\\edef\\next{\\egroup\\def\\noexpand\\thiseqn{\\theequation}}\\next}%\n" .
7015    " \\expandafter\\box\\next\\egroup}%\n" .
7016    "\\newcommand\\lthtmlmathtype[1]{\\gdef\\lthtmlmathenv{#1}}%\n" .
7017    "\\newcommand\\lthtmllogmath{\\dimen0\\ht\\sizebox \\advance\\dimen0\\dp\\sizebox\n" .
7018    "  \\ifdim\\dimen0>.95\\vsize\n" .  "   \\lthtmltypeout{%\n" .
7019    "*** image for \\lthtmlmathenv\\space is too tall at \\the\\dimen0, reducing to .95 vsize ***}%\n" .
7020    "   \\ht\\sizebox.95\\vsize \\dp\\sizebox\\z\@ \\fi\n" .  "  \\lthtmltypeout{l2hSize %\n" .
7021    ":\\lthtmlmathenv:\\the\\ht\\sizebox::\\the\\dp\\sizebox::\\the\\wd\\sizebox.\\preveqno}}%\n" .
7022    "\\newcommand\\lthtmlfigureA[1]{\\let\\\@savefreelist\\\@freelist
7023       \\lthtmlmathtype{#1}\\lthtmlvboxmathA}%\n" .
7024    "\\newcommand\\lthtmlpictureA{\\bgroup\\catcode`\\_=8 \\lthtmlpictureB}%\n" .
7025    "\\newcommand\\lthtmlpictureB[1]{\\lthtmlmathtype{#1}\\egroup
7026       \\let\\\@savefreelist\\\@freelist \\lthtmlhboxmathB}%\n" .
7027    "\\newcommand\\lthtmlpictureZ[1]{\\hfill\\lthtmlfigureZ}%\n" .
7028    "\\newcommand\\lthtmlfigureZ{\\lthtmlboxmathZ\\lthtmllogmath\\copy\\sizebox
7029       \\global\\let\\\@freelist\\\@savefreelist}%\n" .
7030    "\\newcommand\\lthtmldisplayA{\\bgroup\\catcode`\\_=8 \\lthtmldisplayAi}%\n" .
7031    "\\newcommand\\lthtmldisplayAi[1]{\\lthtmlmathtype{#1}\\egroup\\lthtmlvboxmathA}%\n" .
7032    "\\newcommand\\lthtmldisplayB[1]{\\edef\\preveqno{(\\theequation)}%\n" .
7033    "  \\lthtmldisplayA{#1}\\let\\\@eqnnum\\relax}%\n" .
7034    "\\newcommand\\lthtmldisplayZ{\\lthtmlboxmathZ\\lthtmllogmath\\lthtmlsetmath}%\n" .
7035    "\\newcommand\\lthtmlinlinemathA{\\bgroup\\catcode`\\_=8 \\lthtmlinlinemathB}\n" .
7036    "\\newcommand\\lthtmlinlinemathB[1]{\\lthtmlmathtype{#1}\\egroup\\lthtmlhboxmathA\n" .
7037    "  \\vrule height1.5ex width0pt }%\n" .
7038    "\\newcommand\\lthtmlinlineA{\\bgroup\\catcode`\\_=8 \\lthtmlinlineB}%\n" .
7039    "\\newcommand\\lthtmlinlineB[1]{\\lthtmlmathtype{#1}\\egroup\\lthtmlhboxmathA}%\n" .
7040    "\\newcommand\\lthtmlinlineZ{\\egroup\\expandafter\\ifdim\\dp\\sizebox>0pt %\n" .
7041    "  \\expandafter\\centerinlinemath\\fi\\lthtmllogmath\\lthtmlsetinline}\n" .
7042    "\\newcommand\\lthtmlinlinemathZ{\\egroup\\expandafter\\ifdim\\dp\\sizebox>0pt %\n" .
7043    "  \\expandafter\\centerinlinemath\\fi\\lthtmllogmath\\lthtmlsetmath}\n" .
7044    "\\newcommand\\lthtmlindisplaymathZ{\\egroup %\n" .
7045    "  \\centerinlinemath\\lthtmllogmath\\lthtmlsetmath}\n" .
7046    "\\def\\lthtmlsetinline{\\hbox{\\vrule width.1em \\vtop{\\vbox{%\n" .
7047    "  \\kern.1em\\copy\\sizebox}\\ifdim\\dp\\sizebox>0pt\\kern.1em\\else\\kern.3pt\\fi\n" .
7048    "  \\ifdim\\hsize>\\wd\\sizebox \\hrule depth1pt\\fi}}}\n" .
7049    "\\def\\lthtmlsetmath{\\hbox{\\vrule width.1em\\kern-.05em\\vtop{\\vbox{%\n" .
7050    "  \\kern.1em\\kern$kern pt\\hbox{\\hglue.17em\\copy\\sizebox\\hglue$kern pt}}\\kern.3pt%\n" .
7051    "  \\ifdim\\dp\\sizebox>0pt\\kern.1em\\fi \\kern$kern pt%\n" .
7052    "  \\ifdim\\hsize>\\wd\\sizebox \\hrule depth1pt\\fi}}}\n" .
7053    "\\def\\centerinlinemath{%\n" .
7054    "  \\dimen1=\\ifdim\\ht\\sizebox<\\dp\\sizebox \\dp\\sizebox\\else\\ht\\sizebox\\fi\n" .
7055    "  \\advance\\dimen1by.5pt \\vrule width0pt height\\dimen1 depth\\dimen1 \n".
7056    " \\dp\\sizebox=\\dimen1\\ht\\sizebox=\\dimen1\\relax}\n\n" .
7057    "\\def\\lthtmlcheckvsize{\\ifdim\\ht\\sizebox<\\vsize \n" .
7058    "  \\ifdim\\wd\\sizebox<\\hsize\\expandafter\\hfill\\fi \\expandafter\\vfill\n" .
7059    "  \\else\\expandafter\\vss\\fi}%\n" .
7060    "\\providecommand{\\selectlanguage}[1]{}%\n" .
7061#    "\\def\\\@enddocumenthook{\\ifnum\\count0>1 \\ifvoid\\\@cclv\\penalty-\\\@MM\\fi\\fi}\n" .
7062    "\\makeatletter \\tracingstats = 1 \n"
7063    . ($itrans_loaded ? $itrans_tex_mod : '')
7064    . $LaTeXmacros . "\n"  # macros defined in extension files
7065#    "\\usepackage{lthimages}\n" .
7066    . (($LATEX_DUMP)? "\\latexdump\n" : '')
7067    . "\n\\begin{document}\n" .
7068    "\\pagestyle{empty}\\thispagestyle{empty}\\lthtmltypeout{}%\n" .
7069    "\\lthtmltypeout{latex2htmlLength hsize=\\the\\hsize}\\lthtmltypeout{}%\n" .
7070    "\\lthtmltypeout{latex2htmlLength vsize=\\the\\vsize}\\lthtmltypeout{}%\n" .
7071    "\\lthtmltypeout{latex2htmlLength hoffset=\\the\\hoffset}\\lthtmltypeout{}%\n" .
7072    "\\lthtmltypeout{latex2htmlLength voffset=\\the\\voffset}\\lthtmltypeout{}%\n" .
7073    "\\lthtmltypeout{latex2htmlLength topmargin=\\the\\topmargin}\\lthtmltypeout{}%\n" .
7074    "\\lthtmltypeout{latex2htmlLength topskip=\\the\\topskip}\\lthtmltypeout{}%\n" .
7075    "\\lthtmltypeout{latex2htmlLength headheight=\\the\\headheight}\\lthtmltypeout{}%\n" .
7076    "\\lthtmltypeout{latex2htmlLength headsep=\\the\\headsep}\\lthtmltypeout{}%\n" .
7077    "\\lthtmltypeout{latex2htmlLength parskip=\\the\\parskip}\\lthtmltypeout{}%\n" .
7078    "\\lthtmltypeout{latex2htmlLength oddsidemargin=\\the\\oddsidemargin}\\lthtmltypeout{}%\n" .
7079    "\\makeatletter\n" .
7080    "\\if\@twoside\\lthtmltypeout{latex2htmlLength evensidemargin=\\the\\evensidemargin}%\n" .
7081    "\\else\\lthtmltypeout{latex2htmlLength evensidemargin=\\the\\oddsidemargin}\\fi%\n" .
7082    "\\lthtmltypeout{}%\n" .
7083    "\\makeatother\n\\setcounter{page}{1}\n\\onecolumn\n\n% !!! IMAGES START HERE !!!\n\n"
7084    . "$contents\n"
7085#    "\\clearpage\n" .
7086    . "\\end{document}";
7087}
7088
7089sub adjust_textwidth {
7090    local($_) = @_;
7091    local($width,$length) = ('','');
7092    if (/a4/) {$width = 595; $length= 842; }
7093    elsif (/letter/) {$width = 612; $length= 792; }
7094    elsif (/legal/) {$width = 612; $length= 1008; }
7095    elsif (/note/) {$width = 540; $length= 720; }
7096    elsif (/b5/) {$width = 501; $length= 709; }
7097    elsif (/a5/) {$width = 421; $length= 595; }
7098    elsif (/a6/) {$width = 297; $length= 421; }
7099    elsif (/a7/) {$width = 210; $length= 297; }
7100    elsif (/a8/) {$width = 148; $length= 210; }
7101    elsif (/a9/) {$width = 105; $length= 148; }
7102    elsif (/a10/) {$width = 74; $length= 105; }
7103    elsif (/b4/) {$width = 709; $length= 1002; }
7104    elsif (/a3/) {$width = 842; $length= 1190; }
7105    elsif (/b3/) {$width = 1002; $length= 1418; }
7106    elsif (/a2/) {$width = 1190; $length= 1684; }
7107    elsif (/b2/) {$width = 1418; $length= 2004; }
7108    elsif (/a1/) {$width = 1684; $length= 2380; }
7109    elsif (/b1/) {$width = 2004; $length= 2836; }
7110    elsif (/a0/) {$width = 2380; $length= 3368; }
7111    elsif (/b0/) {$width = 2836; $length= 4013; }
7112    else {
7113	&write_warnings("\nPAPERSIZE: $_ unknown, using LaTeX's size.");
7114	return();
7115     }
7116    if ($width > 500) { $width = $width - 144; $length = $length - 288; }
7117    elsif ($width > 250) { $width = $width - 72; $length = $length - 144; }
7118    elsif ($width > 125) { $width = $width - 36; $length = $length - 72; }
7119#    "\\setlength{\\oddsidemargin}{0pt}\n" .
7120#    "\\setlength{\\evensidemargin}{0pt}\n" .
7121#    "\\setlength{\\parskip}{0pt}\\setlength{\\topskip}{0pt}\n" .
7122    "\\setlength{\\hoffset}{0pt}\\setlength{\\voffset}{0pt}\n" .
7123    "\\addtolength{\\textheight}{\\footskip}\\setlength{\\footskip}{0pt}\n" .
7124    "\\addtolength{\\textheight}{\\topmargin}\\setlength{\\topmargin}{0pt}\n" .
7125    "\\addtolength{\\textheight}{\\headheight}\\setlength{\\headheight}{0pt}\n" .
7126    "\\addtolength{\\textheight}{\\headsep}\\setlength{\\headsep}{0pt}\n" .
7127    "\\setlength{\\textwidth}{${width}pt}\n"
7128    . (($length > 500) ? "\\setlength{\\textheight}{${length}pt}\n" : '')
7129}
7130
7131# Given the depth of the current sectioning declaration and the current
7132# section numbers it returns the new section numbers.
7133# It increments the $depth-ieth element of the @curr_sec_id list and
7134# 0's the elements after the $depth-ieth element.
7135sub new_level {
7136    local($depth, @curr_sec_id) = @_;
7137    $depth = $section_commands{$outermost_level} unless $depth;
7138    local($i) = 0;
7139    grep( do { if ($i == $depth) {$_++ ;}
7140	       elsif ($i > $depth) {$_ = 0 ;};
7141	       $i++;
7142	       0;
7143	   },
7144	 @curr_sec_id);
7145    @curr_sec_id;
7146}
7147
7148sub make_head_and_body {
7149    local($title,$body,$before_body) = @_;
7150    local($DTDcomment) = '';
7151    local($version,$isolanguage) = ($HTML_VERSION, 'EN');
7152    local(%isolanguages) = (  'english',  'EN'   , 'USenglish', 'EN-US'
7153			    , 'original', 'EN'   , 'german'   , 'DE'
7154			    , 'austrian', 'DE-AT', 'french'   , 'FR'
7155			    , 'spanish',  'ES'
7156			    , %isolanguages );
7157#    $isolanguage = $isolanguages{$default_language};  # DTD is in EN
7158    $isolanguage = 'EN' unless $isolanguage;
7159#JCL(jcl-tcl)
7160# clean title as necessary
7161# the first words ... is a kludge, but reasonable (or not?)
7162#RRM: why bother? --- as long as it is pure text.
7163    $title = &purify($title,1);
7164    eval("\$title = ". $default_title ) unless ($title);
7165#    $title = &get_first_words($title, $WORDS_IN_NAVIGATION_PANEL_TITLES);
7166
7167    # allow user-modification of the <TITLE> tag; thanks Dan Young
7168    if (defined &custom_TITLE_hook) {
7169	$title = &custom_TITLE_hook($title, $toc_sec_title);
7170    }
7171
7172    if ($DOCTYPE =~ /\/\/[\w\.]+\s*$/) { # language spec included
7173	$DTDcomment = '<!DOCTYPE HTML PUBLIC "'. $DOCTYPE .'"';
7174    } else {
7175	$DTDcomment = '<!DOCTYPE HTML PUBLIC "'. $DOCTYPE .'//'
7176	    . ($ISO_LANGUAGE ? $ISO_LANGUAGE : $isolanguage) . '"'
7177    }
7178    $DTDcomment .= ($PUBLIC_REF ? "\n  \"".$PUBLIC_REF.'"' : '' ) . '>'."\n";
7179
7180    $STYLESHEET = $FILE.".css" unless defined($STYLESHEET);
7181
7182    my ($this_charset) = $charset;
7183    if ($USE_UTF) { $charset = $utf8_str; $NO_UTF = ''; }
7184    if (!$charset && $CHARSET) {
7185	$this_charset = $CHARSET;
7186	$this_charset =~ s/_/\-/go;
7187    }
7188    if ($NO_UTF && $charset =~/utf/) {
7189	$this_charset = $PREV_CHARSET||$CHARSET;
7190	$this_charset =~ s/_/\-/go;
7191    }
7192
7193    join("\n", (($DOCTYPE)? $DTDcomment : '' )
7194	,"<!--Converted with LaTeX2HTML $TEX2HTMLVERSION"
7195	, "original version by:  Nikos Drakos, CBLU, University of Leeds"
7196	, "* revised and updated by:  Marcus Hennecke, Ross Moore, Herb Swan"
7197	, "* with significant contributions from:"
7198	, "  Jens Lippmann, Marek Rouchal, Martin Wilck and others"
7199	    . " -->\n<HTML>\n<HEAD>\n<TITLE>".$title."</TITLE>"
7200	, &meta_information($title)
7201	,  ($CHARSET && $HTML_VERSION ge "2.1" ?
7202	      "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=$this_charset\">"
7203	      : "" )
7204	, $LATEX2HTML_META
7205	, ($BASE ? "<BASE HREF=\"$BASE\">" : "" )
7206	, $STYLESHEET_CASCADE
7207	, ($STYLESHEET ? "<LINK REL=\"STYLESHEET\" HREF=\"$STYLESHEET\">" : '' )
7208	, $more_links_mark
7209	, "</HEAD>" , ($before_body? $before_body : '')
7210	, "<BODY $body>", '');
7211}
7212
7213
7214sub style_sheet {
7215    local($env,$id,$style);
7216    #AXR:  don't overwrite existing .css
7217    #MRO: This is supposed to be $FILE.css, no?
7218    #RRM: only by default, others can be specified as well, via $EXTERNAL_STYLESHEET
7219    #return if (-f $EXTERNAL_STYLESHEET);
7220    return if (-r "$FILE.css" && -s _ && !$REFRESH_STYLES );
7221
7222    unless(open(STYLESHEET, ">$FILE.css")) {
7223        print "\nError: Cannot write '$FILE.css': $!\n";
7224        return;
7225    }
7226    if ( -f $EXTERNAL_STYLESHEET ) {
7227        if(open(EXT_STYLES, "<$EXTERNAL_STYLESHEET")) {
7228            while (<EXT_STYLES>) { print STYLESHEET $_; }
7229            close(EXT_STYLES);
7230        } else {
7231            print "\nError: Cannot read '$EXTERNAL_STYLESHEET': $!\n";
7232        }
7233    } else {
7234	print STYLESHEET <<"EOF"
7235/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */
7236.MATH    { font-family: \"Century Schoolbook\", serif; }
7237.MATH I  { font-family: \"Century Schoolbook\", serif; font-style: italic }
7238.BOLDMATH { font-family: \"Century Schoolbook\", serif; font-weight: bold }
7239
7240/* implement both fixed-size and relative sizes */
7241SMALL.XTINY		{ font-size : xx-small }
7242SMALL.TINY		{ font-size : x-small  }
7243SMALL.SCRIPTSIZE	{ font-size : smaller  }
7244SMALL.FOOTNOTESIZE	{ font-size : small    }
7245SMALL.SMALL		{  }
7246BIG.LARGE		{  }
7247BIG.XLARGE		{ font-size : large    }
7248BIG.XXLARGE		{ font-size : x-large  }
7249BIG.HUGE		{ font-size : larger   }
7250BIG.XHUGE		{ font-size : xx-large }
7251
7252/* heading styles */
7253H1		{  }
7254H2		{  }
7255H3		{  }
7256H4		{  }
7257H5		{  }
7258
7259/* mathematics styles */
7260DIV.displaymath		{ }	/* math displays */
7261TD.eqno			{ }	/* equation-number cells */
7262
7263
7264/* document-specific styles come next */
7265EOF
7266    }
7267    print "\n *** Adding document-specific styles *** ";
7268    while (($env,$style) = each %env_style) {
7269        if ($env =~ /\./) {
7270            $env =~ s/\.$//;
7271            print STYLESHEET "$env\t\t{ $style }\n";
7272        } elsif ($env =~ /inline|^(text|math)?((tt|rm|sf)(family)?|(up|it|sl|sc)(shape)?|(bf|md)(series)?|normal(font)?)$/) {
7273            print STYLESHEET "SPAN.$env\t\t{ $style }\n";
7274        } elsif ($env =~ /\./) {
7275            print STYLESHEET "$env\t\t{ $style }\n";
7276        } elsif ($env =~ /^(preform|\w*[Vv]erbatim(star)?)$/) {
7277            print STYLESHEET "PRE.$env\t\t{ $style }\n";
7278        } elsif ($env =~ /figure|table|tabular|equation|$array_env_rx/) {
7279            print STYLESHEET "TABLE.$env\t\t{ $style }\n";
7280        } else {
7281            print STYLESHEET "DIV.$env\t\t{ $style }\n";
7282        }
7283    }
7284    while (($env,$style) = each %txt_style) {
7285        print STYLESHEET "SPAN.$env\t\t{ $style }\n";
7286    }
7287    while (($env,$style) = each %img_style) {
7288        print STYLESHEET "IMG.$env\t\t{ $style }\n";
7289    }
7290
7291    my ($style);
7292    foreach $id (sort(keys  %styleID)) {
7293        $style =  $styleID{$id};
7294        $style =~ s/font-(color)/$1/;
7295        print STYLESHEET "\#$id\t\t{ $style }\n"
7296            if ($styleID{$id} ne '');
7297    }
7298    close(STYLESHEET);
7299}
7300
7301sub clear_styleID {
7302    return unless ($USING_STYLES);
7303    local($env_id,$id) = ("grp", @_);
7304    undef $styleID{$env_id} if ($id =~ /^\d+$/);
7305}
7306
7307sub make_address {
7308    local($addr) = &make_real_address(@_);
7309    $addr .= "\n</BODY>\n</HTML>\n";
7310    &lowercase_tags($addr) if $LOWER_CASE_TAGS;
7311    $addr;
7312}
7313
7314sub make_real_address {
7315    local($addr) = $ADDRESS;
7316    if ((defined &custom_address)&&($addr)) {
7317	&custom_address($addr)
7318    } elsif ($addr) {
7319	"<ADDRESS>\n$addr\n</ADDRESS>";
7320    } else { '' }
7321}
7322
7323sub purify_caption {
7324    local($_) = @_;
7325    local($text) = &recover_image_code($_);
7326    $text =~ s/\\protect|ALT\=|%EQNO:\d+//g;
7327    $text =~ s/[\\\#\'\"\`]//g;
7328    $text;
7329}
7330
7331sub recover_image_code {
7332    local($key) = @_;
7333    local($text) = $img_params{$key};
7334    if (!$text) {
7335	if ($text = $id_map{$key}) {
7336	    if ($orig_name_map{$text}) {
7337		$text = $img_params{$orig_name_map{$text}}
7338	    }
7339	} elsif ($cached_env_img{$key}) {
7340	    $text = $img_params{$cached_env_img{$key}};
7341	}
7342	if ($text =~ /\#*ALT="([^"]+)"(>|#)/s) { $text = $1 }
7343    }
7344    $text =~ s/\\protect|%EQNO:\d+//g;
7345    $text =~ s/&(gt|lt|amp|quot);/&special_html_inv($1)/eg;
7346    $text;
7347}
7348
7349sub encode_title {
7350    local($_) = @_;
7351    $_ = &encode($_);
7352    while (/(<[^<>]*>)/o) {s/$1//g}; # Remove HTML tags
7353    s/#[^#]*#//g;               # Remove #-delimited markers
7354    $_;
7355}
7356
7357# Encodes the contents of enviroments that are passed to latex. The code
7358# is then used as key to a hash table pointing to the URL of the resulting
7359# picture.
7360sub encode {
7361    local($_) = @_;
7362    # Remove invocation-specific stuff
7363    1 while(s/\\(begin|end)\s*(($O|$OP)\d+($C|$CP))?|{?tex2html_(wrap|nowrap|deferred|)(_\w+)?}?(\2)?//go);
7364    $_ = &revert_to_raw_tex($_);
7365    s/\\protect//g;		# remove redundant \protect macros
7366    #$_ = pack("u*", $_);	# uuencode
7367    s/\\\$/dollar/g;		# replace funnies, may cause problems in a hash key
7368    s/\//slash/g;		# replace funnies, may cause problems in a hash key
7369    s/\$|\/|\\//g;		# remove funnies, may cause problems in a hash key
7370    s/\s*|\n//g;		# Remove spaces  and newlines
7371    s/^(.{80}).*(.{80})$/$1$2/;		# truncate to avoid DBM problems
7372    $_;
7373}
7374
7375
7376##################### Hypertext Section Links ########################
7377sub post_process {
7378    # Put hyperlinks between sections, add HTML headers and addresses,
7379    # do cross references and citations.
7380    # Uses the %section_info array created in sub translate.
7381    # Binds the global variables
7382    # $PREVIOUS, $PREVIOUS_TITLE
7383    # $NEXT, $NEXT_TITLE
7384    # $UP, $UP_TITLE
7385    # $CONTENTS, $CONTENTS_TITLE
7386    # $INDEX, $INDEX_TITLE
7387    # $NEXT_GROUP, $NEXT_GROUP_TITLE
7388    # $PREVIOUS_GROUP, $PREVIOUS_GROUP_TITLE
7389    # Converting to and from lists and strings is very inefficient.
7390    # Maybe proper lists of lists should be used (or wait for Perl5?)
7391    # JKR:  Now using top_navigation and bot_navigation instead of navigation
7392    local($_, $key, $depth, $file, $title, $header, @link, @old_link,
7393	  $top_navigation, $bot_navigation, @keys,
7394	  @tmp_keys, $flag, $child_links, $body, $more_links);
7395
7396    @tmp_keys = @keys = sort numerically keys %section_info;
7397    print "\nDoing section links ...";
7398    while (@tmp_keys) {
7399	$key = shift @tmp_keys;
7400	next if ($MULTIPLE_FILES &&!($key =~ /^$THIS_FILE/));
7401	print ".";
7402	$more_links = "";
7403	($depth, $file, $title, $body) = split($delim,$section_info{$key});
7404	print STDOUT "\n$key $file $title $body" if ($VERBOSITY > 3);
7405	next if ($body =~ /external/);
7406	$PREVIOUS = $PREVIOUS_TITLE = $NEXT = $NEXT_TITLE = $UP = $UP_TITLE
7407	    = $CONTENTS = $CONTENTS_TITLE = $INDEX = $INDEX_TITLE
7408	    = $NEXT_GROUP = $NEXT_GROUP_TITLE
7409	    = $PREVIOUS_GROUP = $PREVIOUS_GROUP_TITLE
7410	    = $_ = $top_navigation = $bot_navigation = undef;
7411	&add_link_tag('previous',$file);
7412	@link =  split(' ',$key);
7413        ($PREVIOUS, $PREVIOUS_TITLE) =
7414	    &add_link($previous_page_visible_mark,$file,@old_link);
7415	@old_link = @link;
7416	unless ($done{$file}) {
7417	    ++$link[$depth];
7418#	    if ($MULTIPLE_FILES && !$depth && $multiple_toc ) {
7419#	    	local($save_depth) = $link[$depth];
7420#	    	$link[$depth] = 1;
7421#		($NEXT_GROUP, $NEXT_GROUP_TITLE) =
7422#		    &add_link($next_visible_mark, $file, @link);
7423#		&add_link_tag('next', $file, @link);
7424#		$link[$depth] = $save_depth;
7425#	    } else {
7426		($NEXT_GROUP, $NEXT_GROUP_TITLE) =
7427		    &add_link($next_visible_mark, $file, @link);
7428		&add_link_tag('next', $file, @link);
7429#	    }
7430
7431	    $link[$depth]--;$link[$depth]--;
7432	    if ($MULTIPLE_FILES && !$depth ) {
7433	    } else {
7434		($PREVIOUS_GROUP, $PREVIOUS_GROUP_TITLE) =
7435		    &add_link($previous_visible_mark, $file,@link);
7436		&add_link_tag('previous', $file,@link);
7437	    }
7438
7439	    $link[$depth] = 0;
7440	    ($UP, $UP_TITLE) =
7441		&add_link($up_visible_mark, $file, @link);
7442	    &add_link_tag('up', $file, @link);
7443
7444	    if ($CONTENTS_IN_NAVIGATION) {
7445		($CONTENTS, $CONTENTS_LINK) =
7446		    &add_special_link($contents_visible_mark, $tocfile, $file);
7447		&add_link_tag('contents', $file, $delim.$tocfile);
7448	    }
7449
7450	    if ($INDEX_IN_NAVIGATION) {
7451		($INDEX, $INDEX_LINK) =
7452		    &add_special_link($index_visible_mark, $idxfile, $file);
7453		&add_link_tag('index', $file, $delim.$idxfile,);
7454	    }
7455
7456	    @link = split(' ',$tmp_keys[0]);
7457	    # the required `next' link may be several sub-sections along
7458	    local($nextdepth,$nextfile,$nextkey,$nexttitle,$nextbody)=
7459	        ($depth,$file,$key,'','');
7460	    $nextkey = shift @tmp_keys;
7461	    ($nextdepth, $nextfile,$nexttitle,$nextbody) = split($delim,$section_info{$nextkey});
7462	    if (($nextdepth<$MAX_SPLIT_DEPTH)&&(!($nextbody=~/external/))) {
7463		($NEXT, $NEXT_TITLE) =
7464		    &add_link($next_page_visible_mark, $file, @link);
7465		&add_link_tag('next', $file, @link);
7466	    } else {
7467		($NEXT, $NEXT_TITLE) = ('','');
7468		$nextfile = $file;
7469	    }
7470	    if ((!$NEXT || $NEXT =~ /next_page_inactive_visible_mark/)&&(@tmp_keys)) {
7471		# the required `next' link may be several sub-sections along
7472		while ((@tmp_keys)&&(($MAX_SPLIT_DEPTH < $nextdepth+1)||($nextfile eq $file))) {
7473		    $nextkey = shift @tmp_keys;
7474		    ($nextdepth, $nextfile,$nexttitle,$nextbody) = split($delim,$section_info{$nextkey});
7475		    if ($nextbody =~ /external/) {
7476			$nextfile = $file;
7477			next;
7478		    };
7479		    print ",";
7480		    print STDOUT "\n $nextkey" if ($VERBOSITY > 3);
7481		}
7482		@link = split(' ',$nextkey);
7483		if (($nextkey)&&($nextdepth<$MAX_SPLIT_DEPTH)) {
7484		    ($NEXT, $NEXT_TITLE) =
7485			&add_link($next_page_visible_mark, $file, @link);
7486		    &add_link_tag('next', $file, @link);
7487		} else {
7488		    ($NEXT, $NEXT_TITLE) = ($NEXT_GROUP, $NEXT_GROUP_TITLE);
7489		    $NEXT =~ s/next_page_(inactive_)?visible_mark/next_page_$1visible_mark/;
7490		    ($PREVIOUS, $PREVIOUS_TITLE) = ($PREVIOUS_GROUP, $PREVIOUS_GROUP_TITLE);
7491		    $PREVIOUS =~ s/previous_(inactive_)?visible_mark/previous_page_$1visible_mark/;
7492		}
7493	    }
7494	    unshift (@tmp_keys,$nextkey) if ($nextkey);
7495#
7496	    $top_navigation = (defined(&top_navigation_panel) ?
7497			       &top_navigation_panel : &navigation_panel)
7498		unless $NO_NAVIGATION;
7499	    $bot_navigation = (defined(&bot_navigation_panel) ?
7500			       &bot_navigation_panel : &navigation_panel)
7501		unless $NO_NAVIGATION;
7502	    local($end_navigation) = "\n<!--End of Navigation Panel-->\n";
7503	    if ($USING_STYLES) {
7504		$top_navigation = "\n".'<DIV CLASS="navigation">' . $top_navigation
7505			if $top_navigation;
7506		$bot_navigation = "\n".'<DIV CLASS="navigation">' . $bot_navigation
7507			if $bot_navigation;
7508		$end_navigation = '</DIV>' . $end_navigation;
7509		$env_style{'navigation'} = " ";
7510	    }
7511
7512	    $header = &make_head_and_body($title, $body);
7513	    $header = join('', $header, $top_navigation, $end_navigation) if ($top_navigation);
7514
7515	    local($this_file) = $file;
7516	    if ($MULTIPLE_FILES && $ROOTED) {
7517		if ($this_file =~ /\Q$dd\E([^$dd$dd]+)$/) { $this_file = $1 }
7518	    }
7519	    &slurp_input($this_file);
7520	    open(OUTFILE, ">$this_file")
7521                || die "\nError: Cannot write file '$this_file': $!\n";
7522
7523	    if (($INDEX) && ($SHORT_INDEX) && ($SEGMENT eq 1)) {
7524		&make_index_segment($title,$file); }
7525
7526	    local($child_star,$child_links);
7527	    local($CURRENT_FILE) = $this_file; # ensure $CURRENT_FILE is set correctly
7528	    if (/$childlinks_on_mark\#(\d)\#/) { $child_star = $1 }
7529	    $child_links = &add_child_links('',$file, $depth, $child_star,$key, @keys)
7530		unless (/$childlinks_null_mark\#(\d)\#/);
7531	    if (($child_links)&&(!/$childlinks_mark/)&&($MAX_SPLIT_DEPTH > 1)) {
7532		if ($depth < $MAX_SPLIT_DEPTH -1) {
7533		    $_ = join('', $header, $_, &child_line(), $childlinks_mark, "\#0\#" );
7534		} else {
7535		    $_ = join('', $header, "\n$childlinks_mark\#0\#", &upper_child_line(), $_ );
7536		}
7537	    } else {
7538		$_ = join('', $header, $_ );
7539	    }
7540	    $flag = (($BOTTOM_NAVIGATION || &auto_navigation) && $bot_navigation);
7541	    $_ .= $bot_navigation . $end_navigation if ($flag &&($bot_navigation));
7542	    $_ .= &child_line() unless $flag;
7543	    print STDOUT "\n *** replace markers *** " if ($VERBOSITY > 1);
7544	    &replace_markers;
7545	    print STDOUT "\n *** post-post-process *** " if ($VERBOSITY > 1);
7546	    &post_post_process if (defined &post_post_process);
7547	    &adjust_encoding;
7548	    print OUTFILE $_;
7549	    print OUTFILE &make_address;
7550	    close OUTFILE;
7551	    $done{$file}++;
7552	}
7553    }
7554    &post_process_footnotes if ($footfile);
7555}
7556
7557sub adjust_encoding {
7558    &convert_to_utf8($_) if ($USE_UTF);
7559    &lowercase_tags($_) if $LOWER_CASE_TAGS;
7560}
7561
7562sub post_replace_markers {
7563    # MRO: replaced $* with /m
7564    # clean up starts and ends of  P, BR and DIV tags
7565    s/(<\/?(P|BR|DIV)>)\s*(\w)/$1\n$3/gom unless ($file eq $citefile);
7566    s/([^\s])(<(BR|DIV))/$1\n$2/gom unless ($file eq $citefile);
7567    local($keep,$after);
7568
7569    # anchor images when otherwise there is an invisible-anchor
7570#    s/(<A[^>]*>)\&\#160;<\/A>\s?(<(P|DIV)[^>]*>)\s*(<IMG[^>]*>)\s*(<\/(P|DIV)>)/
7571    s/(<A[^>]*>)($anchor_mark|$anchor_invisible_mark)<\/A>\s?(<(P|DIV)[^>]*>)\s*(<IMG[^>]*>)\s*(<\/(P|DIV)>)/
7572	do{ $keep="$3$1$5<\/A>";
7573	    $after = $6;
7574	    join('',$keep, &after_punct_break($after), $after);
7575	} /egom;
7576
7577    # absorb named anchor (e.g. from index-entry) into preceding or following anchor
7578#    s/(<A NAME=\"[^\"]+\")>\&#160;<\/A>\s*\b?<A( HREF=\"[^\"]+\">)/$1$2/gom;
7579#    s/(<A HREF=\"[^\"]+\")(>\s*\b?([^<]+|<([^>\/]+|\/[^>A]+)>\s*)*<\/A>)\s*\b?<A( NAME=\"[^\"]+\")>\&#160;<\/A>/$1$5$2/gom;
7580
7581    # clean up empty table cells
7582    s/(<TD[^>]*>)\s*(<\/TD>)/<TD>$2/gom;
7583
7584    # clean up list items (only desirable in the bibliography ?)
7585    # s/\n<P>(<DT[^>]*>)/\n<P><\/P>\n$1/gom;
7586
7587    # remove blank lines and comment-markers
7588#    s/\n\n/\n/g;  # no, cause this kills intended ones in verbatims
7589    s/$comment_mark(\d+\n?)?//gm;
7590    s/\&quot;/"/gm;  # replace  &quot;  entities
7591
7592    # italic \LaTeX looks bad
7593    s:<(I|EM)>(($Laname|$AmSname)?$TeXname)</\1>:$2:gm;
7594}
7595
7596sub lowercase_tags {
7597    # MRO: modified to use $_[0]
7598    # local(*stream) = @_;
7599    my ($tags,$attribs);
7600    $_[0] =~ s!<(/?\w+)( [^>]*)?>!
7601	$tags = $1; $attribs = $2;
7602	$attribs =~ s/ ([\w\d-]+)(=| |$)/' '.lc($1).$2/eg;
7603	join('', '<', lc($tags) , $attribs , '>')!eg;
7604}
7605
7606sub after_punct_break {
7607    # MRO: modified to use $_[0]
7608    # local(*stream) = @_;
7609#    $stream =~ s/^([ \t]*)([,;\.\)\!\"\'\?])[ \t]*(\n)?/(($2)? "$2" : "$1")."\n"/em;
7610#    $stream;
7611    $_[0] =~ s/^([ \t]*)([,;\.\)\!\"\'\?\>]|\&gt;)[ \t]*(\n)?//em;
7612    ($2 ? $2 : $1)."\n";
7613}
7614
7615sub make_index_segment {
7616    local($title,$file)= @_ ;
7617#JCL(jcl-tcl)
7618#    s/<[^>]*>//g;
7619#
7620    $index_segment{$PREFIX} = "$title";
7621    if (!($ref_files{"segment"."$PREFIX"} eq "$file")) {
7622	$ref_files{"segment"."$PREFIX"} = "$file";
7623	$changed = 1
7624    }
7625    $SEGMENT = 2;
7626}
7627
7628
7629sub add_link {
7630    # Returns a pair (iconic link, textual link)
7631    local($icon, $current_file, @link) = @_;
7632    local($dummy, $file, $title, $lbody) = split($delim,$section_info{join(' ',@link)});
7633    if ($lbody =~ /external/) { return ('','') };
7634
7635#    local($dummy, $file, $title) = split($delim,$toc_section_info{join(' ',@link)});
7636
7637    if ($MULTIPLE_FILES && $ROOTED && $file) {
7638        if (!($DESTDIR =~ /\Q$FIXEDDIR\E[$dd$dd]?$/)) { $file = "..$dd$file" }
7639    }
7640#    if ($title && ($file ne $current_file || $icon ne $up_visible_mark)) {
7641    if ($title && ($file ne $current_file)) {
7642	#RRM: allow user-customisation of the link-text; thanks Dan Young
7643	if (defined &custom_link_hook ) {
7644	    $title = &custom_link_hook($title,$toc_section_info{join(' ',@link)});
7645	} else {
7646            $title = &purify($title);
7647	    $title = &get_first_words($title, $WORDS_IN_NAVIGATION_PANEL_TITLES);
7648	}
7649	return ("\n".&make_href($file, $icon), &make_href($file, "$title"))
7650    }
7651#    elsif ($icon eq $up_visible_mark && $file eq $current_file && $EXTERNAL_UP_LINK) {
7652    elsif ($icon eq $up_visible_mark && $EXTERNAL_UP_LINK) {
7653 	return ("\n".&make_href($EXTERNAL_UP_LINK, $icon),
7654		&make_href($EXTERNAL_UP_LINK, "$EXTERNAL_UP_TITLE"))
7655    }
7656    elsif (($icon eq $previous_visible_mark || $icon eq $previous_page_visible_mark)
7657    	&& $EXTERNAL_PREV_LINK && $EXTERNAL_PREV_TITLE) {
7658	return ("\n".&make_href($EXTERNAL_PREV_LINK, $icon),
7659		&make_href($EXTERNAL_PREV_LINK, "$EXTERNAL_PREV_TITLE"))
7660    }
7661    elsif (($icon eq $next_visible_mark ||  $icon eq $next_page_visible_mark)
7662    	&& $EXTERNAL_DOWN_LINK && $EXTERNAL_DOWN_TITLE) {
7663	return ("\n".&make_href($EXTERNAL_DOWN_LINK, $icon),
7664		&make_href($EXTERNAL_DOWN_LINK, "$EXTERNAL_DOWN_TITLE"))
7665    }
7666    (&inactive_img($icon), "");
7667}
7668
7669sub add_special_link { &add_real_special_link(@_) }
7670sub add_real_special_link {
7671    local($icon, $file, $current_file) = @_;
7672    local($text);
7673    if ($icon eq $contents_visible_mark) { $text = $toc_title }
7674    elsif ($icon eq $index_visible_mark) { $text = $idx_title }
7675    elsif ($icon eq $biblio_visible_mark) { $text = $bib_title }
7676    (($file && ($file ne $current_file)) ?
7677    	("\n" . &make_href($file, $icon),
7678    	    ($text ? " ". &make_href($file, $text) : undef))
7679    	: ( undef, undef ))
7680}
7681
7682#RRM: add <LINK ...> tag to the HTML head.
7683#     suggested by Marcus Hennecke
7684#
7685sub add_link_tag {
7686    local($rel, $currentfile, @link ) = @_;
7687#    local($dummy, $file, $title) = split($delim,$toc_section_info{join(' ',@link)});
7688    local($dummy, $file, $title) = split($delim,$section_info{join(' ',@link)});
7689    ($dummy, $file, $title) = split($delim,$toc_section_info{join(' ',@link)})
7690	unless ($title);
7691
7692    if ($MULTIPLE_FILES && $ROOTED && $file) {
7693        if (!($DESTDIR =~ /\Q$FIXEDDIR\E[$dd$dd]?$/)) { $file = "..$dd$file" }
7694    }
7695    if ($file && !($file eq $currentfile) && (!$NO_NAVIGATION)) {
7696	#RRM: allow user-customisation of the REL attribute
7697	if (defined &custom_REL_hook ) {
7698	    $rel = &custom_REL_hook($rel,$toc_section_info{join(' ',@link)});
7699	}
7700        $more_links .= "\n<LINK REL=\"$rel\" HREF=\"$file\">";
7701    }
7702}
7703
7704sub remove_markers {
7705# modifies $_
7706    s/$lof_mark//go;
7707    s/$lot_mark//go;
7708    &remove_bbl_marks;
7709    s/$toc_mark//go;
7710    s/$idx_mark//go;
7711    &remove_cross_ref_marks;
7712    &remove_external_ref_marks;
7713    &remove_cite_marks;
7714    &remove_file_marks;
7715# sensitive markers
7716    &remove_image_marks;
7717    &remove_icon_marks;
7718    &remove_verbatim_marks;
7719    &remove_verb_marks;
7720    &remove_child_marks;
7721# uncaught markers
7722    s/$percent_mark/%/go;
7723    s/$ampersand_mark/\&amp;/go;
7724    s/$comment_mark\s*(\d+\n?)?//sgo;
7725    s/$caption_mark//go;
7726    s/<tex2html[^>]*>//g;
7727    s/$OP\d+\$CP//g;
7728    $_;
7729}
7730
7731sub replace_markers {
7732    &find_quote_ligatures;
7733    &replace_general_markers;
7734    &text_cleanup;
7735    # Must NOT clean the ~'s out of the navigation icons (in panel or text),
7736    # and must not interfere with verbatim-like environments
7737    &replace_sensitive_markers;
7738    &replace_init_file_mark if (/$init_file_mark/);
7739    &replace_file_marks;
7740    &post_replace_markers;
7741}
7742
7743sub replace_general_markers {
7744    if (defined &replace_infopage_hook) {&replace_infopage_hook if (/$info_page_mark/);}
7745    else { &replace_infopage if (/$info_page_mark/); }
7746    if (defined &add_idx_hook) {&add_idx_hook if (/$idx_mark/);}
7747    else {&add_idx if (/$idx_mark/);}
7748
7749    if ($segment_figure_captions) {
7750#	s/$lof_mark/<UL>$segment_figure_captions<\/UL>/o
7751#   } else { s/$lof_mark/<UL>$figure_captions<\/UL>/o }
7752	s/$lof_mark/$segment_figure_captions/o
7753    } else { s/$lof_mark/$figure_captions/o }
7754    if ($segment_table_captions) {
7755#	s/$lot_mark/<UL>$segment_table_captions<\/UL>/o
7756#   } else { s/$lot_mark/<UL>$table_captions<\/UL>/o }
7757	s/$lot_mark/$segment_table_captions/o
7758    } else { s/$lot_mark/$table_captions/o }
7759    &replace_morelinks();
7760    if (defined &replace_citations_hook) {&replace_citations_hook if /$bbl_mark/;}
7761    else {&replace_bbl_marks if /$bbl_mark/;}
7762    if (defined &add_toc_hook) {&add_toc_hook if (/$toc_mark/);}
7763    else {&add_toc if (/$toc_mark/);}
7764    if (defined &add_childs_hook) {&add_childs_hook if (/$childlinks_on_mark/);}
7765    else {&add_childlinks if (/$childlinks_on_mark/);}
7766    &remove_child_marks;
7767
7768    if (defined &replace_cross_references_hook) {&replace_cross_references_hook;}
7769    else {&replace_cross_ref_marks if /$cross_ref_mark||$cross_ref_visible_mark/;}
7770    if (defined &replace_external_references_hook) {&replace_external_references_hook;}
7771    else {&replace_external_ref_marks if /$external_ref_mark/;}
7772    if (defined &replace_cite_references_hook) {&replace_cite_references_hook;}
7773    else { &replace_cite_marks if /$cite_mark/; }
7774    if (defined &replace_user_references) {
7775 	&replace_user_references if /$user_ref_mark/; }
7776}
7777
7778sub replace_sensitive_markers {
7779    if (defined &replace_images_hook) {&replace_images_hook;}
7780    else {&replace_image_marks if /$image_mark/;}
7781    if (defined &replace_icons_hook) {&replace_icons_hook;}
7782    else {&replace_icon_marks if /$icon_mark_rx/;}
7783    if (defined &replace_verbatim_hook) {&replace_verbatim_hook;}
7784    else {&replace_verbatim_marks if /$verbatim_mark/;}
7785    if (defined &replace_verb_hook) {&replace_verb_hook;}
7786    else {&replace_verb_marks if /$verb_mark|$verbstar_mark/;}
7787    s/;SPMdollar;/\$/g; s/;SPMtilde;/\~/g; s/;SPMpct;/\%/g;
7788    s/;SPM/\&/go;
7789    s/$percent_mark/%/go;
7790    s/$ampersand_mark/\&amp;/go;
7791    #JKR: Turn encoded ~ back to normal
7792    s/&#126;/~/go;
7793}
7794
7795sub find_quote_ligatures {
7796    my $ent;
7797
7798# guillemets, governed by $NO_FRENCH_QUOTES
7799    do {
7800	$ent = &iso_map('laquo', "", 1);
7801	if ($NO_UTF && !$USE_UTF && $ent=~/\&\#(\d+);/) {
7802	    $ent='' if ($1 > 255);
7803	}
7804	s/((\&|;SPM)lt;){2}/$ent/ogs if $ent;
7805	$ent = &iso_map('raquo', "", 1) if ($ent);
7806	s/((\&|;SPM)gt;){2}/$ent/ogs if $ent;
7807	# single guillemot chars cannot be easily implemented this way
7808	# finding an approp regexp is work for the future
7809    } unless ($NO_FRENCH_QUOTES);
7810
7811    $ent = &iso_map("gg", "", 1);
7812    s/;SPMgg;/($ent ? $ent : '&gt;&gt;')/eg unless ($USE_NAMED_ENTITIES);
7813    $ent = &iso_map("ll", "", 1);
7814    s/;SPMll;/($ent ? $ent : '&lt;&lt;')/eg unless ($USE_NAMED_ENTITIES);
7815
7816    my $ldquo, $rdquo;
7817# "curly" quotes, governed by  $USE_CURLY_QUOTES.
7818    do {
7819	$ldquo = &iso_map("ldquo", "", 1);
7820	if ($NO_UTF && !$USE_UTF && $ldquo =~ /\&\#(\d+);/) {
7821	    $ldquo = '' if ($1 > 255);
7822	}
7823	s/``/$ldquo/ogs if ($ldquo);
7824	$rdquo = &iso_map("rdquo", "", 1) if ($ldquo);
7825	s/''/$rdquo/ogs if ($rdquo);
7826
7827	# single curly quotes cannot be easily implemented this way
7828	# finding an approp regexp is work for the future
7829    } if ($USE_CURLY_QUOTES);
7830
7831# "german" quotes, governed by  $NO_GERMAN_QUOTES.
7832    do {
7833	$ent = &iso_map('bdquo', "", 1);
7834	if ($NO_UTF && !$USE_UTF && $ent =~ /\&\#(\d+);/) {
7835	    $ent = '' if ($1 > 255);
7836	}
7837	s/,,/$ent/eg if $ent;
7838
7839	# closing upper quotes are not properly displayed in browsers
7840	s/($ent[\w\s\&\#;']+)$ldquo/$1``/og
7841		if ($USE_CURLY_QUOTES && $ldquo && $ent);
7842    } unless ($NO_GERMAN_QUOTES);
7843}
7844
7845sub add_childlinks {
7846    local($before, $after, $star);
7847    while (/$childlinks_on_mark\#(\d)\#/) {
7848	$star = $1;
7849	$before = $`;
7850	$after = $';
7851	$before =~ s/\n\s*$//;
7852	$_ = join('', $before, "\n", $child_links, $after);
7853    }
7854}
7855
7856sub replace_infopage {
7857    local($INFO)=1 if !(defined $INFO);
7858    if ($INFO == 1) {
7859    	local($title);
7860	if ((defined &do_cmd_infopagename)||$new_command{'infopagename'}) {
7861	    local($br_id)=++$global{'max_id'};
7862	    $title = &translate_environments("$O$br_id$C\\infopagename$O$br_id$C");
7863	} else { $title = $info_title }
7864	    if ($MAX_SPLIT_DEPTH <= $section_commands{$outermost_level}) {
7865	        $_ =~ s/(<HR[^>]*>\s*)?$info_title_mark/
7866		    ($1? $1 : "\n<HR>")."\n<H2>$title<\/H2>"/eog;
7867	    } else {
7868	        $_ =~ s/$info_title_mark/"\n<H2>$title<\/H2>"/eog;
7869	    }
7870    }
7871    while (/$info_page_mark/o) {
7872	$_ = join('', $`, &do_cmd_textohtmlinfopage, $');
7873    }
7874}
7875
7876sub replace_init_file_mark {
7877    local($init_file, $init_contents, $info_line)=($INIT_FILE,'','');
7878    if (-f $init_file) {
7879    } elsif (-f "$orig_cwd$dd$init_file") {
7880	$init_file = $orig_cwd.$dd.$init_file;
7881    } else {
7882	s/$init_file_mark//g;
7883	return();
7884    }
7885    if(open(INIT, "<$init_file")) {
7886        foreach $info_line (<INIT>) {
7887	    $info_line =~ s/[<>"&]/'&'.$html_special_entities{$&}.';'/eg;
7888	    $init_contents .= $info_line;
7889	}
7890        close INIT;
7891    } else {
7892        print "\nError: Cannot read '$init_file': $!\n";
7893    }
7894    s/$init_file_mark/\n<BLOCKQUOTE><PRE>\n$init_contents\n<\/PRE><\/BLOCKQUOTE>\n/g;
7895}
7896
7897sub replace_morelinks {
7898    $_ =~ s/$more_links_mark/$more_links/e;
7899}
7900
7901# This code is extremely inefficient. At least the subtrees should be
7902# filtered according to $MAX_LINK_DEPTH before going into the
7903# inner loops.
7904# RRM: revamped parts, for $TOC_STARS, fixing some errors.
7905#
7906sub add_child_links { &add_real_child_links(@_) }
7907sub add_real_child_links {
7908    local($exclude, $base_file, $depth, $star, $current_key, @keys) = @_;
7909    local $min_depth = $section_commands{$outermost_level} - 1;
7910    return ('') if ((!$exclude)&&(!$LEAF_LINKS)&&($depth >= $MAX_SPLIT_DEPTH));
7911    if ((!$depth)&&($outermost_level)) { $depth = $min_depth }
7912
7913    local($_, $child_rx, @subtree, $next, %open, @roottree);
7914    local($first, $what, $pre, $change_key, $list_class);
7915    $childlinks_start = join('','<div id="table-of-contents">',"\n",
7916			     '<!--Table of Child-Links-->',"\n") ;
7917    $childlinks_end =  join('',"<!--End of Table of Child-Links-->","\n",'</div>',"\n") ;
7918    $child_rx = $current_key;
7919    $child_rx =~ s/( 0)*$//;	# Remove trailing 0's
7920    if ((!$exclude)&&($depth < $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH -1 )
7921	#	    &&($depth >= $MAX_SPLIT_DEPTH-1)) {
7922	&&($depth > $min_depth)) {
7923	if ((defined &do_cmd_childlinksname)||$new_command{'childlinksname'}) {
7924	    local($br_id)=++$global{'max_id'};
7925	    $what = &translate_environments("$O$br_id$C\\childlinksname$O$br_id$C");
7926	} else {
7927	    $what = "<strong>$child_name</strong>";
7928	}
7929	$list_class = ' CLASS="ChildLinks"' if ($USING_STYLES);
7930	$first = "$childlinks_start\n<A NAME=\"CHILD_LINKS\">$what<\/A>\n";
7931    } elsif ($exclude) {
7932	# remove any surrounding braces
7933	$exclude =~ s/^($O|$OP)\d+($C|$CP)|($O|$OP)\d+($C|$CP)$//g;
7934	# Table-of-Contents
7935	$list_class = ' CLASS="TofC"' if ($USING_STYLES);
7936	$childlinks_start = "\n<!--Table of Contents-->\n";
7937	$childlinks_end = "<!--End of Table of Contents-->";
7938	$first = "$childlinks_start";
7939    } else {
7940	$list_class = ' CLASS="ChildLinks"' if ($USING_STYLES);
7941	$first = "$childlinks_start\n"
7942	    . ($star ? '':"<A NAME=\"CHILD_LINKS\">$anchor_mark<\/A>\n");
7943    }
7944    my $startlist, $endlist;
7945    $startlist = "<UL$list_class>" unless $CHILD_NOLIST;
7946    $endlist = '</UL>' unless $CHILD_NOLIST;
7947    my $alt_item = '<BR>&nbsp;<BR>'."\n";
7948    my $outer_item = ($CHILD_NOLIST ? $alt_item : '<LI>');
7949    my $inner_item = '<LI>';
7950    my $inner_end = '</UL><BR>';
7951
7952    # collect the relevant keys...
7953    foreach $next (@keys) {
7954	if ($MULTIPLE_FILES && $exclude) {
7955	    # ...all but with this document as the root
7956	    if ($next =~ /^$THIS_FILE /) {
7957#		# make current document the root
7958#	    	$change_key = '0 '.$';
7959		push(@roottree,$next);
7960		print "\n$next : m-root" if ($VERBOSITY > 3);
7961	    } else {
7962		push(@subtree,$next);
7963		print "\n$next : m-sub" if ($VERBOSITY > 3);
7964	    }
7965	} elsif (($next =~ /^$child_rx /)&&($next ne $current_key)) {
7966	# ...which start as $current_key
7967	    push(@subtree,$next);
7968	    print "\n$next : sub $child_rx" if ($VERBOSITY > 3);
7969	} else {
7970	    print "\n$next : out $current_key" if ($VERBOSITY > 3);
7971	}
7972    }
7973    if (@subtree) { @subtree = sort numerically @subtree; }
7974    if (@roottree) {
7975    	@roottree = sort numerically @roottree;
7976    	@subtree = ( @roottree, @subtree );
7977    }
7978    # @subtree now contains the subtree rooted at the current node
7979
7980    local($countUL); #counter to ensure correct tag matching
7981    my $root_file, $href;
7982    if (@subtree) {
7983	local($next_depth, $file, $title, $sec_title, $star, $ldepth,$this_file, $prev_file);
7984	$ldepth = $depth;
7985	$prev_file = $base_file;
7986#	@subtree = sort numerically @subtree;
7987	foreach $next (@subtree) {
7988	    $title = '';
7989	    if ($exclude) {
7990		# making TOC
7991		($next_depth, $file, $sec_title) =
7992			split($delim,$section_info{$next});
7993		($next_depth, $file, $title, $star) =
7994			split($delim,$toc_section_info{$next});
7995		# use the %section_info  title, in case there are images
7996		$title = $sec_title if ($sec_title =~ /image_mark>\#/);
7997	    } else {
7998		# making mini-TOC i.e. the child-links tables
7999		$star = '';
8000		($next_depth, $file, $title) =
8001			split($delim,$section_info{$next});
8002	    }
8003	    $root_file = $file unless $root_file;
8004	    if ($root_file && $root_file =~ /_mn\./) { $root_file=$` };
8005	    # remove any surrounding braces
8006	    $title =~ s/^($O|$OP)\d+($C|$CP)|($O|$OP)\d+($C|$CP)$//g;
8007	    next if ($exclude && $title =~ /^$exclude$/);
8008	    if (!$title) {
8009		($next_depth, $file, $title, $star) =
8010			split($delim,$toc_section_info{$next});
8011	    }
8012	    $this_file = $file;
8013	    $title = "\n".$title if !($title =~/^\n/);
8014	    next if ( $exclude &&(				# doing Table-of-Contents
8015		( $TOC_DEPTH &&($next_depth > $TOC_DEPTH))	# and  too deep
8016		||($star && !$TOC_STARS ) ));			# or no starred sections
8017	    $file = "" if (!$MAX_SPLIT_DEPTH); # Martin Wilck
8018	    next if ($exclude && !$MULTIPLE_FILES &&($title =~ /^\s*$exclude\s*$/));
8019	    next if (!$exclude && $next_depth > $MAX_LINK_DEPTH + $depth);
8020	    print "\n$next :" if ($VERBOSITY > 3);
8021	    if ($this_file =~ /^(\Q$prev_file\E|\Q$base_file\E)$/) {
8022		$file .= join('', "#SECTION", split(' ', $next));
8023	    } else { $prev_file = $file }
8024
8025	    if (!$next_depth && $MULTIPLE_FILES) { ++$next_depth }
8026	    local($num_open) = (split('/',%open))[0];
8027	    if ((($next_depth > $ldepth)||$first)
8028		&& ((split('/',%open))[0] < $MAX_LINK_DEPTH + $depth )
8029		) {
8030		# start a new <UL> list
8031		if ($first) {
8032		    $_ = "$first\n$startlist\n"; $countUL++;
8033		    local $i = 1;
8034		    while ($i <= $ldepth) {
8035			$open{$i}=0; $i++
8036		    }
8037		    $first = '';	# include NAME tag first time only
8038		    while ($i < $next_depth) {
8039			$open{$i}=1; $i++;
8040			$_ .= ($countUL >1 ? $inner_item : $outer_item)."<UL>\n";
8041			$countUL++;
8042		    }
8043		} else {
8044		    $_ .= "<UL>\n"; $countUL++;
8045		}
8046		$ldepth = $next_depth;
8047		$open{$ldepth}++;
8048		# append item to this list
8049		print " yes " if ($VERBOSITY > 3);
8050		if (defined &add_frame_child_links) {
8051		    $href = &make_href($file,$title);
8052		    if ($href =~ s/($root_file)_mn/$1_ct/) {
8053			$href =~ s/(target=")main(")/$1contents$2/i;
8054		    };
8055		    $_ .= ($countUL >1 ? $inner_item : $outer_item)
8056			. $href . "\n";
8057		} else {
8058		    $_ .= ($countUL >1 ? $inner_item : $outer_item)
8059			. &make_href($file,$title) . "\n";
8060		}
8061	    }
8062	    elsif (($next_depth)&&($next_depth <= $ldepth)
8063		&&((split('/',%open))[0] <= $MAX_LINK_DEPTH + $depth )
8064		) {
8065		# append item to existing <UL> list
8066		while (($next_depth < $ldepth) && %open ) {
8067		# ...closing-off any nested <UL> lists
8068		    if ($open{$ldepth}) {
8069			if (!(defined $open{$next_depth}))  {
8070			    $open{$next_depth}++;
8071			} else {
8072			    $_ .= ($countUL==2 ? $inner_end : '</UL>')."\n";
8073			    $countUL--;
8074			}
8075			delete $open{$ldepth};
8076		    };
8077		    $ldepth--;
8078		}
8079		$ldepth = $next_depth;
8080		print " yes" if ($VERBOSITY > 3);
8081		if (defined &add_frame_child_links) {
8082		    $href = &make_href($file,$title);
8083		    if ($href =~ s/($root_file)_mn/$1_ct/) {
8084			$href =~ s/(target=")main(")/$1contents$2/i;
8085		    };
8086		    $_ .= ($countUL >1 ? $inner_item : $outer_item)
8087			. $href . "\n";
8088		} else {
8089		    $_ .= ($countUL >1 ? $inner_item : $outer_item)
8090			. &make_href($file,$title) . "\n";
8091		}
8092	    } else {
8093		# ignore items that are deeper than $MAX_LINK_DEPTH
8094		print " no" if ($VERBOSITY > 3);
8095	    }
8096	}
8097
8098	if (%open) {
8099	# close-off any remaining <UL> lists
8100	    $countUL-- if $CHILD_NOLIST;
8101	    local $cnt = (split('/',%open))[0];
8102	    local $i = $cnt;
8103		while ($i > $depth) {
8104		    if ($open{$i}) {
8105			$_ .= '</UL>' if $countUL;
8106			$countUL--;
8107			delete $open{$i};
8108		    }
8109		$i--;
8110	    }
8111	}
8112    }
8113    # just in case the count is wrong
8114    $countUL-- if ($CHILD_NOLIST && $countUL > 0);
8115    $countUL = '' if ($countUL < 0);
8116    while ($countUL) { $_ .= '</UL>'; $countUL-- }
8117    ($_ ? join('', $_, "\n$childlinks_end") : '');
8118}
8119
8120sub child_line {($CHILDLINE) ? "$CHILDLINE" : "<BR>\n<HR>";}
8121sub upper_child_line { "<HR>\n"; }
8122
8123sub adjust_root_keys {
8124    return() unless ($MULTIPLE_FILES && $ROOTED);
8125    local($next,$change_key,$current_rx);
8126    local(@keys) = (keys %toc_section_info);
8127
8128    local($current_key) = join(' ',@curr_sec_id);
8129    $current_key =~ /^(\d+ )/;
8130    $current_rx = $1;
8131    return() unless $current_rx;
8132
8133    # alter the keys which start as $current_key
8134    foreach $next (@keys) {
8135	if ($next =~ /^$current_rx/) {
8136	    # make current document the root
8137	    $change_key = '0 '.$';
8138	    $toc_section_info{$change_key} = $toc_section_info{$next};
8139	    $section_info{$change_key} = $section_info{$next};
8140#	    if (!($next eq $current_key)) {
8141#		$toc_section_info{$next} = $section_info{$next} = '';
8142#	    }
8143	}
8144    }
8145}
8146
8147sub top_page {
8148    local($file, @navigation_panel) = @_;
8149    # It is the top page if there is a link to itself
8150    join('', @navigation_panel) =~ /$file/;
8151}
8152
8153# Sets global variable $AUX_FILE
8154sub process_aux_file {
8155    local(@exts) = ('aux');
8156    push(@exts, 'lof') if (/\\listoffigures/s);
8157    push(@exts, 'lot') if (/\\listoftables/s);
8158    local($_, $status);		# To protect caller from &process_ext_file
8159    $AUX_FILE = 1;
8160    foreach $auxfile (@exts) {
8161	$status = &process_ext_file($auxfile);
8162	if ($auxfile eq "aux" && ! $status) {
8163	    print "\nCannot open $FILE.aux $!\n";
8164	    &write_warnings("\nThe $FILE.aux file was not found," .
8165			    " so sections will not be numbered \nand cross-references "
8166			    . "will be shown as icons.\n");
8167	}
8168    }
8169    $AUX_FILE = 0;
8170}
8171
8172sub do_cmd_htmlurl {
8173    local($_) = @_;
8174    local($url);
8175    $url = &missing_braces unless (
8176	(s/$next_pair_pr_rx/$br_id=$1;$url=$2;''/e)
8177	||(s/$next_pair_rx/$br_id=$1;$url=$2;''/e));
8178    $url =~ s/\\(html)?url\s*($O|$OP)([^<]*)\2/$3/;
8179    $url =~ s/\\?~/;SPMtilde;/og;
8180    join('','<TT>', &make_href($url,$url), '</TT>', $_);
8181}
8182sub do_cmd_url { &do_cmd_htmlurl(@_) }
8183
8184sub make_href { &make_real_href(@_) }
8185sub make_real_href {
8186    local($link, $text) = @_;
8187    $href_name++;
8188    my $htarget = '';
8189    $htarget = ' target="'.$target.'"'
8190	if (($target)&&($HTML_VERSION > 3.2));
8191    #HWS: Nested anchors not allowed.
8192    $text =~ s/<A .*><\/A>//go;
8193    $text =~ s:<A [^>]*>([^<]+)</A>:$1:gi;
8194    #JKR: ~ is handled different - &#126; is turned to ~ later.
8195    #$link =~ s/&#126;/$percent_mark . "7E"/geo;
8196    if ($text eq $link) { $text =~ s/~/&#126;/g; }
8197    $link =~ s/~/&#126;/g;
8198    # catch \url or \htmlurl
8199    $link =~ s/\\(html)?url\s*(($O|$OP)\d+($C|$CP))([^<]*)\2/$5/;
8200    $link =~ s:(<TT>)?<A [^>]*>([^<]*)</A>(</TT>)?(([^<]*)|$):$2$4:;
8201    # this should not be here; else TOC, List of Figs, etc. fail:
8202    # $link =~ s/^\Q$CURRENT_FILE\E(\#)/$1/ unless ($SEGMENT||$SEGMENTED);
8203    $text = &simplify($text);
8204    "<A NAME=\"tex2html$href_name\"$htarget\n  HREF=\"$link\">$text</A>";
8205}
8206
8207sub make_href_noexpand { # clean
8208    my ($link, $name, $text) = @_;
8209    do {$name = "tex2html". $href_name++} unless $name;
8210    #HWS: Nested anchors not allowed.
8211    $text =~ s/<A .*><\/A>//go;
8212    #JKR: ~ is handled different - &#126; is turned to ~ later.
8213    #$link =~ s/&#126;/$percent_mark . "7E"/geo;
8214    if ($text eq $link) { $text =~ s/~/&#126;/g; }
8215    $link =~ s/~/&#126;/g;
8216    # catch \url or \htmlurl
8217    $link =~ s/\\(html)?url\s*(($O|$OP)\d+($C|$CP))([^<]*)\2/$5/;
8218    $link =~ s:(<TT>)?<A [^>]*>([^<]*)</A>(</TT>)?(([^<]*)|$):$2$4:;
8219    "<A NAME=\"$name\"\n HREF=\"$link\">$text</A>";
8220}
8221
8222sub make_named_href {
8223    local($name, $link, $text) = @_;
8224    $text =~ s/<A .*><\/A>//go;
8225    $text = &simplify($text);
8226    if ($text eq $link) { $text =~ s/~/&#126;/g; }
8227    $link =~ s/~/&#126;/g;
8228    # catch \url or \htmlurl
8229    $link =~ s/\\(html)?url\s*(($O|$OP)\d+($C|$CP))([^<]*)\2/$5/;
8230    $link =~ s:(<TT>)?<A [^>]*>([^<]*)</A>(</TT>)?(([^<]*)|$):$2$4:;
8231    if (!($name)) {"<A\n HREF=\"$link\">$text</A>";}
8232    elsif ($text =~ /^\w/) {"<A NAME=\"$name\"\n HREF=\"$link\">$text</A>";}
8233    else {"<A NAME=\"$name\"\n HREF=\"$link\">$text</A>";}
8234}
8235
8236sub make_section_heading {
8237    local($text, $level, $anchors) = @_;
8238    local($elevel) = $level; $elevel =~ s/^(\w+)\s.*$/$1/;
8239    local($section_tag) = join('', @curr_sec_id);
8240    local($align,$pre_anchors);
8241
8242    # separate any invisible anchors or alignment, if this has not already been done
8243    if (!($anchors)){ ($anchors,$text) = &extract_anchors($text) }
8244    else {
8245	$anchors =~ s/(ALIGN=\"\w*\")/$align = " $1";''/e;
8246	$align = '' if ($HTML_VERSION < 2.2);
8247	$anchors = &translate_commands($anchors) if ($anchors =~ /\\/);
8248    }
8249
8250    # strip off remains of bracketings
8251    $text =~ s/$OP\d+$CP//g;
8252    if (!($text)) {
8253	# anchor to a single `.' only
8254	$text = "<A NAME=\"SECTION$section_tag\">.</A>$anchors\n";
8255    } elsif ($anchors) {
8256#	# put anchors immediately after, except if title is too long
8257#	if ((length($text)<60 )&&(!($align)||($align =~/left/))) {
8258#	    $text = "<A NAME=\"SECTION$section_tag\">$text</A>\n" . $anchors;
8259	# ...put anchors preceding the title, on a separate when left-aligned
8260#	} else {
8261	    $text = "<A NAME=\"SECTION$section_tag\">$anchor_invisible_mark</A>$anchors"
8262		. (!($align)||($align =~ /left/i ) ? "<BR>" : "") . "\n". $text;
8263#	}
8264    } elsif (!($text =~ /<A[^\w]/io)) {
8265	# no embedded anchors, so anchor it all
8266	$text = "<A NAME=\"SECTION$section_tag\">\n" . $text . "</A>";
8267    } else {
8268	# there are embedded anchors; these cannot be nested
8269	local ($tmp) = $text;
8270	$tmp =~ s/<//o ;	# find 1st <
8271	if ($`) {		# anchor text before the first <
8272#	    $text = "<A NAME=\"SECTION$section_tag\">\n" . $` . "</A>\n<" . $';
8273	    $text = "<A NAME=\"SECTION$section_tag\">\n" . $` . "</A>";
8274	    $pre_anchors = "<" . $';
8275	    if ($pre_anchors =~ /^(<A NAME=\"[^\"]+>${anchor_invisible_mark}<\/A>\s*)+$/) {
8276		$pre_anchors .= "\n"
8277	    } else { $text .= $pre_anchors; $pre_anchors = '' }
8278	} else {
8279	    # $text starts with a tag
8280	    local($after,$tmp) = ($','');
8281	    if ( $after =~ /^A[^\w]/i ) {
8282		# it is an anchor already, so need a separate line
8283		$text = "<A NAME=\"SECTION$section_tag\">$anchor_invisible_mark</A><BR>\n$text";
8284	    } else {
8285		# Is it a tag enclosing the anchor ?
8286		$after =~ s/^(\w)*[\s|>]/$tmp = $1;''/eo;
8287		if ($after =~ /<A.*<\/$tmp>/) {
8288		    # it encloses an anchor, so use anchor_mark + break
8289		    $text = "<A NAME=\"SECTION$section_tag\">$anchor_invisible_mark</A><BR>\n$text";
8290		} else {
8291		    # take up to the anchor
8292		    $text =~ s/^(.*)<A([^\w])/"<A NAME=\"SECTION$section_tag\">$1<A$2"/oe;
8293		}
8294	    }
8295	}
8296    }
8297    "$pre_anchors\n<$level$align>$text\n<\/$elevel>";
8298}
8299
8300sub do_cmd_captionstar { &process_cmd_caption(1, @_) }
8301sub do_cmd_caption { &process_cmd_caption('', @_) }
8302sub process_cmd_caption {
8303    local($noLOTentry, $_) = @_;
8304    local($text,$opt,$br_id, $contents);
8305    local($opt) = &get_next_optional_argument;
8306    $text = &missing_braces unless (
8307	(s/$next_pair_pr_rx/$br_id=$1;$text=$2;''/e)
8308	||(s/$next_pair_rx/$br_id=$1;$text=$2;''/e));
8309
8310    # put it in $contents, so &extract_captions can find it
8311    local($contents) = join('','\caption', ($opt ? "[$opt]" : '')
8312	   , "$O$br_id$C" , $text , "$O$br_id$C");
8313
8314    # $cap_env is set by the surrounding figure/table
8315    &extract_captions($cap_env);
8316    $contents.$_;
8317}
8318
8319sub extract_captions {
8320    # Uses and modifies $contents and $cap_anchors, defined in translate_environments
8321    # and modifies $figure_captions, $table_captions, $before and $after
8322    # MRO: no effect! local($env,*cap_width) = @_;
8323    local($env) = @_;
8324    local(%captions, %optional_captions, $key, $caption, $optional_caption,
8325	  $item, $type, $list, $extra_list, $number, @tmp, $br_id, $_, $bcaption);
8326    # associate the br_id of the caption with the argument of the caption
8327    $contents =~ s/$caption_rx(\n)?/do {
8328	$key = $9; $caption = $10; $optional_caption = $3;
8329	$key = &filter_caption_key($key) if (defined &filter_caption_key);
8330	$optional_captions{$key} = $optional_caption||$caption;
8331        print "PCT: nowhere captions: key: $key - caption: " . $captions{$key} ; "\n" if ($VERBOSITY > 10) ;
8332	$captions{$key} = $10; ''}/ego;
8333#	$captions{$9} = $10; $caption_mark }/ego;
8334    $key = $caption = $optional_caption = '';
8335
8336    #catch any  \captionwidth  settings that may remain
8337    $contents =~ s/$caption_width_rx(\n)?/&translate_commands($&);''/eo;
8338
8339#    $after = join("","<P>",$after) if ($&);
8340#    $before .= "</P>" if ($&);
8341    #JKR: Replaced "Figure" and "Table" with variables (see latex2html.config too).
8342    if ($env eq 'figure') {
8343	if ((defined &do_cmd_figurename)||$new_command{'figurename'}){
8344	    $br_id = ++$global{'max_id'};
8345	    $type = &translate_environments("$O$br_id$C\\figurename$O$br_id$C")
8346		unless ($noLOFentry);
8347	} else { $type = $fig_name }
8348	$list = "\$figure_captions";
8349#	$extra_list = "\$segment_figure_captions" if ($figure_table_captions);
8350	$extra_list = "\$segment_figure_captions" if ($segment_figure_captions);
8351    }
8352    elsif ($env =~ /table/) {
8353	print "PCT: extract_captions: table: $env\n" if ($VERBOSITY > 10) ;
8354	if ((defined &do_cmd_tablename)||$new_command{'tablename'}) {
8355	    print "PCT: extract_captions: tablename...\n" if ($VERBOSITY > 10) ;
8356	    $br_id = ++$global{'max_id'};
8357	    $type = &translate_environments("$O$br_id$C\\tablename$O$br_id$C") unless ($noLOTentry);
8358	}
8359	else {
8360	    $type = $tab_name ;
8361	}
8362	$list = "\$table_captions";
8363	$extra_list = "\$segment_table_captions" if ($segment_table_captions);
8364	print "PCT: extract_captions: tab_name: $tab_name - type: $type - list: $list et $table_captions - extra_list: $extra_list\n" if ($VERBOSITY > 10) ;
8365    }
8366
8367#    $captions = "";
8368    $cap_anchors = "";
8369    local($this);
8370    foreach $key (sort {$a <=> $b;} keys %captions){ # Sort numerically
8371	$this = $captions{$key};
8372	$this =~ s/\\label\s*($O\d+$C)[^<]+\1//g; # remove \label commands
8373       	local($br_id) = ++$global{'max_id'};
8374	local($open_tags_R) = []; # locally, initially no style
8375	$caption = &translate_commands(&translate_environments("$O$br_id$C$this$O$br_id$C"));
8376
8377	# same again for the optional caption
8378	$this = $optional_captions{$key};
8379	$this =~ s/\\label\s*($O\d+$C)[^<]+\1//g; # remove \label commands
8380	local($open_tags_R) = []; local($br_id) = ++$global{'max_id'};
8381	$this = &translate_environments("$O$br_id$C$this$O$br_id$C");
8382	$optional_caption = &translate_commands($this);
8383
8384	$cap_anchors .= "<A NAME=\"$key\">$anchor_mark</A>";
8385	$_ = $optional_caption || $caption;
8386
8387
8388	# split at embedded anchor or citation marker
8389	local($pre_anchor,$post_anchor) = ('','');
8390	if (/\s*(<A\W|\#[^#]*\#<tex2html_cite_[^>]*>)/){
8391	    $pre_anchor = "$`";
8392	    $post_anchor = "$&$'";
8393	    $pre_anchor = $anchor_invisible_mark
8394		unless (($pre_anchor)||($SHOW_SECTION_NUMBERS));
8395	} else {
8396	    $pre_anchor = "$_";
8397	}
8398
8399#JCL(jcl-tcl)
8400##	&text_cleanup;
8401##	$_ = &encode_title($_);
8402##	s/&nbsp;//g;            # HWS - LaTeX changes ~ in its .aux files
8403#	$_ = &sanitize($_);
8404##
8405#	$_ = &revert_to_raw_tex($_);
8406
8407	#replace image-markers by the image params
8408	s/$image_mark\#([^\#]+)\#/&purify_caption($1)/e;
8409
8410	local($checking_caption, $cap_key) = (1, $_);
8411	$cap_key = &simplify($cap_key);
8412	$cap_key = &sanitize($cap_key);
8413	@tmp = split(/$;/, eval ("\$encoded_$env" . "_number{\$cap_key}"));
8414	$number = shift(@tmp);
8415	$number = "" if ($number eq "-1");
8416
8417	if (!$number) {
8418	    $cap_key = &revert_to_raw_tex($cap_key);
8419	    @tmp = split(/$;/
8420	       , eval ("\$encoded_$env" . "_number{\$cap_key}"));
8421	    $number = shift(@tmp);
8422	    $number = "" if ($number eq "-1");
8423	}
8424
8425	#resolve any embedded cross-references first
8426	$checking_caption = '';
8427	$_ = &simplify($_);
8428	$_ = &sanitize($_);
8429
8430
8431#	@tmp = split(/$;/, eval ("\$encoded_$env" . "_number{\$_}"));
8432#	$number = shift(@tmp);
8433#	$number = "" if ($number eq "-1");
8434
8435	&write_warnings(qq|\nNo number for "$_"|) if (! $number);
8436	eval("\$encoded_$env" . "_number{\$_} = join(\$;, \@tmp)");
8437
8438	$item = join( '', ($SHOW_SECTION_NUMBERS ? $number."\. " : '')
8439	    , &make_href("$CURRENT_FILE#$key", $pre_anchor)
8440	    , $post_anchor);
8441	undef $_;
8442	undef @tmp;
8443
8444	$bcaption = join("",($bcaption) ? $bcaption : '', $caption) ;
8445	$captions = join("", ($captions ? $captions."\n<BR>\n" : '')
8446		, "<STRONG>$type" , ($number ? " $number:" : ":")
8447		, "</STRONG>\n$caption" , (($captions) ? "\n" : "" ));
8448
8449	do {
8450	    eval "$extra_list .= \"\n<LI>\" .\$item" if ($extra_list);
8451	    eval "$list .= \"\n<LI>\" .\$item"
8452	} unless ( $noLOTentry || $noLOFentry);
8453	#	eval("print \"\nCAPTIONS:\".$extra_list.\n\"");
8454    }
8455    $bcaption ;
8456}
8457
8458
8459# This processes \label commands found in environments that will
8460# be handed over to Latex. Sets the table %symbolic_labels
8461sub do_labels {
8462    local($context,$new_context) = @_;
8463    local($label);
8464    # MRO: replaced $* by /m
8465    $context =~ s/\s*$labels_rx/do {
8466	$label = &do_labels_helper($2);
8467	$new_context = &anchor_label($label,$CURRENT_FILE,$new_context);""}/geom;
8468    $new_context;
8469}
8470
8471sub extract_labels {
8472    local($_) = @_;
8473    local($label,$anchors);
8474    # MRO: replaced $* by /m
8475    while (s/[ \t]*$labels_rx//om) {
8476        $label = &do_labels_helper($2);
8477        $anchors .= &anchor_label($label,$CURRENT_FILE,'');
8478    }
8479    ($_, $anchors);
8480}
8481
8482# This should be done inside the substitution but it doesn't work ...
8483sub do_labels_helper {
8484    local($_) = @_;
8485    s/$label_rx/_/g;  # replace non-alphanumeric characters
8486    $symbolic_labels{$_} = $latex_labels{$_}; # May be empty;
8487    $_;
8488}
8489
8490sub convert_to_description_list {
8491    # MRO: modified to use $_[1]
8492    # local($which, *list) = @_;
8493    my $which = $_[0];
8494    $_[1] =~ s!(</A>\s*)<[OU]L([^>]*)>!$1<DD><DL$2>!ig;
8495    $_[1] =~ s!<(/?)[OU]L([^>]*)>!$1? "<$1DL$2>":"<DL$2>"!eig;
8496    $_[1] =~ s!(</?)LI>!$1D$which>!ig;
8497#    $_[1] =~ s/^\s*<DD>//;
8498}
8499
8500sub add_toc { &add_real_toc(@_) }
8501sub add_real_toc {
8502    local($temp1, $temp2);
8503    print "\nDoing table of contents ...";
8504    local(@keys) = keys %toc_section_info;
8505    @keys = sort numerically @keys;
8506    $temp1 = $MAX_LINK_DEPTH; $temp2 = $MAX_SPLIT_DEPTH;
8507    $MAX_SPLIT_DEPTH = $MAX_LINK_DEPTH = 1000;
8508    #JKR: Here was a "Contents" - replaced it with $toc_title
8509    local($base_key) = $keys[0];
8510    if ($MULTIPLE_FILES) {
8511    	$base_key = $THIS_FILE;
8512    }
8513    local($title);
8514    if ((defined &do_cmd_contentsname)||$new_command{'contentsname'}) {
8515	local($br_id)=++$global{'max_id'};
8516	$title = &translate_environments("$O$br_id$C\\contentsname$O$br_id$C");
8517    } else { $title = $toc_title }
8518    local($toc,$on_first_page) = ('','');
8519    $on_first_page = $CURRENT_FILE
8520	unless ($MAX_SPLIT_DEPTH && $MAX_SPLIT_DEPTH <1000);
8521    $toc = &add_child_links($title,$on_first_page,'',1,$keys[0],@keys);
8522    &convert_to_description_list('T',$toc) if ($use_description_list);
8523    s/$toc_mark/$toc/;
8524    $MAX_LINK_DEPTH = $temp1; $MAX_SPLIT_DEPTH = $temp2;
8525}
8526
8527# Assign ref value, but postpone naming the label
8528sub make_half_href {
8529    local($link) = $_[0];
8530    $href_name++;
8531    "<A NAME=\"tex2html$href_name\"\n HREF=\"$link\">";
8532}
8533
8534
8535# Redefined in makeidx.perl
8536sub add_idx {
8537    local($sidx_style, $eidx_style) =('<STRONG>','</STRONG>');
8538    if ($INDEX_STYLES) {
8539	if ($INDEX_STYLES =~/,/) {
8540	local(@styles) = split(/\s*,\s*/,$INDEX_STYLES);
8541	    $sidx_style = join('','<', join('><',@styles) ,'>');
8542	    $eidx_style = join('','</', join('></',reverse(@styles)) ,'>');
8543	} else {
8544	    $sidx_style = join('','<', $INDEX_STYLES,'>');
8545	    $eidx_style = join('','</', $INDEX_STYLES,'>');
8546	}
8547    }
8548    &add_real_idx(@_)
8549}
8550sub add_real_idx {
8551    print "\nDoing the index ...";
8552    local($key, $str, @keys, $index, $level, $count,
8553	  @previous, @current);
8554    @keys = keys %index;
8555    @keys = sort keysort  @keys;
8556    $level = 0;
8557    foreach $key (@keys) {
8558	@current = split(/!/, $key);
8559	$count = 0;
8560	while ($current[$count] eq $previous[$count]) {
8561	    $count++;
8562	}
8563	while ($count > $level) {
8564	    $index .= "\n<DL COMPACT>";
8565	    $level++;
8566	}
8567	while ($count < $level) {
8568	    $index .= "\n</DL>";
8569	    $level--;
8570	}
8571	foreach $term (@current[$count .. $#current-1]) {
8572	    # need to "step in" a little
8573#	    $index .= "<DT>" . $term . "\n<DL COMPACT>";
8574	    $index .= "\n<DT>$sidx_style" . $term . "$eidx_style\n<DD><DL COMPACT>";
8575	    $level++;
8576	}
8577	$str = $current[$#current];
8578	$str =~ s/\#\#\#\d+$//o; # Remove the unique id's
8579	$index .= $index{$key} .
8580	    # If it's the same string don't start a new line
8581	    (&index_key_eq(join('',@current), join('',@previous)) ?
8582	     ", $sidx_style" . $cross_ref_visible_mark . "$eidx_style</A>\n" :
8583	     "<DT>$sidx_style" . $str . "$eidx_style</A>\n");
8584	@previous = @current;
8585    }
8586    while ($count < $level) {
8587	$index .= "\n</DL>";
8588	$level--;
8589    }
8590    $index = '<DD>'.$index unless ($index =~ /^\s*<D(T|D)>/);
8591
8592    $index =~ s/(<A [^>]*>)(<D(T|D)>)/$2$1/g;
8593
8594#    s/$idx_mark/<DL COMPACT>$index<\/DL>/o;
8595    s/$idx_mark/$preindex\n<DL COMPACT>\n$index<\/DL>\n/o;
8596}
8597
8598sub keysort {
8599    local($x, $y) = ($a,$b);
8600    $x = &clean_key($x);
8601    $y = &clean_key($y);
8602#    "\L$x" cmp "\L$y";  # changed sort-rules, by M Ernst.
8603    # Put alphabetic characters after symbols; already downcased
8604    $x =~ s/^([a-z])/~~~$1/;
8605    $y =~ s/^([a-z])/~~~$1/;
8606    $x cmp $y;
8607}
8608
8609sub index_key_eq {
8610    local($a,$b) = @_;
8611    $a = &clean_key($a);
8612    $b = &clean_key($b);
8613    $a eq $b;
8614}
8615
8616sub clean_key {
8617    local ($_) = @_;
8618    tr/A-Z/a-z/;
8619    s/\s+/ /g;		# squeeze white space and newlines into space
8620    s/ (\W)/$1/g;	# make foo( ), foo () and foo(), or <TT>foo</TT>
8621    ;			# and <TT>foo </TT> to be equal
8622    s/$O\d+$C//go;	# Get rid of bracket id's
8623    s/$OP\d+$CP//go;	# Get rid of processed bracket id's
8624    s/\#\#\#\d+$//o;	# Remove the unique id
8625    $_;
8626}
8627
8628
8629sub make_footnotes {
8630    # Uses $footnotes defined in translate and set in do_cmd_footnote
8631    # Also uses $footfile
8632    local($_) = "\n<DL>$footnotes\n<\/DL>";
8633    $footnotes = ""; # else they get used
8634    local($title);
8635    if ((defined &do_cmd_footnotename)||$new_command{'footnotename'}) {
8636	local($br_id)=++$global{'max_id'};
8637	$title = &translate_environments("$O$br_id$C\\footnotename$O$br_id$C");
8638    } else {
8639	$foot_title = "Footnotes" unless $foot_title;
8640	$title = $foot_title;
8641    }
8642    print "\nDoing footnotes ...";
8643#JCL(jcl-tcl)
8644# If the footnotes go into a separate file: see &make_file.
8645    if ($footfile) {
8646	$toc_sec_title = $title;
8647	&make_file($footfile, $title, $FOOT_COLOR); # Modifies $_;
8648	$_ = "";
8649    } else {
8650	$footnotes = ""; # else they get re-used
8651	$_ = join ('', '<BR><HR><H4>', $title, '</H4>', $_ );
8652    }
8653    $_;
8654}
8655
8656sub post_process_footnotes {
8657    &slurp_input($footfile);
8658    open(OUT, ">$footfile") || die "Cannot write file '$footfile': $!\n";
8659    &replace_markers;
8660    &post_post_process if (defined &post_post_process);
8661    &adjust_encoding;
8662    print OUT $_;
8663    close OUT;
8664}
8665
8666sub make_file {
8667    # Uses and modifies $_ defined in the caller
8668    local($filename, $title, $layout) = @_;
8669    $layout = $BODYTEXT unless $layout;
8670    $_ = join('',&make_head_and_body($title,$layout), $_
8671	, (($filename =~ /^\Q$footfile\E$/) ? '' : &make_address )
8672	, (($filename =~ /^\Q$footfile\E$/) ? "\n</BODY>\n</HTML>\n" : '')
8673	);
8674    &replace_markers unless ($filename eq $footfile);
8675
8676    unless(open(FILE,">$filename")) {
8677        print "\nError: Cannot write '$filename': $!\n";
8678        return;
8679    }
8680    print FILE $_;
8681    close(FILE);
8682}
8683
8684sub add_to_body {
8685    local($attrib, $value) = @_;
8686    local($body) = $BODYTEXT;
8687    if ($body =~ s/\Q$attrib\E\s*=\s*"[^"]*"/$attrib="$value"/) {
8688    } else {
8689	$body .= " $attrib=\"$value\""; $body =~ s/\s{2,}/ /g;
8690    }
8691    $BODYTEXT = $body if $body;
8692}
8693
8694sub replace_verbatim_marks {
8695    # Modifies $_
8696    my($tmp);
8697    s/$math_verbatim_rx/&make_comment('MATH', $verbatim{$1})/eg;
8698    s/$mathend_verbatim_rx/&make_comment('MATHEND', '')/eg;
8699#    s/$verbatim_mark(verbatim\*?)(\d+)#/<PRE>\n$verbatim{$2}\n<\/PRE>/go;
8700##    s/$verbatim_mark(\w*[vV]erbatim\*?)(\d+)#/\n$verbatim{$2}\n/go;
8701    s!$verbatim_mark(\w*[vV]erbatim\*?|tex2html_code)(\d+)#\n?!$tmp=$verbatim{$2};
8702	$tmp.(($tmp =~/\n\s*$/s)? '':"\n")!eg;
8703#	"\n".$tmp.(($tmp =~/\n\s*$/s)? '':"\n")!eg;
8704#    s/$verbatim_mark(rawhtml)(\d+)#/$verbatim{$2}/eg; # Raw HTML
8705    s/$verbatim_mark(imagesonly)(\d+)#//eg; # imagesonly is *not* replaced
8706    # Raw HTML, but replacements may have protected characters
8707    s/$verbatim_mark(rawhtml)(\d+)#/&unprotect_raw_html($verbatim{$2})/eg;
8708    s/$verbatim_mark$keepcomments_rx(\d+)#/$verbatim{$2}/ego; # Raw TeX
8709    s/$unfinished_mark$keepcomments_rx(\d+)#/$verbatim{$2}/ego; # Raw TeX
8710}
8711
8712# TeX's special characters may have been escaped with a '\'; remove it.
8713sub unprotect_raw_html {
8714    local($raw) = @_;
8715    $raw =~ s/\\($latex_specials_rx|~|\^|@)/$1/g;
8716    $raw;
8717}
8718
8719# remove file-markers; special packages may redefine &replace_file_marks
8720sub remove_file_marks {
8721    s/<(DD|LI)>\n?($file_mark|$endfile_mark)\#.*\#\n<\/\1>(\n|(<))/$4/gm;
8722    s/($file_mark|$endfile_mark)\#.*\#(\n|(<))/$3/gm;
8723}
8724sub replace_file_marks { &remove_file_marks }
8725
8726sub remove_verbatim_marks {
8727    # Modifies $_
8728    s/($math_verbatim_rx|$mathend_verbatim_rx)//go;
8729#    s/$verbatim_mark(verbatim\*?)(\d+)#//go;
8730    s/$verbatim_mark(\w*[Vv]erbatim\w*\*?)(\d+)#//go;
8731    s/$verbatim_mark(rawhtml|imagesonly)(\d+)#//go;
8732    s/$verbatim_mark$keepcomments_rx(\d+)#//go;
8733    s/$unfinished_mark$keepcomments_rx(\d+)#//go;
8734}
8735
8736sub replace_verb_marks {
8737    # Modifies $_
8738    s/(?:$verb_mark|$verbstar_mark)(\d+)$verb_mark/
8739	$code = $verb{$1};
8740	$code = &replace_comments($code) if ($code =~ m:$comment_mark:);
8741	"<code>$code<\/code>"/ego;
8742}
8743
8744sub replace_comments{
8745    local($_) = @_;
8746    $_ =~ s/$comment_mark(\d+)\n?/$verbatim{$1}/go;
8747    $_ =~ s/$comment_mark\d*\n/%\n/go;
8748    $_;
8749}
8750
8751sub remove_verb_marks {
8752    # Modifies $_
8753    s/($verb_mark|$verbstar_mark)(\d+)$verb_mark//go;
8754}
8755
8756# This is used by revert_to_raw_tex
8757sub revert_verbatim_marks {
8758    # Modifies $_
8759#    s/$verbatim_mark(verbatim)(\d+)#/\\begin{verbatim}$verbatim{$2}\\end{verbatim}\n/go;
8760    s/$verbatim_mark(\w*[Vv]erbatim)(\d+)#/\\begin{$1}\n$verbatim{$2}\\end{$1}\n/go;
8761    s/$verbatim_mark(rawhtml)(\d+)#/\\begin{rawhtml}\n$verbatim{$2}\\end{rawhtml}\n/go;
8762    s/$verbatim_mark(imagesonly|tex2html_code)(\d+)#\n?/$verbatim{$2}/go;
8763    s/$verbatim_mark$image_env_rx(\d+)#/\\begin{$1}\n$verbatim{$2}\\end{$1}\n/go;
8764    s/($math_verbatim_rx|$mathend_verbatim_rx)//go;
8765}
8766
8767sub revert_verb_marks {
8768    # Modifies $_
8769    s/$verbstar_mark(\d+)$verb_mark/\\verb*$verb_delim{$1}$verb{$1}$verb_delim{$1}/go;
8770    s/$verb_mark(\d+)$verb_mark/\\verb$verb_delim{$1}$verb{$1}$verb_delim{$1}/go;
8771}
8772
8773sub replace_cross_ref_marks {
8774    # Modifies $_
8775    local($label,$id,$ref_label,$ref_mark,$after,$name);
8776    local($invis) = "<tex2html_anchor_invisible_mark></A>";
8777#    s/$cross_ref_mark#([^#]+)#([^>]+)>$cross_ref_mark/
8778    s/$cross_ref_mark#([^#]+)#([^>]+)>$cross_ref_mark<\/A>(\s*<A( NAME=\"\d+)\">$invis)?/
8779	do {($label,$id) = ($1,$2); $name = $4;
8780	    $ref_label = $external_labels{$label} unless
8781		($ref_label = $ref_files{$label});
8782	    print "\nXLINK<: $label : $id :$name " if ($VERBOSITY > 3);
8783	    $ref_label = '' if ($ref_label eq $CURRENT_FILE);
8784	    $ref_mark = &get_ref_mark($label,$id);
8785	    &extend_ref if ($name); $name = '';
8786	    print "\nXLINK: $label : $ref_label : $ref_mark " if ($VERBOSITY > 3);
8787	    '"' . "$ref_label#$label" . "\">" . $ref_mark . "<\/A>"
8788	}/geo;
8789
8790    # This is for pagerefs which cannot have symbolic labels ???
8791#    s/$cross_ref_mark#(\w+)#\w+>/
8792    s/$cross_ref_mark#([^#]+)#[^>]+>/
8793	do {$label = $1;
8794	    $ref_label = $external_labels{$label} unless
8795		($ref_label = $ref_files{$label});
8796	    $ref_label = '' if ($ref_label eq $CURRENT_FILE);
8797	    print "\nXLINKP: $label : $ref_label" if ($VERBOSITY > 3);
8798	    '"' . "$ref_files{$label}#$label" . "\">"
8799	}/geo;
8800}
8801
8802#RRM: this simply absorbs the name from the invisible anchor following,
8803#     when the anchor itself is not already named.
8804sub extend_ref {
8805    if ($ref_label !=~ /NAME=/) { $label .= "\"\n".$name  }
8806}
8807
8808sub remove_cross_ref_marks {
8809    # Modifies $_
8810#    s/$cross_ref_mark#(\w+)#(\w+)>$cross_ref_mark/
8811    s/$cross_ref_mark#([^#]+)#([^>]+)>$cross_ref_mark/
8812	print "\nLOST XREF: $1 : $2" if ($VERBOSITY > 3);''/ego;
8813#    s/$cross_ref_mark#(\w+)#\w+>//go;
8814    s/$cross_ref_mark#([^#]+)#[^#>]+>//go;
8815}
8816
8817sub replace_external_ref_marks {
8818    # Modifies $_
8819    local($label, $link);
8820#    s/$external_ref_mark#(\w+)#(\w+)>$external_ref_mark/
8821    s/$external_ref_mark#([^#]+)#([^>]+)>$external_ref_mark/
8822	do {($label,$id) = ($1,$2);
8823	    $link = $external_labels{$label};
8824	    print "\nLINK: $label : $link" if ($VERBOSITY > 3);
8825	    '"'. "$link#$label" . "\">\n"
8826	       . &get_ref_mark("userdefined$label",$id)
8827	}
8828    /geo;
8829}
8830
8831sub remove_external_ref_marks {
8832    # Modifies $_
8833#    s/$external_ref_mark#(\w+)#(\w+)>$external_ref_mark/
8834    s/$external_ref_mark#([^#]+)#([^>]+)>$external_ref_mark/
8835	print "\nLOST LINK: $1 : $2" if ($VERBOSITY > 3);''/ego;
8836}
8837
8838sub get_ref_mark {
8839    local($label,$id) = @_;
8840    ( ( $SHOW_SECTION_NUMBERS && $symbolic_labels{"$label$id"}) ||
8841     $latex_labels{"userdefined$label$id"} ||
8842     $symbolic_labels{"$label$id"} ||
8843     $latex_labels{$label} ||
8844     $external_latex_labels{$label} ||
8845     $cross_ref_visible_mark );
8846}
8847
8848sub replace_bbl_marks {
8849    # Modifies $_
8850    s/$bbl_mark#([^#]+)#/$citations{$1}/go;
8851}
8852
8853sub remove_bbl_marks {
8854    # Modifies $_
8855    s/$bbl_mark#([^#]+)#//go;
8856}
8857
8858sub replace_image_marks {
8859    # Modifies $_
8860    s/$image_mark#([^#]+)#([\.,;:\)\]])?(\001)?([ \t]*\n?)(\001)?/
8861	"$id_map{$1}$2$4"/ego;
8862#	"$id_map{$1}$2".(($4)?"\n":'')/ego;
8863}
8864
8865sub remove_image_marks {
8866    # Modifies $_
8867    s/$image_mark#([^#]+)#//go;
8868}
8869
8870sub replace_icon_marks {
8871    # Modifies $_
8872    if ($HTML_VERSION < 2.2 ) {
8873	local($icon);
8874	s/$icon_mark_rx/$icon = &img_tag($1);
8875	    $icon =~ s| BORDER="?\d+"?||;$icon/ego;
8876    } else {
8877	s/$icon_mark_rx/&img_tag($1)/ego;
8878    }
8879}
8880
8881sub remove_icon_marks {
8882    # Modifies $_
8883    s/$icon_mark_rx//go;
8884}
8885
8886sub replace_cite_marks {
8887    local($key,$label,$text,$file);
8888    # Modifies $_
8889    # Uses $citefile set by the thebibliography environment
8890    local($citefile) = $citefile;
8891    $citefile =~ s/\#.*$//;
8892
8893    s/#([^#]+)#$cite_mark#([^#]+)#((($OP\d+$CP)|[^#])*)#$cite_mark#/
8894	$text = $3; $label= $1; $file='';
8895	$text = $cite_info{$1} unless $text;
8896	if ($checking_caption){
8897	    "$label"
8898	} elsif ($citefiles{$2}){
8899	    $file = $citefiles{$2}; $file =~ s:\#.*$::;
8900	    &make_named_href('', "$file#$label","$text");
8901	} elsif ($PREAMBLE) {
8902	    $text || "\#!$1!\#" ;
8903	} elsif ($simplifying) {
8904	    $text
8905	} else {
8906	     &write_warnings("\nno reference for citation: $1");
8907	     "\#!$1!\#"
8908	}/sge ;
8909    #
8910    #RRM: Associate the cite_key with  $citefile , for use by other segments.
8911    if ($citefile) {
8912	local($cite_key, $cite_ref);
8913	while (($cite_key, $cite_ref) = each %cite_info) {
8914	    if ($ref_files{'cite_'."$cite_key"} ne $citefile) {
8915		$ref_files{'cite_'."$cite_key"} = $citefile;
8916		$changed = 1; }
8917	}
8918    }
8919}
8920
8921sub remove_cite_marks {
8922    # Modifies $_
8923    s/#([^#]+)#$cite_mark#([^#]+)#([^#]*)#$cite_mark#//go;
8924}
8925
8926sub remove_anchors {
8927# modifies $_
8928    s/<A[^>]*>//g;
8929    s/<\/A>//g;
8930}
8931
8932
8933# We need two matching keys to determine section/figure/etc. numbers.
8934# The "keys" are the name of the section/figure/etc. and its
8935# equivalent in the .aux file (also carrying the number we desire).
8936# But both keys might have been translated slightly different,
8937# depending on the usage of math, labels, special characters such
8938# as umlauts, or simply spacing!
8939#
8940# This routine tries to squeeze the HTML translated keys such
8941# that they match (hopefully very often). -- JCL
8942#
8943sub sanitize {
8944    local($_,$mode) = @_;
8945    &remove_markers;
8946    &remove_anchors;
8947    &text_cleanup;
8948    s/(\&|;SPM)nbsp;//g;            # HWS - LaTeX changes ~ in its .aux files
8949    #strip unwanted HTML constructs
8950    s/<\/?(P|BR|H)[^>]*>//g;
8951    s/\s+//g; #collapse white space
8952    $_;
8953}
8954
8955# This one removes any HTML markup, so that pure
8956# plain text remains. (perhaps with <SUP>/<SUB> tags)
8957# As the result will be part of the HTML file, it will be
8958# &text_cleanup'd later together with its context.
8959#
8960sub purify {
8961    local($_,$strict) = @_;
8962    &remove_markers;
8963    #strip unwanted HTML constructs
8964#    s/<[^>]*>/ /g;
8965    s/<(\/?SU[BP])>/>$1>/g unless ($strict);  # keep sup/subscripts ...
8966    s/<[^>]*>//g;                             # remove all other tags
8967    s/>(\/?SU[BP])>/<$1>/g unless ($strict);  # ...reinsert them
8968    s/^\s+|\001//g; s/\s\s+/ /g;              #collapse white space
8969    $_;
8970}
8971
8972# This one is not as strict as &sanitize.
8973# It is chosen to strip section names etc. a bit from
8974# constructs so that it better fits a table of contents,
8975# label files, etc.
8976# As the result will be part of the HTML file, it will be
8977# &text_cleanup'd later together with its context.
8978#
8979sub simplify {
8980    local($_) = @_;
8981    local($simplifying) = 1;
8982    s/$tex2html_envs_rx//g;
8983    if (/\\/) {
8984	local($USING_STYLES) = 0;
8985	$_ = &translate_commands($_);
8986	undef $USING_STYLES;
8987    }
8988    &replace_external_ref_marks if /$external_ref_mark/;
8989    &replace_cross_ref_marks if /$cross_ref_mark||$cross_ref_visible_mark/;
8990    &replace_cite_marks if /$cite_mark/;
8991    # strip unwanted HTML constructs
8992#    s/<\/?H[^>]*>/ /g;
8993    s/<\/?(H)[^>]*>//g;
8994    s/<\#\d+\#>//g;
8995    s/^\s+//;
8996    $_;
8997}
8998
8999#RRM: This extracts $anchor_mark portions from a given chunk of text,
9000#     so they can be positioned separately by the calling subroutine.
9001# added for v97.2:
9002#  search within the immediately following text also; so that
9003#  \index and \label after section-headings work as expected.
9004#
9005sub extract_anchors {
9006    local($search_text, $start_only) = @_;
9007    local($anchors) = '';
9008    local($untranslated_anchors) = '';
9009
9010    do {
9011	while ($search_text =~ s/<A[^>]*>($anchor_mark|$anchor_invisible_mark)<\/A>//) {
9012	    $anchors .= $&;
9013	}
9014    } unless ($start_only);
9015
9016    $search_text =~ s/\s*(\\protect)?\\(label|index|markright|markboth\s*(($O|$OP)\d+($C|$CP))[^<]*\3)\s*(($O|$OP)\d+($C|$CP))[^<]*\6/
9017	$anchors .= $&;''/eg unless ($start_only);
9018
9019    while ( s/^\s*<A[^>]*>($anchor_mark|$anchor_invisible_mark)<\/A>//m) {
9020	$untranslated_anchors .= $&;
9021    }
9022    while ( s/^\s*(\\protect)?\\(label|index|markright|markboth\s*(($O|$OP)\d+($C|$CP))[^<]*\3)\s*(($O|$OP)\d+($C|$CP))[^<]*\6//) {
9023	$untranslated_anchors .= $&;
9024    }
9025    if ($TITLE||$start_only) {
9026	$anchors .= &translate_commands($untranslated_anchors);
9027	$untranslated_anchors = '';
9028    }
9029    ($anchors.$untranslated_anchors,$search_text);
9030}
9031
9032# This routine must be called once on the text only,
9033# else it will "eat up" sensitive constructs.
9034sub text_cleanup {
9035    # MRO: replaced $* with /m
9036    s/(\s*\n){3,}/\n\n/gom;	# Replace consecutive blank lines with one
9037    s/<(\/?)P>\s*(\w)/<$1P>\n$2/gom;      # clean up paragraph starts and ends
9038    s/$O\d+$C//go;		# Get rid of bracket id's
9039    s/$OP\d+$CP//go;		# Get rid of processed bracket id's
9040    s/(<!)?--?(>)?/(length($1) || length($2)) ? "$1--$2" : "-"/ge;
9041    # Spacing commands
9042    s/\\( |$)/ /go;
9043    #JKR: There should be no more comments in the source now.
9044    #s/([^\\]?)%/$1/go;        # Remove the comment character
9045    # Cannot treat \, as a command because , is a delimiter ...
9046    s/\\,/ /go;
9047    # Replace tilde's with non-breaking spaces
9048    s/ *~/&nbsp;/g;
9049
9050    ### DANGEROUS ?? ###
9051    # remove redundant (not <P></P>) empty tags, incl. with attributes
9052    s/\n?<([^PD >][^>]*)>\s*<\/\1>//g;
9053    s/\n?<([^PD >][^>]*)>\s*<\/\1>//g;
9054    # remove redundant empty tags (not </P><P> or <TD> or <TH>)
9055    s/<\/(TT|[^PTH][A-Z]+)><\1>//g;
9056    s/<([^PD ]+)(\s[^>]*)?>\n*<\/\1>//g;
9057
9058
9059#JCL(jcl-hex)
9060# Replace ^^ special chars (according to p.47 of the TeX book)
9061# Useful when coming from the .aux file (german umlauts, etc.)
9062    s/\^\^([^0-9a-f])/chr((64+ord($1))&127)/ge;
9063    s/\^\^([0-9a-f][0-9a-f])/chr(hex($1))/ge;
9064}
9065
9066# This is useful for getting words from a title which are not cluttered
9067# with tex2html markers or HTML constructs
9068sub extract_pure_text {
9069    local($mode) = @_;
9070    &text_cleanup;		# Remove marking brackets
9071#
9072# HWS <hswan@perc.Arco.com>:  Conditionally doing the following
9073#     permits equations in section headings.
9074#
9075    if ($mode eq "strict") {
9076	s/$image_mark#[^#]*#//g;	# Remove image marker
9077	s/$bbl_mark#[^#]*#//g;		# Remove citations marker
9078        s/<tex2html_percent_mark>/%/g;  # BMcM: Retain % signs...
9079        s/<tex2html_ampersand_mark>/\&amp;/g;
9080	s/tex2html[\w\d]*//g; 	# Remove other markers
9081	}
9082
9083#
9084# HWS <hswan@perc.Arco.com>:  Replace next statement with the following two
9085#    to permit symbolic links and images to appear in section headings.
9086
9087#   s/<[^>]*>//go;			# Remove HTML constructs
9088    s/$OP[^#]*$CP//go;			# Remove <# * #> constructs
9089    s/<\s*>//go;			# Remove embedded whitespace
9090}
9091
9092############################ Misc ####################################
9093
9094# MRO: Print standardized header
9095sub banner {
9096    print <<"EOF";
9097This is LaTeX2HTML Version $TEX2HTMLVERSION
9098by Nikos Drakos, Computer Based Learning Unit, University of Leeds.
9099
9100EOF
9101}
9102
9103# MRO: Extract usage information from POD
9104sub usage {
9105    my $start  = 0;
9106    my $usage  = 'Usage: ';
9107    my $indent = '';
9108
9109    print (@_, "\n") if @_;
9110
9111    my $perldoc = "/usr/bin${dd}perldoc";
9112    my $script = $SCRIPT || $0;
9113    open(PIPE, "$perldoc -t $script |")
9114        || die "Fatal: can't open pipe: $!";
9115    while (<PIPE>) {
9116        if (/^\s*$/) {
9117            next;
9118        } elsif (/^SYNOPSIS/) {
9119            $start = 1;
9120        } elsif (/^\w/) {
9121            $start = 0;
9122        } elsif ($start == 1) {
9123            ($indent) = /^(\s*)/;
9124            s/^$indent/$usage/;
9125            $usage =~ s/./ /g;
9126            $start = 2;
9127            print $_;
9128        } elsif ($start == 2) {
9129            s/^$indent/$usage/;
9130            print $_;
9131        }
9132    }
9133    close PIPE;
9134    1;
9135}
9136
9137# The bibliographic references, the appendices, the lists of figures and tables
9138# etc. must appear in the contents table at the same level as the outermost
9139# sectioning command. This subroutine finds what is the outermost level and
9140# sets the above to the same level;
9141sub set_depth_levels {
9142    # Sets $outermost_level
9143    local($level);
9144    # scan the document body, not the preamble, for use of sectioning commands
9145    my ($contents) = $_;
9146    if ($contents =~ /\\begin\s*((?:$O|$OP)\d+(?:$C|$CP))document\1|\\startdocument/s) {
9147	$contents = $';
9148    }
9149    #RRM:  do not alter user-set value for  $MAX_SPLIT_DEPTH
9150    foreach $level ("part", "chapter", "section", "subsection",
9151		    "subsubsection", "paragraph") {
9152	last if (($outermost_level) = $contents =~ /\\($level)$delimiter_rx/);
9153	last if (($outermost_level) = $contents =~ /\\endsegment\s*\[\s*($level)\s*\]/s);
9154	if ($contents =~ /\\segment\s*($O\d+$C)[^<]+\1\s*($O\d+$C)\s*($level)\s*\2/s)
9155		{ $outermost_level = $3; last };
9156    }
9157    $level = ($outermost_level ? $section_commands{$outermost_level} :
9158	      do {$outermost_level = 'section'; 3;});
9159
9160    #RRM:  but calculate value for $MAX_SPLIT_DEPTH when a $REL_DEPTH was given
9161    if ($REL_DEPTH && $MAX_SPLIT_DEPTH) {
9162	$MAX_SPLIT_DEPTH = $level + $MAX_SPLIT_DEPTH;
9163    } elsif (!($MAX_SPLIT_DEPTH)) { $MAX_SPLIT_DEPTH = 1 };
9164
9165    %unnumbered_section_commands = (
9166          'tableofcontents', $level
9167	, 'listoffigures', $level
9168	, 'listoftables', $level
9169	, 'bibliography', $level
9170	, 'textohtmlindex', $level
9171	, 'a', $level
9172        , %unnumbered_section_commands
9173        );
9174
9175    %section_commands = (
9176	  %unnumbered_section_commands
9177        , %section_commands
9178        );
9179}
9180
9181# Now ignores accents which cannot be translated to ISO-LATIN-1 characters
9182# Also replaces ?' and !' ....
9183sub replace_strange_accents {
9184    &real_replace_strange_accents(@_); # if ($CHARSET =~ /8859[_\-]1$/);
9185}
9186sub real_replace_strange_accents {
9187    # Modifies $_;
9188    s/\?`/&iso_map("iquest", "")/geo;
9189    s/!`/&iso_map("iexcl", "")/geo;
9190    s/\\\^\\i /&iso_map("icirc", "")/geo;
9191    my ($charset) = "${CHARSET}_character_map_inv";
9192    $charset =~ s/-/_/g;
9193    # convert upper 8-bit characters
9194    if (%$charset &&($CHARSET =~ /8859[_\-]1$/)) {
9195	s/([\200-\377])/
9196	    $tmp = $$charset{'&#'.ord($1).';'};
9197	    &mark_string($tmp) if ($tmp =~ m!\{!);
9198	    &translate_commands($tmp)
9199	/egos
9200    }
9201};
9202
9203# Creates a new directory or reuses old, perhaps after deleting its contents
9204sub new_dir {
9205    local($this_dir,$mode) = @_;
9206    local(@files)=();
9207    $this_dir = '.' unless $this_dir;
9208    $this_dir =~ s/[$dd$dd]+$//o;
9209    local($print_dir) = $this_dir.$dd;
9210    (!$mode && mkdir($this_dir, 0755)) ||
9211	do {
9212	    print "\nCannot create directory $print_dir: $!" unless ($mode);
9213	    if ($REUSE) {
9214		print ", reusing it.\n" unless ($mode);
9215		&reuse($this_dir,$print_dir);
9216	    } else {
9217	    	print "\n" unless ($mode);
9218		while (! ($answer =~ /^[dqr]$/)) {
9219		    if ($mode) {
9220			$answer = $mode;
9221		    } else {
9222		        print "(r) Reuse the images in the old directory OR\n"
9223			    . (($this_dir eq '.') ?
9224		"(d) *** DELETE *** the images in $print_dir  OR\n"
9225		: "(d) *** DELETE *** THE CONTENTS OF $print_dir  OR\n" )
9226			    . "(q) Quit ?\n:";
9227		        $answer = scalar(<STDIN>);
9228		    };
9229		    if ($answer =~ /^d$/) {
9230                        @files = ();
9231			if(opendir(DIR,$this_dir)) {
9232			    @files = readdir DIR;
9233			    closedir DIR;
9234                        } else {
9235                            print "\nError: Cannot read dir '$this_dir': $!\n";
9236                        }
9237			foreach (@files) {
9238			    next if /^\.+$/;
9239			    if (-d "$this_dir$dd$_") {
9240				&new_dir("$this_dir$dd$_",'d');
9241			    } elsif ($this_dir eq '.') {
9242				L2hos->Unlink($_) if (/\.(pl|gif|png)$/)
9243			    } else {
9244				L2hos->Unlink("$this_dir$dd$_");
9245			    };
9246			}
9247			return(1) if ($this_dir eq '.');
9248			if($mode) {
9249			  rmdir($this_dir);
9250			  rmdir($print_dir);
9251                        }
9252			if (!$mode) { &new_dir($this_dir,'r')};
9253			return(1);
9254		    } elsif ($answer =~ /^q$/) {
9255			die "Bye!\n";
9256		    } elsif ($answer =~ /^r$/) {
9257			&reuse($this_dir,$print_dir);
9258			return(1);
9259		    } else {print "Please answer r d or q!\n";};
9260		}
9261	    };
9262	};
9263    1;
9264}
9265
9266sub reuse {
9267    local($this_dir,$print_dir) = @_;
9268    $print_dir = $this_dir.$dd unless ($print_dir);
9269    if (-f "$this_dir$dd${PREFIX}images.pl") {
9270	print STDOUT "Reusing directory $print_dir:\n";
9271	local($key);
9272	require("$this_dir$dd${PREFIX}images.pl");
9273    }
9274}
9275
9276
9277# JCL(jcl-del) - use $CD rather than a space as delimiter.
9278# The commands might take white space, or not, depending on
9279# their definition. Eg. \relax takes white space, because it's a
9280# letter command, but \/ won't.
9281# TeX seems to have an internal separator: If \x is " x",
9282# and \y is "y", then \expandafter\y \x expands to "y x", TeX
9283# hasn't gobbled the space, meaning that spaces are gobbled once
9284# when the \y token is consumed, but then never again after \y.
9285#
9286# The actions below ensure to insert exactly one space after
9287# the command name.	# what happens to  `\ '  ?
9288# The substition is done twice to handle \one\delimits\another
9289# cases.
9290# The internal shortcut $CD is then turned into the single
9291# space we desire.
9292#
9293sub tokenize {
9294    # Modifies $_;
9295    local($rx) = @_;
9296    # $rx must be specially constructed, see &make_new_cmd_rx.
9297    if (length($rx)) {
9298	# $1: non-letter cmd, or $2: letter cmd
9299	s/$rx/\\$1$2$CD$4/g;
9300	s/$rx/\\$1$2$CD$4/g;
9301	s/$CD+/ /g;	# puts space after each command name
9302    }
9303}
9304
9305# When part of the input text contains special perl characters and the text
9306# is to be used as a pattern then these specials must be escaped.
9307sub escape_rx_chars {
9308    my($rx) = @_; # must use a copy of the string
9309    $rx =~ s:([\\(){}[\]\^\$*+?.|]):\\$1:g; $rx; }
9310
9311# Does not do much but may need it later ...
9312# The document environment has to be removed because it spans
9313# more than one sections (the translator can only deal with
9314# environments wholly contained with sections).
9315
9316# (Does a little more now ... the end of the preamble is now marked
9317# with an internally-generated command which causes all output
9318# erroneously generated from unrecognized commands in the preamble
9319# to vanish --- rst).
9320
9321sub remove_document_env {
9322#    s/\\begin$match_br_rx[d]ocument$match_br_rx/\\latextohtmlditchpreceding /o;
9323    if (/\\begin\s*${match_br_rx}document$match_br_rx/) {
9324        s/\\begin\s*$match_br_rx[d]ocument$match_br_rx/\\latextohtmlditchpreceding /
9325    }
9326#   s/\\end$match_br_rx[d]ocument$match_br_rx(.|\n)*//o;
9327    if (/\\end\s*${match_br_rx}document$match_br_rx/) { $_ = $` }
9328}
9329
9330# And here's the code to handle the marker ...
9331
9332sub do_cmd_latextohtmlditchpreceding {
9333    local($_) = @_;
9334    $ref_before = '';
9335    $_;
9336}
9337
9338print "\n"; # flushes a cache? This helps, for some unknown reason!!
9339
9340sub do_AtBeginDocument{
9341    local($_) = @_;
9342    eval $AtBeginDocument_hook;
9343    $_;
9344}
9345
9346sub cleanup {
9347    local($explicit) = @_;
9348    return unless $explicit || !$DEBUG;
9349
9350    if (opendir(DIR, '.')) {
9351	while (defined($_ = readdir(DIR))) {
9352	    L2hos->Unlink($_)
9353		if /\.ppm$/ || /^${PREFIX}images\.dvi$/ || /^(TMP[-._]|$$\_(image)?)/;
9354	}
9355	closedir (DIR);
9356    }
9357
9358    L2hos->Unlink("WARNINGS") if ($explicit &&(-f "WARNINGS"));
9359
9360    if ($TMPDIR && opendir(DIR, $TMPDIR)) {
9361	local(@files) = grep(!/^\.\.?$/,readdir(DIR));
9362	local($busy);
9363	foreach (@files) {
9364	    $busy .= $_." " unless (L2hos->Unlink("$TMPDIR$dd$_"));
9365	}
9366	closedir (DIR);
9367	if ($busy) {
9368	    print "\n\nFiles: $busy  are still in use.\n\n" if ($DEBUG);
9369	} else {
9370	    &write_warnings("\n\n Couldn't remove $TMPDIR : $!")
9371		unless (rmdir $TMPDIR);
9372	}
9373    }
9374    if (opendir(DIR, $TMP_)) {
9375	local(@files) = grep(!/^\.\.?$/,readdir(DIR));
9376	$busy = '';
9377	foreach (@files) {
9378	    $busy .= "$_ " unless (L2hos->Unlink("$TMP_$dd$_"));
9379	}
9380	closedir (DIR);
9381	local($full_dir) = L2hos->Make_directory_absolute($TMP_);
9382	if ($busy) {
9383	    print "\n\nFiles: $busy in $full_dir are still in use.\n\n"
9384	        if ($DEBUG);
9385	} else {
9386	    &write_warnings("\n\nCouldn't remove directory '$full_dir': $!")
9387		unless (rmdir $full_dir);
9388	}
9389    }
9390}
9391
9392sub handler {
9393    print "\nLaTeX2HTML shutting down.\n";
9394    kill ('INT', $child_pid) if ($child_pid);
9395    &close_dbm_database;
9396    &cleanup();
9397    exit(-1);
9398}
9399
9400# Given a filename or a directory it returns the file and the full pathname
9401# relative to the current directory.
9402sub get_full_path {
9403    local($file) = @_;
9404    local($path,$dir);
9405    if (-d $file) {	# $file is a directory
9406	$path = L2hos->Make_directory_absolute($file);
9407	$file = '';
9408
9409# JCL(jcl-dir)
9410    } elsif ($file =~ s|\Q$dd\E([^$dd$dd]*)$||o ) {
9411	$path = $file;
9412	$file = $1;
9413	$path = L2hos->Make_directory_absolute($path);
9414
9415#RRM: check within $TEXINPUTS directories
9416    } elsif (!($TEXINPUTS =~ /^\.$envkey$/)) {
9417	#check along directories in the $TEXINPUTS variable
9418	foreach $dir (split(/$envkey/,$TEXINPUTS)) {
9419	    $dir =~ s/[$dd$dd]$//o;
9420	    if (-f $dir.$dd.$file) {
9421		$path = L2hos->Make_directory_absolute($dir);
9422		last;
9423	    }
9424	}
9425    } else {
9426	$path = L2hos->Cwd();
9427    }
9428    ($path, $file);
9429}
9430
9431
9432# Given a directory name in either relative or absolute form, returns
9433# the absolute form.
9434# Note: The argument *must* be a directory name.
9435# The whole function has been moved to override.pm
9436
9437
9438
9439# Given a relative filename from the directory in which the original
9440# latex document lives, it tries to expand it to the full pathname.
9441sub fulltexpath {
9442    # Uses $texfilepath defined in sub driver
9443    local($file) = @_;
9444    $file =~ s/\s//g;
9445    $file = "$texfilepath$dd$file"
9446      unless (L2hos->is_absolute_path($file));
9447    $file;
9448}
9449
9450#RRM  Extended to allow customised filenames, set $CUSTOM_TITLES
9451#     or long title from the section-name, set $LONG_TITLES
9452#
9453sub make_name {
9454    local($sec_name, $packed_curr_sec_id) = @_;
9455    local($title,$making_name,$saved) = ('',1,'');
9456    if ($LONG_TITLES) {
9457	$saved = $_;
9458	&process_command($sections_rx, $_) if /^$sections_rx/;
9459	$title = &make_long_title($TITLE)
9460	    unless ((! $TITLE) || ($TITLE eq $default_title));
9461	$_ = $saved;
9462    } elsif ($CUSTOM_TITLES) {
9463	$saved = $_;
9464	&process_command($sections_rx, $_) if /^$sections_rx/;
9465	$title = &custom_title_hook($TITLE)
9466	    unless ((! $TITLE) || ($TITLE eq $default_title));
9467	$_ = $saved;
9468    }
9469    if ($title) {
9470	#ensure no more than 32 characters, including .html extension
9471	$title =~ s/^(.{1,27}).*$/$1/;
9472    	++$OUT_NODE;
9473	join("", ${PREFIX}, $title, $EXTN);
9474    } else {
9475    # Remove 0's from the end of $packed_curr_sec_id
9476	$packed_curr_sec_id =~ s/(_0)*$//;
9477	$packed_curr_sec_id =~ s/^\d+$//o; # Top level file
9478	join("",($packed_curr_sec_id ?
9479	    "${PREFIX}$NODE_NAME". ++$OUT_NODE : $sec_name), $EXTN);
9480    }
9481}
9482
9483#RRM: redefine this subroutine, to create customised file-names
9484#     based upon the actual section title.
9485#     The default is empty, so reverts to:  node1, node2, ...
9486#
9487sub custom_title_hook {
9488    local($_)= @_;
9489    "";
9490}
9491
9492
9493sub make_long_title {
9494    local($_)= @_;
9495    local($num_words) = $LONG_TITLES;
9496    #RRM:  scan twice for short words, due to the $4 overlap
9497    #      Cannot use \b , else words break at accented letters
9498    $_ =~ s/(^|\s)\s*($GENERIC_WORDS)(\'|(\s))/$4/ig;
9499    $_ =~ s/(^|\s)\s*($GENERIC_WORDS)(\'|(\s))/$4/ig;
9500    #remove leading numbering, unless that's all there is.
9501    local($sec_num);
9502    if (!(/^\d+(\.\d*)*\s*$/)&&(s/^\s*(\d+(\.\d*)*)\s*/$sec_num=$1;''/e))
9503	{ $num_words-- };
9504    &remove_markers; s/<[^>]*>//g; #remove tags
9505    #revert entities, etc. to TeX-form...
9506    s/([\200-\377])/"\&#".ord($1).";"/eg;
9507    $_ = &revert_to_raw_tex($_);
9508
9509    # get $LONG_TITLES number of words from what remains
9510    $_ = &get_first_words($_, $num_words) if ($num_words);
9511    # ...and cleanup accents, spaces and punctuation
9512    $_ = join('', ($SHOW_SECTION_NUMBERS ? $sec_num : ''), $_);
9513    s/\\\W\{?|\}//g; s/\s/_/g; s/\W/_/g; s/__+/_/g; s/_+$//;
9514    $_;
9515}
9516
9517
9518sub make_first_key {
9519    local($_);
9520    $_ = ('0 ' x keys %section_commands);
9521    s/^0/$THIS_FILE/ if ($MULTIPLE_FILES);
9522    chop;
9523    $_;
9524}
9525
9526# This copies the preamble into the variable $preamble.
9527# It also sets the LaTeX font size, if $FONT_SIZE is set.
9528sub add_preamble_head {
9529    $preamble = join("\n", $preamble, @preamble);
9530    $preamble = &revert_to_raw_tex($preamble);
9531    $preamble = join ("\n", &revert_to_raw_tex(/$preamble_rx/o),
9532				$preamble);
9533    local($savedRS) = $/; undef $/;
9534    # MRO: replaced $* with /m
9535    $preamble =~ /(\\document(style|class))\s*(\[[^]]*\])?\s*\{/sm;
9536    local($before,$after) = ($`.$1, '{'.$');
9537    $/ = $savedRS;
9538    local ($options) = $3;
9539    if ($FONT_SIZE) {
9540	$options =~ s/(1\dpt)\b//;
9541	$options =~ s/(\[|\])//g;
9542	$options = "[$FONT_SIZE".($options ? ",$options" : '').']';
9543	$preamble = join('', $before, $options, $after );
9544	&write_mydb_simple("preamble", $preamble);
9545	@preamble = split(/\n/, $preamble);
9546	$LATEX_FONT_SIZE = $FONT_SIZE;
9547    }
9548    if (($options =~ /(1\dpt)\b/)&&(!$LATEX_FONT_SIZE)) {
9549	$LATEX_FONT_SIZE = $1;
9550    }
9551    #RRM: need to know the font-size before the .aux file is read
9552    $LATEX_FONT_SIZE = '10pt' unless ($LATEX_FONT_SIZE);
9553}
9554
9555# It is necessary to filter some parts of the document back to raw
9556# tex before passing them to latex for processing.
9557sub revert_to_raw_tex {
9558    local($_) = @_;
9559    local($character_map) = "";
9560    if ( $CHARSET && $HTML_VERSION ge "2.1" ) {
9561	$character_map = $CHARSET;
9562	$character_map =~ tr/-/_/; }
9563    while (s/$O\s*\d+\s*$C/\{/o) { s/$&/\}/;}
9564    while (s/$O\s*\d+\s*$C/\{/o) { s/$&/\}/;} #repeat this.
9565    # The same for processed markers ...
9566    while ( s/$OP\s*\d+\s*$CP/\{/o ) { s/$&/\}/; }
9567    while ( s/$OP\s*\d+\s*$CP/\{/o ) { s/$&/\}/;} #repeat this.
9568
9569    s/<BR>/\\\\/g; # restores the \\ from \parbox's
9570
9571    # revert any math-entities
9572    s/\&\w+#(\w+);/\\$1/g;
9573    s/\&limits;/\\limits/g;
9574    s/\\underscore/\\_/g;
9575    s/\\circflex/\\^/g;
9576    s/\\space/\\ /g;
9577    s/;SPMthinsp;/\\,/g;
9578    s/;SPMnegsp;/\\!/g;
9579    s/;SPMsp;/\\:/g;
9580    s/;SPMthicksp;/\\;/g;
9581    s/;SPMgg;/\\gg /g;
9582    s/;SPMll;/\\ll /g;
9583    s/;SPMquot;/"/g;
9584
9585    # revert any super/sub-scripts
9586    s/<SUP>/\^\{/g;
9587    s/<SUB>/\_\{/g;
9588    s/<\/SU(B|P)>/\}/g;
9589
9590
9591#    #revert common character entities  ??
9592#    s/&#92;/\\/g;
9593
9594#    # revert special marks
9595#    s/$percent_mark/\\%/go;
9596##    s/$comment_mark(\d+)\n/%$comments{$1}\n/go;
9597    local($tmp,$tmp2);
9598#    s/$comment_mark(\d+)\n/$tmp=$verbatim{$1};chomp($tmp);$tmp."\n"/ego;
9599    s/$comment_mark(\d+)(\n|$|(\$))/$tmp=$verbatim{$1};$tmp2 = $3;
9600        ($tmp=~m!^\%!s ? '':'%').$tmp.(($tmp=~ m!\n\s*$!s)?'':"\n").$tmp2/sego;
9601    s/${verbatim_mark}tex2html_code(\d+)\#/$verbatim{$1}/go;
9602    s/^($file_mark|$endfile_mark).*\#\n//gmo;
9603    s/$comment_mark(\d*)\s*\n/%\n/go;
9604    s/$dol_mark/\$/go;
9605    s/$caption_mark//go;
9606
9607    # From &pre_process.
9608    # MRO: replaced $* with /m
9609    s/\\\\[ \t]*(\n)?/\\\\$1/gm;
9610
9611    # revert any array-cell delimiters
9612    s/$array_col_mark/\&/g;
9613    s/$array_row_mark/\\\\/g;
9614    s/$array_text_mark/\\text/g;
9615    s/$array_mbox_mark/\\mbox/g;
9616
9617    # Replace any verbatim and image markers ...
9618    &revert_verbatim_marks;
9619    &revert_verb_marks;
9620
9621
9622#    &replace_image_marks;
9623    s/$image_mark\#([^\#]+)\#/&recover_image_code($1)/eg;
9624
9625    # remove artificial environments and commands
9626
9627    s/(\n*)\\(begin|end)(($O|$OP)\d+($C|$CP))tex2html_b(egin)?group\3\n?/
9628	($1? "\n":'')."\\".($6? $2:(($2 =~ m|end|)? 'e':'b'))."group\n"
9629    /gem;
9630    s/\\(begin|end)(\{|(($O|$OP)\d+($C|$CP|\})))(tex2html|verbatim)_code(\}|\3)\n?//gm;
9631
9632    #take care not to concatenate \<cmd> with following letters
9633    local($tmp);
9634    s/(\\\w+)?$tex2html_wrap_rx([^\\\n])?/$tmp=$2;
9635        ((($tmp eq 'end')&&($1)&&!($5)&&($6))? "$1 $6":"$1$5$6")/egs;
9636    undef $tmp;
9637    s/\s*\\newedcommand\s*{/"%\n\\providecommand{\\"/gem;
9638    s/\\newedcommand\s*{/\\providecommand{\\/gom;
9639#    s/(\n*)\\renewedcommand{/($1? "\n":'')."\\renewcommand{\\"/geo;
9640    s/\s*\\providedcommand\s*{/"%\n\\providecommand{\\"/gem;
9641#    s/\\providedcommand{/\\providecommand{\\/go;
9642    s/\\renewedenvironment\s*/\\renewenvironment/gom;
9643    s/\\newedboolean\s*{/\\newboolean{/gom;
9644    s/\\newedcounter\s*{/\\newcounter{/gom;
9645    s/\\newedtheorem\s*{/\\newtheorem{/gom;
9646    s/\\xystar/\\xy\*/gom; # the * has a special meaning in Xy-pic
9647
9648    #fix-up the star'd environment names
9649    s/(\\(begin|end)(($O|$OP)\d+($C|$CP))[^<]*)star\3/$1\*$3/gm;
9650    s/(\\(begin|end)\{[^\}]*)star\}/$1\*\}/gm;
9651    s/\\(begin|end)\{[^\}]*begin(group)\}/\\$1$2/gm;
9652    s/\\(b|e)(egin|end)\{[^\}]*b(group)\}/\\$1$3/gm;
9653
9654    s/(\\(\w+)TeX)/($language_translations{$2}? "\\selectlanguage{$2}": $1)/egom;
9655
9656    if ($PREPROCESS_IMAGES) {
9657      while (/$pre_processor_env_rx/m) {
9658	$done .= $`; $pre_env = $5; $which =$1; $_ = $';
9659        if (($which =~ /begin/)&&($pre_env =~ /indica/)) {
9660	    ($indic, $dum) = &get_next_optional_argument;
9661	    $done .= "\#$indic";
9662        } elsif (($which =~ /begin/)&&($pre_env =~ /itrans/)) {
9663	    ($indic, $dum) = &get_next_optional_argument;
9664	    $done .= "\#$indic";
9665        } elsif (($which =~ /end/)&&($pre_env =~ /indica/)) {
9666	    $done .= '\#NIL';
9667        } elsif (($which =~ /end/)&&($pre_env =~ /itrans/)) {
9668	    $done .= "\#end$indic";
9669	} elsif ($which =~ /begin/) {
9670	    $done .= (($which =~ /end/)? $end_preprocessor{$pre_env}
9671		          : $begin_preprocessor{$pre_env} )
9672	}
9673	$_ = $done . $_;
9674      }
9675    }
9676    s/\\ITRANSinfo\{(\w+)\}\{([^}]*)\}/\#$1=$2/gm if $itrans_loaded;
9677
9678    s/\n{3,}/\n\n/gm; # remove multiple (3+) new-lines
9679    s/^\n+$//gs; # ...especially if that is all there is!
9680    if ($PREAMBLE) {
9681	s/$comment_mark(\d+\n?)?//g;
9682#	$preamble =~ s/\\par\n?/\n/g;
9683	s/\\par\b/\n/g;
9684	s/^\s*$//g; #remove blank lines in the preamble
9685    };
9686
9687    s/($html_specials_inv_rx)/$html_specials_inv{$1}/geo;
9688    # revert entities to TeX code, except if in {rawhtml} environments
9689    if (!($env =~ /rawhtml/)) {
9690        s/$character_entity_rx/( $character_map ?
9691	  eval "\$${character_map}_character_map_inv\{\"$1\"\}" :
9692	    $iso_8859_1_character_map_inv{$1} ||
9693	      $iso_10646_character_map_inv{$1})/geo;
9694        s/$named_entity_rx/( $character_map ?
9695	  eval "\$${character_map}_character_map_inv\{\$${character_map}_character_map{'$1'}}" :
9696	    $iso_8859_1_character_map_inv{$iso_8859_1_character_map{$1}} ||
9697	      $iso_10646_character_map_inv{$iso_10646_character_map{$1}})/geo;
9698
9699    } else {
9700        #RRM: check for invalid named entities in {rawhtml} environments
9701	s/($named_entity_rx)/&write_warnings(
9702	    "An unknown named entity ($1) appears in the source text.") unless (
9703		 $character_map && eval
9704	  "\$${character_map}_character_map_inv\{\$${character_map}_character_map{'$2'}}");
9705		     ";SPM$2;"/ego;
9706    }
9707
9708    #RRM: check for numbered character entity out-of-range
9709    if ($HTML_VERSION < 4.0) {
9710	s/$character_entity_rx/&write_warnings(
9711	    "An invalid character entity ($1) appears in the source text.")
9712	     if ($2 > 255);
9713	$1/ego; }
9714
9715    #RRM: check for invalid named entities outside {rawhtml} environments
9716    # --- these should have been caught already, but check again
9717    s/$named_entity_rx/&write_warnings(
9718	    "An unknown named entity ($1) appears in the source text.") unless (
9719	$character_map && eval
9720	  "\$${character_map}_character_map_inv\{\$${character_map}_character_map{'$1'}}");
9721		     $1/ego;
9722
9723    &revert_to_raw_tex_hook if (defined &revert_to_raw_tex_hook);
9724    $_;
9725}
9726
9727sub next_wrapper {
9728    local($dollar) = @_;
9729    local($_,$id);
9730    $wrap_toggle = (($wrap_toggle eq 'end') ? 'begin' : 'end');
9731    $id = ++$global{'max_id'};
9732    $_ = "\\$wrap_toggle$O$id$C"."tex2html_wrap$O$id$C";
9733    $_ = (($wrap_toggle eq 'end') ? $dollar.$_ : $_.$dollar);
9734    $_;
9735}
9736
9737sub make_wrapper {
9738    &make_any_wrapper($_[0], '', "tex2html_wrap");
9739}
9740
9741sub make_nowrapper {
9742    &make_any_wrapper($_[0], 1, "tex2html_nowrap");
9743}
9744
9745sub make_inline_wrapper {
9746    &make_any_wrapper($_[0], '', "tex2html_wrap_inline");
9747}
9748
9749sub make_deferred_wrapper {
9750    &make_any_wrapper($_[0], 1, "tex2html_deferred");
9751}
9752
9753sub make_nomath_wrapper {
9754    &make_any_wrapper($_[0], '', "tex2html_nomath_inline");
9755}
9756
9757sub make_any_wrapper {
9758    local($toggle,$break,$kind) = @_;
9759    local($max_id) = ++$global{'max_id'};
9760    '\\'. (($toggle) ? 'begin' : 'end')
9761	. "$O$max_id$C"."$kind$O$max_id$C"
9762	. (($toggle || !$break) ? '' : '');
9763}
9764
9765sub get_last_word {
9766    # Returns the last word in multi-line strings
9767    local($_) = @_;
9768    local ($word,$lastbit,$which);
9769#JCL(jcl-tcl)
9770# also remove anchors and other awkward HTML markup
9771#    &extract_pure_text("strict");
9772##    $_ = &purify($_);  ## No. what if it is a verbatim string or image?
9773#
9774#    while (/\s(\S+)\s*$/g) { $word = $lastbit = $1;}
9775
9776    if (!$_ && (defined $keep)) {
9777	# inside mathematics !
9778	$_ = $keep . $pre ;
9779    }
9780    if (!$_ && $ref_before) { $_ = $ref_before; }
9781    elsif (!$_) {
9782	# get it from last thing before the current environment
9783	$which = $#processedE;
9784	$_ = $processedE[$which];
9785    }
9786
9787    while (/((($O|$OP)\d+($C|$CP))[.\n]*\2|\s(\S+))\s*$/g)
9788	{ $word = $lastbit = $1 }
9789    if (($lastbit =~ s/\$\s*$//)||(defined $keep)) {
9790	local($br_idA) = ++$global{'max_id'};
9791	local($br_idB) = ++$global{'max_id'};
9792	$lastbit = join('', "\\begin $O$br_idA${C}tex2html_wrap_inline$O$br_idA$C\$"
9793		, $lastbit, "\$\\end $O$br_idB${C}tex2html_wrap_inline$O$br_idB$C");
9794	$lastbit = &translate_environments($lastbit);
9795	$lastbit = &translate_commands($lastbit);
9796	return ($lastbit);
9797    }
9798    if ($lastbit =~ s/($O|$OP)\d+($C|$CP)//g) { return ($lastbit); }
9799    elsif ($lastbit eq '') { return ($_) }
9800
9801    local($pre_bit);
9802    if ($lastbit =~/>([^>]*)$/) {
9803	$word = $1; $pre_bit = $`.'>';
9804	if ($pre_bit =~ /($verb_mark|$verbstar_mark)$/) {
9805	    $word = $lastbit;
9806	} elsif ($pre_bit =~ /<\w+_mark>$/) {
9807	    $word = $& . $word;
9808	} elsif (!($word)) {
9809	    if ($lastbit =~ s/<([^\/][^>]*)>$//o)
9810	        { $word=$1; $pre_bit = $`; }
9811	    elsif ($lastbit =~ s/>([^<]*)<\/[^>]*>//o)
9812	        { $word=$1; $pre_bit = $`.'>' }
9813	    else { $word = ";SPMnbsp;"; }
9814	}
9815#	if ($pre_bit =~ /<\w+_mark>$/) { $word = $& . $word }
9816     } else { $word = $lastbit };
9817    $word;
9818}
9819
9820#JCL(jcl-tcl)
9821# changed completely
9822#
9823# We take the first real words specified by $min from the string.
9824# Allow for simple HTML constructs like <I>...</I> (but not <H*>
9825# or <P*> and the like), math, or images to remain in the result,
9826# not counting as words.
9827# Take care that eg. <I>...</I> grouping tags are not broken.
9828# This is achieved by lifting the markup, removing superfluous
9829# words, re-inserting the markup, and throw empty markup away.
9830# In later versions images could be modified such that they become
9831# thumbnail sized.
9832#
9833# rawhtml or verbatim environments might introduce lots of awkward
9834# stuff, but yet we leave the according tex2html markers in.
9835#
9836sub get_first_words {
9837    local($_, $min) = @_;
9838    local($words,$i);
9839    local($id,%markup);
9840    #no limit if $min is negative
9841    $min = 1000 if ($min < 0);
9842
9843    &remove_anchors;
9844    #strip unwanted HTML constructs
9845    s/<\/?(P|BR|H)[^>]*>/ /g;
9846    #remove leading white space and \001 characters
9847    s/^\s+|\001//g;
9848    #lift html markup, numbered for recovery
9849    s/(<[^>]*>(#[^#]*#)?)/$markup{++$id}=$1; "\000$id\000"/ge;
9850
9851    foreach (split /\s+|\-{3,}/) {
9852        # count words (incl. HTML markup as part of the word)
9853        ++$i;
9854#	$words .= $_ . " " if (/\000/ || ($i <= $min));
9855	$words .= $_ . " " if ($i <= $min);
9856    }
9857    $_ = $words;
9858    chop;
9859
9860    #re-insert markup
9861    s/\000(\d+)\000/$markup{$1}/g;
9862    # remove empty markup
9863    # it's normalized, because generated by LaTeX2HTML only
9864    s/<([A-Z]+)[^>]*>\s*<\/\1>\s*//g;
9865    $_;
9866}
9867
9868sub replace_word {
9869    # Replaces the LAST occurrence of $old with $new in $str;
9870    local($str, $old, $new) = @_;
9871    substr($str,rindex($str,$old),length($old)) = $new;
9872    $str;
9873}
9874
9875# Returns the recognised sectioning commands as a string of alternatives
9876# for use in regular expressions;
9877sub get_current_sections {
9878    local($_, $key);
9879    foreach $key (keys %section_commands) {
9880	if ($key =~ /star/) {
9881	    $_ = $key . "|" . $_}
9882	else {
9883	    $_ .= "$key" . '[*]?|';
9884	}
9885    }
9886    chop;			# Remove the last "|".
9887    $_;
9888}
9889
9890sub numerically {
9891    local(@x) = split(' ',$a);
9892    local(@y) = split(' ',$b);
9893    local($i, $result);
9894    for($i=0;$i<$#x;$i++) {
9895       last if ($result = ($x[$i] <=> $y[$i]));
9896    }
9897    $result
9898}
9899
9900# Assumes that the files to be sorted are of the form
9901# <NAME><NUMBER>
9902sub file_sort {
9903    local($i,$j) = ($a,$b);
9904    $i =~ s/^[^\d]*(\d+)$/$1/;
9905    $j =~ s/^[^\d]*(\d+)$/$1/;
9906    $i <=> $j
9907}
9908
9909# If a normalized command name exists, return it.
9910sub normalize {
9911    # MRO: modified to use $_[1]
9912    # local($cmd,*after) = @_;
9913    my $cmd =$_[0];
9914    my $ncmd;
9915    # Escaped special LaTeX characters
9916    if ($cmd =~ /^($latex_specials_rx)/) {
9917#	$cmd =~ s/&(.*)$/&amp;$1/o;
9918	$cmd =~ s/&(.*)$/$ampersand_mark$1/o;
9919        $cmd =~ s/%/$percent_mark/o;
9920	$_[1] = join('', $cmd, $_[1]);
9921	$cmd = ""}
9922    elsif ($ncmd = $normalize{$cmd}) {
9923	$ncmd;
9924    }
9925    else {
9926 	$cmd =~ s/[*]$/star/;
9927 	$cmd =~ s/\@/_at_/g;
9928	$cmd;
9929    }
9930}
9931
9932sub normalize_sections {
9933    my $dummy = '';
9934    # MRO: s/$sections_rx/'\\' . &normalize($1.$2,*after) . $4/ge;
9935    s/$sections_rx/'\\' . &normalize($1.$2,$dummy) . $4/ge;
9936}
9937
9938sub embed_image {
9939    my ($url,$name,$external,$altst,$thumbnail,$map,$align,
9940	$usemap,$exscale,$exstr) = @_;
9941    my $imgID = '';
9942    my $urlimg = $url;
9943    my $ismap = $map ? " ISMAP" : '';
9944    print "\nembedding $url for $name, with $altst\n" if ($VERBOSITY > 1);
9945
9946    if (! ($NO_IMAGES || $PS_IMAGES)) {
9947	# for over-scaled GIFs with pre-determined sizes	# RRM 11-9-96
9948        my $size;
9949	if (($width{$name})&&(($exscale)||($EXTRA_IMAGE_SCALE))) {
9950	    $exscale = $EXTRA_IMAGE_SCALE unless ($exscale);
9951	    if ($name =~ /inline|indisplay|entity|equation|math|eqn|makeimage/){
9952		($size, $imgID) = &get_image_size($url, $exscale);
9953	    } else {
9954		($size, $imgID) = &get_image_size($url,'');
9955	    }
9956	} else {
9957	    ($size,$imgID) = &get_image_size($url,'');
9958	}
9959	$image_size{$url} = $size
9960	    unless ((! $size) || ($size eq "WIDTH=\"0\" HEIGHT=\"0\""));
9961	$url = &find_unique($url);
9962    }
9963
9964    $urlimg = $url;
9965    $urlimg =~ s/\.$IMAGE_TYPE$/.html/ if ($map);
9966    if ($exstr =~ s/align\s*=\s*(\"?)(\w+)\1($|\s|,)//io) { $align = $2; }
9967    my $usersize = '';
9968    if ($exstr =~ s/width\s*=\s*(\"?)([^\s,]+)\1($|\s|,)//io) {
9969	my ($pxs,$len) = &convert_length($2);
9970	$usersize = " WIDTH=\"$pxs\"";
9971    }
9972    if ($exstr =~ s/height\s*=\s*(\"?)([^\s,]+)\1($|\s|,)//io) {
9973	my ($pxs,$len) = &convert_length($2);
9974	$usersize .= " HEIGHT=\"$pxs\"";
9975    }
9976
9977    my $border = '';
9978    $border = "\" BORDER=\"0"
9979	unless (($HTML_VERSION < 2.2 )||($exstr =~ /BORDER/i));
9980
9981    my $aalign;
9982    if (($name =~ /figure|table|displaymath\d+|eqnarraystar/)&&(!$align)) {
9983    } elsif ($name =~ /displaymath_/) {
9984	$aalign = "MIDDLE".$border;
9985    } elsif (($name =~ /(equation|eqnarray)($|\d)/)&&(!$align)) {
9986	if ($HTML_VERSION >= 3.2) {
9987	    $aalign =  ($EQN_TAGS eq "L") ? "RIGHT" : "LEFT";
9988	}
9989    } elsif ($name =~ /inline|display|entity|xy|diagram/ && $depth{$name} != 0) {
9990	$aalign = "MIDDLE".$border;
9991    } elsif ($name =~ /inpar/m) {
9992	$aalign = "TOP".$border;
9993    } else {  $aalign = "BOTTOM".$border }
9994
9995    $aalign = "\U$align" if $align;
9996    my $ausemp = $usemap ? "\UUSEMAP=$usemap" : '';
9997
9998    #append any extra valid options
9999    $ismap .= &parse_keyvalues ($exstr, ("IMG")) if ($exstr);
10000
10001    $altst = '' if ($ismap =~ /(^|\s+)ALT\s*=/);
10002    if ($altst) {
10003	if ($altst =~ /\s*ALT="?([^\"]+)"?\s*/io) { $altst=$1 }
10004	$altst =~ s/[<>"&]/'&'.$html_special_entities{$&}.';'/eg;
10005	$altst = "\n ALT=\"$altst\"";
10006    }
10007
10008    my ($extern_image_mark,$imagesize);
10009    if ($thumbnail) {
10010	print "\nmaking thumbnail" if ($VERBOSITY > 1);
10011	if (($image_size{$thumbnail}) = &get_image_size($thumbnail,'')) {
10012	    $thumbnail = &find_unique($thumbnail);
10013	    $imagesize = " ".$image_size{$thumbnail};
10014	    if ($HTML_VERSION < 2.2 ) {
10015		# put the WIDTH/HEIGHT information into the ALT string
10016		# first removing the quotes
10017		my ($noquotes) = $imagesize;
10018		$noquotes =~ s/\"//g;
10019		$altst =~ s/"$/\% $noquotes "/m;
10020		$imagesize = '';
10021	    }
10022	    $extern_image_mark = join('',"<IMG"
10023		, "\n$imagesize"
10024		, (($aalign) ? " ALIGN=\"$aalign\"" : '')
10025		, ("$aalign$imagesize" ? "\n" : '' )
10026		, " SRC=\"$thumbnail\"$altst>");
10027	}
10028	$extern_image_mark =~ s/\s?BORDER="?\d+"?//
10029            unless ($exstr =~ /BORDER/i);
10030    } else {
10031        # MRO: dubious (&extern_image_mark takes only one arg)
10032        $extern_image_mark = &extern_image_mark($IMAGE_TYPE,$altst);
10033    }
10034
10035    my ($anch1,$anch2) = ('','');
10036    my $result;
10037    if ($external || $thumbnail || $EXTERNAL_IMAGES) {
10038	if ( $extern_image_mark ) {
10039	    $result = &make_href_noexpand($urlimg, $name , $extern_image_mark);
10040	    &save_image_map($url, $urlimg, $map, $name, $altst, $ausemp) if $map;
10041	}
10042    } else {
10043	if ($map) {
10044	    $anch1 = "<A HREF=\"$map\">";
10045	    $anch2 = "</A>";
10046	}
10047#	if ($aalign eq "CENTER") {
10048#	    if ($HTML_VERSION eq "2.0") {
10049#	        $anch1 .= "\n<P ALIGN=\"CENTER\">";
10050#	        $anch2 .= "</P>";
10051#	    } else {
10052#	        $anch1 .= "\n<DIV ALIGN=\"CENTER\">";
10053#	        $anch2 .= "</DIV>";
10054#	    }
10055#	}
10056
10057	$imagesize = $image_size{$url};
10058	$imagesize = $usersize if (($usersize)&&($HTML_VERSION > 2.1 ));
10059	if ($HTML_VERSION < 2.2 ) {
10060	    # put the WIDTH/HEIGHT information into the ALT string
10061	    # first removing the quotes
10062	    my ($noquotes) = $imagesize;
10063	    $noquotes =~ s/\"//g;
10064	    $altst =~ s/"$/\% $noquotes "/m;
10065	}
10066
10067	# include a stylesheet entry for each included image
10068	if ($USING_STYLES && $SCALABLE_IMAGES &&(!$imgID)) {
10069	    if ($url =~ /($dd|^)([^$dd$dd]+)\.$IMAGE_TYPE$/) {
10070		my $img_name = $2;
10071		$imgID = $img_name . ($img_name =~ /img/ ? '' : $IMAGE_TYPE);
10072		$img_style{"$imgID"} = ' ' unless $img_style{"$imgID"};
10073		$imgID = join('', ' CLASS="', $imgID, '"') if $imgID;
10074	    }
10075	}
10076
10077	### MEH Add width and height to IMG
10078	### Patched by <hswan@perc.Arco.com>:  Fixed \htmladdimg
10079	if ( $imagesize || $name eq "external image" || $NO_IMAGES || $PS_IMAGES) {
10080	    $imagesize = '' if ($HTML_VERSION < 2.2 );
10081	    if ($border =~ s/^"//) { $border .= '"' };
10082	    $result = join(''
10083		   , "<IMG$imgID"
10084		   , "\n", ($imagesize ? " $imagesize" : '')
10085		   , (($aalign)? " ALIGN=\"$aalign\"" : $border)
10086		   , $ismap );
10087	    if ($ausemp) { $result .= " $ausemp" }
10088	    $result .= "\n" unless (($result =~ /\n *$/m)|| !$imagesize);
10089	    $result .= " SRC=\"$url\"";
10090	    if ($altst) { $result .= $altst }
10091	    $result .= ">";
10092	}
10093    }
10094    join('',$anch1, $result, $anch2);
10095}
10096
10097# MRO: added PNG support
10098sub get_image_size { # clean
10099    my ($imagefile, $scale) = @_;
10100
10101    $scale = '' if ($scale == 1);
10102    my ($imgID,$size) = ('','');
10103    if (open(IMAGE, "<$imagefile")) {
10104        my ($buffer,$magic,$dummy,$width,$height) = ('','','',0,0);
10105	binmode(IMAGE); # not harmful un UNIX
10106        if ($IMAGE_TYPE =~ /gif/) {
10107	    read(IMAGE,$buffer,10);
10108	    ($magic,$width,$height) = unpack('a6vv',$buffer);
10109            # is this image sane?
10110	    unless($magic =~ /^GIF8[79]a$/ && ($width * $height) > 0) {
10111                $width = $height = 0;
10112	    }
10113        }
10114        elsif ($IMAGE_TYPE =~ /png/) {
10115            read(IMAGE,$buffer,24);
10116	    ($magic,$dummy,$width,$height) = unpack('a4a12NN',$buffer);
10117	    unless($magic eq "\x89PNG" && ($width * $height) > 0) {
10118                $width = $height = 0;
10119            }
10120	}
10121	close(IMAGE);
10122
10123	# adjust for non-trivial $scale factor.
10124        my ($img_w,$img_h) = ($width,$height);
10125	if ($scale && ($width * $height) > 0) {
10126            $img_w = int($width / $scale + .5);
10127            $img_h = int($height / $scale + .5);
10128	}
10129	$size = qq{WIDTH="$img_w" HEIGHT="$img_h"};
10130
10131	# allow height/width to be stored in the stylesheet
10132	my ($img_name,$imgID);
10133	if ($SCALABLE_IMAGES && $USING_STYLES) {
10134	    if ($imagefile =~ /(^|[$dd$dd])([^$dd$dd]+)\.(\Q$IMAGE_TYPE\E|old)$/o) {
10135		$img_name = $2;
10136		$imgID = $img_name . ($img_name =~ /img/ ? '' : $IMAGE_TYPE);
10137	    }
10138	    if ($imgID) {
10139		$width = $width/$LATEX_FONT_SIZE/$MATH_SCALE_FACTOR;
10140		$height = 1.8 * $height/$LATEX_FONT_SIZE/$MATH_SCALE_FACTOR;
10141		# How wide is an em in the most likely browser font ?
10142		if ($scale) {
10143		# How high is an ex in the most likely browser font ?
10144		    $width = $width/$scale; $height = $height/$scale;
10145		}
10146		$width = int(100*$width + .5)/100;
10147		$height = int(100*$height + .5)/100;
10148		$img_style{$imgID} = qq(width:${width}em ; height:${height}ex );
10149		#join('','width:',$width,'em ; height:',$height,'ex ');
10150		$imgID = qq{ CLASS="$imgID"};
10151	    }
10152	}
10153    }
10154    ($size, $imgID);
10155}
10156
10157sub find_unique { # clean
10158    my ($image1) = @_;
10159    local($/) = undef; # slurp in complete files
10160
10161    my $imagedata;
10162    if(open(IMG1,"<$image1")) {
10163	binmode(IMG1); # needed with .png under DOS
10164        $imagedata = <IMG1>;
10165        close(IMG1);
10166    } else {
10167        print "\nError: Cannot read '$image1': $!\n"
10168	    unless ($image1 =~ /^\s*$HTTP_start/i);
10169        return $image1;
10170    }
10171
10172    my ($image2,$result);
10173    foreach $image2 (keys(%image_size)) {
10174	if ( $image1 ne $image2 &&
10175	    $image_size{$image1} eq $image_size{$image2} ) {
10176	    if(open(IMG2,$image2)) {
10177		binmode(IMG2); # needed with .png under DOS
10178	        $result = ($imagedata eq <IMG2>);
10179	        close(IMG2);
10180            } else {
10181                print "\nWarning: Cannot read '$image2': $!\n"
10182		    unless ($image2 =~ /^\s*$HTTP_start/i);
10183            }
10184#
10185#  If we've found a match, rename the new image to a temporary one.
10186#  Then try to link the new name to the old image.
10187#  If the link fails, restore the temporary image.
10188#
10189	    if ( $result ) {
10190		my $tmp = "temporary.$IMAGE_TYPE";
10191		L2hos->Unlink($tmp);
10192		L2hos->Rename($image1, $tmp);
10193		if (L2hos->Link($image2, $image1)) {
10194                    L2hos->Unlink($tmp);
10195                } else {
10196                    L2hos->Rename($tmp, $image1);
10197                }
10198		return $image1;
10199	    }
10200	}
10201    }
10202    $image1;
10203}
10204
10205sub save_image_map { # clean
10206    my ($url, $urlimg, $map, $name, $altst, $ausemp) = @_;
10207    unless(open(IMAGE_MAP, ">$urlimg")) {
10208        print "\nError: Cannot write '$urlimg': $!\n";
10209        return;
10210    }
10211    ### HWS  Pass server map unchanged from user
10212    print IMAGE_MAP "<HTML>\n<BODY>\n<A HREF=\"$map\">\n";
10213    print IMAGE_MAP "<IMG\n SRC=\"$url\" ISMAP $ausemp $altst> </A>";
10214    print IMAGE_MAP "</BODY>\n</HTML>\n";
10215    close IMAGE_MAP;
10216}
10217
10218#  Subroutine used mainly to rename an old image file about to recycled.
10219#  But for active image maps, we must edit the auxiliary HTML file to point
10220#     to the newly renames image.
10221sub rename_html {
10222    local ($from, $to) = @_;
10223    local ($from_prefix, $to_prefix, $suffix);
10224    ($from_prefix, $suffix) = split(/\./, $from);
10225    ($to_prefix, $suffix) = split(/\./, $to);
10226    if ($EXTN =~ /$suffix$/) {
10227	if (open(FROM, "<$from") && open(HTMP, ">HTML_tmp")) {
10228	    while (<FROM>) {
10229		s/$from_prefix\.$IMAGE_TYPE/$to_prefix.$IMAGE_TYPE/g;
10230		print HTMP;
10231	    }
10232	    close (FROM);
10233	    close (HTMP);
10234	    L2hos->Rename ("HTML_tmp", $to);
10235	    L2hos->Unlink($from) unless ($from eq $to);
10236	}
10237	else {
10238	    &write_warnings("File $from is missing!\n");
10239	}
10240    }
10241    L2hos->Rename("$from_prefix.old", "$to_prefix.$IMAGE_TYPE");
10242    $to;
10243}
10244
10245sub save_captions_in_file {
10246    local ($type, $_) = @_;
10247    if ($_) {
10248	s/^\n//om;
10249	&replace_markers;
10250	&add_dir_to_href if ($DESTDIR);
10251	if(open(CAPTIONS, ">${PREFIX}$type.pl")) {
10252	    print CAPTIONS $_;
10253	    close (CAPTIONS);
10254        } else {
10255            print "\nError: Cannot write '${PREFIX}$type.pl': $!\n";
10256        }
10257    }
10258}
10259
10260sub add_dir_to_href {
10261    $_ =~ s/'/\\'/g;
10262    $_ =~ s/(<LI><A )(NAME\=\"tex2html\d+\")?\s*(HREF=\")/$1$3\'.\$dir.\'/og;
10263    $_ = join('', "\'", $_, "\'\n");
10264}
10265
10266sub save_array_in_file {
10267    local ($type, $array_name, $append, %array) = @_;
10268    local ($uutxt,$file,$prefix,$suffix,$done_file,$depth,$title);
10269    $prefix = $suffix = "";
10270    my $filespec = ($append ? '>>' : '>') . "${PREFIX}$type.pl";
10271    $prefix = q("$URL/" . )
10272	if ($type eq "labels") && !($array_name eq "external\_latex\_labels");
10273    $suffix = " unless (\$$array_name\{\$key\})"
10274	if (($type =~ /(sections|contents)/)||($array_name eq "printable\_key"));
10275    if ((%array)||($type eq "labels")) {
10276	print "\nSAVE_ARRAY:$array_name in FILE: ${PREFIX}$type.pl"
10277	    if ($VERBOSITY > 1);
10278	unless(open(FILE,$filespec)) {
10279            print "\nError: Cannot write '${PREFIX}$type.pl': $!\n";
10280            return;
10281        }
10282	if (($array_name eq "sub\_index") || ($array_name eq "printable\_key")) {
10283	    print FILE "\n# LaTeX2HTML $TEX2HTMLVERSION\n";
10284	    print FILE "# Printable index-keys from $array_name array.\n\n";
10285	} elsif ($array_name eq "index\_labels") {
10286	    print FILE "\n# LaTeX2HTML $TEX2HTMLVERSION\n";
10287	    print FILE "# labels from $array_name array.\n\n";
10288	} elsif ($array_name eq "index\_segment") {
10289	    print FILE "\n# LaTeX2HTML $TEX2HTMLVERSION\n";
10290	    print FILE "# segment identifier from $array_name array.\n\n";
10291	} elsif ($array_name eq "external\_latex\_labels") {
10292	    print FILE "\n# LaTeX2HTML $TEX2HTMLVERSION\n";
10293	    print FILE "# labels from $array_name array.\n\n";
10294	} else {
10295	    print FILE "# LaTeX2HTML $TEX2HTMLVERSION\n";
10296	    print FILE "# Associate $type original text with physical files.\n\n";
10297	}
10298	while (($uutxt,$file) = each %array) {
10299	    $uutxt =~ s|/|\\/|g;
10300	    $uutxt =~ s|\\\\/|\\/|g;
10301
10302	    if (!($array_name =~/images/)&&($file =~ /</)) {
10303		do { local $_ = $file;
10304		     &replace_markers;
10305		     $file = $_; undef $_;
10306		     $file =~ s/(\G|[^q])[\\\|]\|/$1\\Vert/sg;
10307		     $file =~ s/(\G|[^q])\|/$1\\vert/sg;
10308		};
10309	    }
10310
10311	    local ($nosave);
10312	    if ($MULTIPLE_FILES && $ROOTED &&
10313	    	    $type =~ /(sections|contents)/) {
10314		#RRM: save from $THIS_FILE only
10315	    	if ( $uutxt =~ /^$THIS_FILE /) {
10316		    #RRM: save from $THIS_FILE only
10317	    	    $nosave = ''
10318	    	} else { $nosave = 1 }
10319	    } else {
10320		#RRM: suppress info from other segments
10321	        $nosave = $noresave{$uutxt};
10322	    }
10323
10324	    if (!$nosave && ($file ne ''))  {
10325		print FILE "\n\$key = q/$uutxt/;\n";
10326
10327		$file =~ s/\|/\\\|/g; # RRM:  escape any occurrences of |
10328		$file =~ s/\\\\\|/\\\|/g; # unless already escaped as \|
10329		$file =~ s|\\\\|\\\\\\\\|g;
10330		$file =~ s/(SRC=")($HTTP_start)?/$1.($2 ? '' :"|.\"\$dir\".q|").$2/seg;
10331#
10332#
10333# added code for  $dir  with segmented docs;  RRM  15/3/96
10334#
10335		if ($type eq "contents") {
10336		    ($depth, $done_file) = split($delim, $file, 2 );
10337		    next if ($depth > $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH);
10338		    print FILE
10339    "\$$array_name\{\$key\} = '$depth$delim'.\"\$dir\".q|$done_file|$suffix; \n";
10340
10341		} elsif ($type eq "sections") {
10342		    ($depth, $done_file) = split($delim, $file, 2 );
10343		    next if ($depth > $MAX_SPLIT_DEPTH + $MAX_LINK_DEPTH);
10344		    print FILE
10345    "\$$array_name\{\$key\} = '$depth$delim'.\"\$dir\".q|$done_file|$suffix; \n";
10346
10347		} elsif ($type eq "internals") {
10348		    print FILE
10349    "\$$array_name\{\$key\} = \"\$dir\".q|$file|$suffix; \n";
10350
10351		} elsif ($array_name eq "sub_index") {
10352		    print FILE
10353    "\$$array_name\{\$key\} .= q|$file|$suffix; \n";
10354
10355		} elsif ($array_name eq "index") {
10356		    local($tmp_file) = '';
10357		    ($depth, $done_file) = split('HREF=\"', $file, 2 );
10358		    if ($done_file) {
10359			while ($done_file) {
10360			    $depth =~ s/\s*$/ / if ($depth);
10361			    $tmp_file .= "q|${depth}HREF=\"|.\"\$dir\".";
10362			    ($depth, $done_file) = split('HREF=\"', $done_file, 2 );
10363			}
10364			print FILE
10365    "\$$array_name\{\$key\} .= ${tmp_file}q|$depth|$suffix; \n";
10366
10367		    } else {
10368			print FILE
10369    "\$$array_name\{\$key\} .= q|$file|$suffix; \n";
10370		    }
10371		} elsif ($array_name eq "printable_key") {
10372		    print FILE
10373    "\$$array_name\{\$key\} = q|$file|$suffix; \n";
10374
10375		} else {
10376		    print FILE
10377    "\$$array_name\{\$key\} = ${prefix}q|$file|$suffix; \n";
10378		}
10379
10380		if ($type =~ /(figure|table|images)/) {} else {
10381		    print FILE "\$noresave\{\$key\} = \"\$nosave\";\n";
10382		}
10383
10384		if ($type eq "sections") {
10385		    ($depth, $done_file, $title) = split($delim, $file);
10386		    print FILE "\$done\{\"\$\{dir\}$done_file\"\} = 1;\n";
10387		}
10388	    }
10389	}
10390	print FILE "\n1;\n\n"  unless  ( $array_name =~ /index/ );
10391	close (FILE);
10392    } else {
10393	print "\nSAVE_FILE:$array_name: ${PREFIX}$type.pl  EMPTY " if ($VERBOSITY > 1);
10394    }
10395}
10396
10397# returns true if $AUTO_NAVIGATION is on and there are more words in $_
10398# than $WORDS_IN_PAGE
10399sub auto_navigation {
10400    # Uses $_;
10401    local(@tmp) = split(/\W*\s+\W*/, $_);
10402    ($AUTO_NAVIGATION && ( (scalar @tmp) > $WORDS_IN_PAGE));
10403}
10404
10405# Returns true if $f1 is newer than $f2
10406sub newer {
10407    ($f1,$f2) = @_;
10408    local(@f1s) = stat($f1);
10409    local(@f2s) = stat($f2);
10410    ($f1s[9] > $f2s[9]);
10411};
10412
10413sub iso_map {
10414    local($char, $kind, $quiet) = @_;
10415    my($character_map,$enc);
10416    local ($this);
10417
10418    if ( $CHARSET && $HTML_VERSION ge "2.1" ) {
10419	# see if it is a character in the charset
10420	$character_map = ((($charset =~ /utf/)&&!$NO_UTF)?
10421			  'iso_10646' : $CHARSET );
10422	$character_map =~ tr/-/_/;
10423	eval "\$enc = \$${character_map}_character_map\{\"$char$kind\"\}";
10424	print "\n no support for $CHARSET: $@ " if ($@);
10425    }
10426    if ($USE_ENTITY_NAMES && $enc) { return(";SPM$char$kind;") }
10427
10428    if ($enc) {
10429	$enc =~ /^\&\#(\d{3});$/;
10430	# maybe convert it to an 8-bit character
10431	if ($NO_UTF && !$USE_UTF && ($1<=255)) { $enc = chr($1) }
10432#	elsif (!$USE_UTF &&($1>127)&&($1<160)) { $enc = chr($1) }
10433	elsif ($character_map !~ /^iso_(8859_1|10646)/) {
10434	# get its latin1 or unicode entity encoding
10435	    $enc = $iso_8859_1_character_map{"$char$kind"}
10436	        ||$iso_8859_1A_character_map{"$char$kind"}
10437	        ||$iso_10646_character_map{"$char$kind"}
10438	}
10439     } else {
10440	# get its latin1 or unicode entity encoding, if available
10441	$enc = $iso_8859_1_character_map{"$char$kind"}
10442	    ||$iso_8859_1A_character_map{"$char$kind"}
10443	    ||$iso_10646_character_map{"$char$kind"};
10444    }
10445
10446    if ($enc) {
10447	$ISOLATIN_CHARS = 1; $enc;
10448    } elsif (!$image_made{"$char$kind"}) {
10449	print "\ncouldn't convert character $char$kind into available encodings"
10450	    if (!quiet &&($VERBOSITY > 1));
10451	&write_warnings(
10452	    "couldn't convert character $char$kind into available encodings"
10453	    . ($ACCENT_IMAGES ? ', using image' : '')) unless ($quiet);
10454	$image_made{"$char$kind"} = 1;
10455	'';
10456    } else {''}
10457}
10458
10459sub titles_language {
10460    local($_) = @_;
10461    local($lang) = $_ . "_titles";
10462    if (defined(&$lang)) { &$lang }
10463    else {
10464	&english_titles;
10465	&write_warnings(
10466	    "\nThere is currently no support for the $tmp language." .
10467	    "\nSee the file $CONFIG_FILE for examples on how to add it\n\n");
10468    }
10469}
10470
10471sub translate_titles {
10472    $toc_title = &translate_commands($toc_title) if ($toc_title =~ /\\/);
10473    $lof_title = &translate_commands($lof_title) if ($lof_title =~ /\\/);
10474    $lot_title = &translate_commands($lot_title) if ($lot_title =~ /\\/);
10475    $idx_title = &translate_commands($idx_title) if ($idx_title =~ /\\/);
10476    $ref_title = &translate_commands($ref_title) if ($ref_title =~ /\\/);
10477    $bib_title = &translate_commands($bib_title) if ($bib_title =~ /\\/);
10478    $abs_title = &translate_commands($abs_title) if ($abs_title =~ /\\/);
10479    $app_title = &translate_commands($app_title) if ($app_title =~ /\\/);
10480    $pre_title = &translate_commands($pre_title) if ($pre_title =~ /\\/);
10481    $foot_title = &translate_commands($foot_title) if ($foot_title =~ /\\/);
10482    $fig_name = &translate_commands($fig_name) if ($fig_name =~ /\\/);
10483    $tab_name = &translate_commands($tab_name) if ($tab_name =~ /\\/);
10484    $prf_name = &translate_commands($prf_name) if ($prf_name =~ /\\/);
10485    $page_name = &translate_commands($page_name) if ($page_name =~ /\\/);
10486    $child_name = &translate_commands($child_name) if ($child_name =~ /\\/);
10487    $info_title = &translate_commands($info_title) if ($info_title =~ /\\/);
10488    $part_name = &translate_commands($part_name) if ($part_name =~ /\\/);
10489    $chapter_name = &translate_commands($chapter_name)
10490	if ($chapter_name =~ /\\/);
10491    $section_name = &translate_commands($section_name)
10492	if ($section_name =~ /\\/);
10493    $subsection_name = &translate_commands($subsection_name)
10494	if ($subsection_name =~ /\\/);
10495    $subsubsection_name = &translate_commands($subsubsection_name)
10496	if ($subsubsection_name =~ /\\/);
10497    $paragraph_name = &translate_commands($paragraph_name)
10498	if ($paragraph_name =~ /\\/);
10499    $see_name = &translate_commands($see_name) if ($see_name =~ /\\/);
10500    $also_name = &translate_commands($also_name) if ($also_name =~ /\\/);
10501    $next_name = &translate_commands($next_name) if ($next_name =~ /\\/);
10502    $prev_name = &translate_commands($prev_name) if ($prev_name =~ /\\/);
10503    $up_name = &translate_commands($up_name) if ($up_name =~ /\\/);
10504    $group_name = &translate_commands($group_name) if ($group_name =~ /\\/);
10505    $encl_name = &translate_commands($encl_name) if ($encl_name =~ /\\/);
10506    $headto_name = &translate_commands($headto_name) if ($headto_name =~ /\\/);
10507    $cc_name = &translate_commands($cc_name) if ($cc_name =~ /\\/);
10508    $default_title = &translate_commands($default_title)
10509	if ($default_title =~ /\\/);
10510}
10511####################### Code Generation Subroutines ############################
10512# This takes a string of commands followed by optional or compulsory
10513# argument markers and generates a subroutine for each command that will
10514# ignore the command and its arguments.
10515# The commands are separated by newlines and have the format:
10516##      <cmd_name>#{}# []# {}# [] etc.
10517# {} marks a compulsory argument and [] an  optional one.
10518sub ignore_commands {
10519    local($_) = @_;
10520    foreach (/.*\n?/g) {
10521	s/\n//g;
10522	# For each line
10523	local($cmd, @args) = split('\s*#\s*',$_);
10524	print "PCT: ignore_commands: cmd: $cmd\n" if ($VERBOSITY > 10) ;
10525	next unless $cmd;
10526	$cmd =~ s/ //;
10527	++$ignore{$cmd};
10528	local ($body, $code, $thisone) = ("", "");
10529
10530	# alter the pattern here to debug particular commands
10531	$thisone = 1 if ($cmd =~ /let/);
10532
10533	if (@args) {
10534	    print "\n$cmd: ".scalar(@args)." arguments" if ($thisone);
10535	    # Replace the argument markers with appropriate patterns
10536	    foreach $arg (@args) {
10537		print "\nARG: $arg" if ($thisone);
10538		if ($arg =~ /\{\}/) {
10539		    $body .= 'local($cmd) = '."\"$cmd\"".";\n";
10540		    $body .= '$args .= &missing_braces'."\n ".'unless (';
10541		    $body .= '(s/$next_pair_pr_rx/$args .= $2;\'\'/eo)'."\n";
10542		    $body .= '  ||(s/$next_pair_rx/$args .= $2;\'\'/eo));'."\n";
10543		    print "\nAFTER:$'" if (($thisone)&&($'));
10544		    $body .= $' if ($');
10545		} elsif ($arg =~ /\[\]/) {
10546		    $body .= '($dummy, $pat) = &get_next_optional_argument;'
10547									       . '$args .= $pat;'."\n";
10548		    print "\nAFTER:$'" if (($thisone)&&($'));
10549		    $body .= $' if ($');
10550		} elsif ($arg =~ /^\s*\\/) {
10551		    $body .= '($dummy, $pat) = &get_next_tex_cmd;'
10552								     . '$args .= $pat;'."\n";
10553		    print "\nAFTER:$'" if (($thisone)&&($'));
10554		    $body .= $' if ($');
10555		} elsif ($arg =~ /<<\s*([^>]*)[\b\s]*>>/) {
10556		    local($endcmd, $after) = ($1,$');
10557		    $after =~ s/(^\s*|\s*$)//g;
10558		    $endcmd = &escape_rx_chars($endcmd);
10559		    $body .= join('','if (/',$endcmd,'/o) { $args .= $`; $_ = $',"'",'};',"\n") ;
10560		    print "\nAFTER:$after" if (($thisone)&&($after));
10561		    $body .= "$after" if ($after);
10562		}
10563		else {
10564		    print "\nAFTER:$'" if (($thisone)&&($arg));
10565		    $body .= $arg ;
10566		}
10567	    }
10568	    # Generate a new subroutine
10569	    #	    $code = "sub do_cmd_$cmd {\n".'local($_) = @_;'. join('',@args) .'$_}';
10570	    $code = join('',"sub do_cmd_$cmd {\n",
10571			 'local($_,$ot) = @_; ',
10572			 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R; ',
10573			 'local($args); ',
10574			 "\n",
10575			 $body,
10576			 (($body)? ";\n" : ''),
10577			 (($thisone)? "print \"\\n$cmd:\".\$args.\"\\n\";\n" : ''),
10578			 (($arg)? $arg : '$_') . "}"
10579		);
10580	    print STDOUT "\n$code\n" if ($thisone); # for error-checking
10581	    eval ($code); # unless ($thisone);
10582	    print STDERR "\n\n*** sub do_cmd_$cmd failed: $@\n" if ($@);
10583	}
10584	else {
10585	    $code = "sub do_cmd_$cmd {\n".'$_[0]}';
10586	    print "\n$code\n" if ($thisone); # for error-checking
10587	    eval ($code); # unless ($thisone);
10588	    print STDERR "\n\n*** sub do_cmd_$cmd failed: $@\n" if ($@);
10589        }
10590    }
10591}
10592
10593
10594sub ignore_numeric_argument {
10595    # Chop this off
10596    #RRM: 2001/11/8: beware of taking too much, when  <num> <num>
10597    local($num) = '(^|width|height|plus|minus)\s*[+-]?[\d\.]+(cm|em|ex|in|pc|pt|mm)?\s*';
10598    do { s/^\s*=?\s*//so; s/^($num)*//so } unless (/^(\s*\<\<\d+\>\>|$)/);
10599}
10600
10601sub get_numeric_argument {
10602    my ($num_rx,$num) = ('','');
10603    # Collect the numeric part
10604    #RRM: 2001/11/8: beware of taking too much, when  <num> <num>
10605    $num_rx = '(^|width|height|plus|minus)\s*[+-]?[\d\.]+(cm|em|ex|in|pc|pt|mm)?\s*';
10606    do { s/^\s*=?\s*//so; s/($num_rx)*/$num=$&;''/soe } unless (/^(\s*\<\<\d+\>\>|$)/);
10607    $num;
10608}
10609
10610sub process_in_latex_helper {
10611    local($ctr,$val,$cmd) = @_;
10612    ($ASCII_MODE ? "[$cmd]" :
10613	&process_in_latex("\\setcounter{$ctr}{$val}\\$cmd"))
10614}
10615
10616sub do_cmd_catcode {
10617    local($_) = @_;
10618    s/^\s*[^=]+(=?\s*\d+\s|\\active)\s?//;
10619    $_;
10620}
10621
10622sub do_cmd_string {
10623    local($_) = @_;
10624    local($tok);
10625    s/^\s*(\\([a-zA-Z]+|.)|[&;]\w+;(#\w+;)?|.)/$tok=$1;''/e;
10626    if ($2) {$tok = "\&#92;$2"};
10627    "$tok".$_
10628}
10629
10630sub do_cmd_boldmath {
10631    local($_) = @_;
10632    $BOLD_MATH = 1;
10633    $_;
10634}
10635
10636sub do_cmd_unboldmath {
10637    local($_) = @_;
10638    $BOLD_MATH = 0;
10639    $_;
10640}
10641
10642sub do_cmd_lq {
10643    local($_) = @_ ;
10644    local($lquote);
10645    # check for double quotes
10646    if (s/^\s*\\lq(\b|$|[^A-Za-z])/$1/) {
10647	$lquote = ((($HTML_VERSION < 4)&&!($charset =~ /utf/)) ? '``'
10648		: &do_leftquotes($_));
10649    } else {
10650	$lquote = ((($HTML_VERSION < 4)&&!($charset =~ /utf/)) ? '`'
10651		: &do_leftquote($_));
10652    }
10653    $lquote . $_;
10654				      }
10655
10656sub do_leftquote {
10657    # MRO: use $_[0] : local(*_) = @_;
10658    local($quote,$lquo) = ('',($HTML_VERSION<5)? '&#8216;' : ';SPMlsquo;');
10659    # select whole quotation, if \lq matches \rq
10660    if ($_[0] =~ /^(.*)((\\rq\\rq|'')*)(\\rq)/) {
10661	$quote = $1.$2; $_[0] = $';
10662	local($rquo) = &do_rightquote();
10663	&process_quote($lquo,$quote,$rquo);
10664    } else { $lquo; }
10665}
10666
10667sub do_leftquotes {
10668    # MRO: use $_[0] : local(*_) = @_;
10669    local($quote,$lquo) = ('',($HTML_VERSION<5)? '&#8220;' : ';SPMldquo;');
10670    # select whole quotation, if \lq\lq matches \rq\rq or ''
10671    if ($_[0] =~ /^(.*)(\\rq\\rq|'')/) {
10672	$quote = $1; $_[0] = $';
10673	local($rquo) = &do_rightquotes();
10674	&process_quote($lquo,$quote,$rquo);
10675    } else { $lquo; }
10676}
10677
10678# RRM: By default this just concatenates the strings; e.g. ` <quote> '
10679# This can be overridden in a html-version file
10680sub process_quote { join ('', @_) }
10681
10682sub do_cmd_rq {
10683    local($_) = @_ ;
10684    local($rquote);
10685    if ($_ =~ s/^\s*\\rq\b//) {
10686	$rquote = ((($HTML_VERSION < 4)&&!($charset =~ /utf/)) ? "''"
10687		: &do_rightquotes());
10688    } else {
10689	$rquote = ((($HTML_VERSION < 4)&&!($charset =~ /utf/)) ? "'"
10690		: &do_rightquote());
10691    }
10692    $rquote . $_;
10693}
10694
10695sub do_rightquote { (($HTML_VERSION < 5)? '&#8217;' : ';SPMrsquo;') }
10696sub do_rightquotes { (($HTML_VERSION < 5)? '&#8221;' : ';SPMrdquo;') }
10697
10698sub do_cmd_parbox {
10699    local($_) = @_;
10700    local($args, $contents, $dum, $pat);
10701    ($dum,$pat) = &get_next_optional_argument; # discard this
10702    ($dum,$pat) = &get_next_optional_argument; # discard this
10703    ($dum,$pat) = &get_next_optional_argument; # discard this
10704    $args .= $pat if ($pat);
10705    $pat = &missing_braces unless (
10706	(s/$next_pair_pr_rx/$pat=$2;''/eom)
10707	||(s/$next_pair_rx/$pat=$2;''/eom));
10708    $args .= "{".$`.$pat."}";
10709    $contents = &missing_braces unless (
10710	(s/$next_pair_pr_rx/$contents=$2;''/eom)
10711	||(s/$next_pair_rx/$contents=$2;''/eom));
10712    $args .= "{".$`.$contents."}";
10713    if ($NO_PARBOX_IMAGES) {
10714	$contents = join ('', &do_cmd_par(), $contents, '</P>' );
10715    } else {
10716	$contents = &process_math_in_latex('','text',0,"\\parbox$args")
10717	    if ($contents);
10718    }
10719    $contents . $_;
10720}
10721
10722
10723sub do_cmd_mbox {
10724    local($_) = @_;
10725    local($text,$after)=('','');
10726    $text = &missing_braces unless (
10727	(s/$next_pair_pr_rx/$text = $2;''/eo)
10728	||(s/$next_pair_rx/$text = $2;''/eo));
10729    $after = $_;
10730
10731    # incomplete macro replacement
10732    if ($text =~ /(^|[^\\<])#\d/) { return($after) }
10733
10734    if ($text =~ /(tex2html_wrap_inline|\$$OP(\d+)$CP$OP\2$CP\$|\$$O(\d+)$C$O\2$C\$)/) {
10735	if ($text =~
10736	    /$image_mark#([^#]+)#([\.,;:\)\]])?(\001)?([ \t]*\n?)(\001)?/) {
10737	    local($mbefore, $mtext, $mafter) = ($`, $&, $');
10738	    $mbefore = &translate_commands($mbefore) if ($mbefore =~ /\\/);
10739	    $mafter = &translate_commands($mafter) if ($mafter =~ /\\/);
10740	    join('', $mbefore, $mtext, $mafter, $after);
10741	} else {
10742	    join ('', &process_math_in_latex('','','',"\\hbox{$text}"), $after )
10743	}
10744    } else {
10745	$text = &translate_environments($text);
10746	$text = &translate_commands($text);
10747	join('', $text, $after);
10748    }
10749}
10750
10751
10752
10753# *Generates* subroutines to handle each of the declarations
10754# like \em, \quote etc., in case they appear with the begin-end
10755# syntax.
10756sub generate_declaration_subs {
10757    local($key, $val, $pre, $post, $code );
10758    print "\n *** processing declarations ***\n";
10759    while ( ($key, $val) = each %declarations) {
10760	if ($val) {
10761	    ($pre,$post) = ('','');
10762	    $val =~ m|</.*$|;
10763	    do {$pre = $`; $post = $& } unless ($` =~ /^<>/);
10764	    $pre =~ s/"/\\"/g; $post =~ s/"/\\"/g;
10765	    $code = "sub do_env_$key {"
10766#		. 'local($_) = @_;' . "\n"
10767#		. 'push(@$open_tags_R, $key);'. "\n"
10768#		. '$_ = &translate_environments($_);'. "\n"
10769#		. '$_ = &translate_commands($_);'. "\n"
10770#		. "join('',\"$pre\",\"\\n\"," .'$_' .",\"$post\");\n};";
10771		. '&declared_env('.$key.',@_)};';
10772	    eval $code;
10773	    if ($@) {print "\n *** $key ".  $@ };
10774	}
10775    }
10776				      }
10777
10778# *Generates* subroutines to handle each of the sectioning commands.
10779sub generate_sectioning_subs {
10780    local($key, $val, $cmd, $body);
10781    while ( ($key, $val) = each %standard_section_headings) {
10782	$numbered_section{$key} = 0;
10783	eval "sub do_cmd_$key {"
10784	    . 'local($after,$ot) = @_;'
10785	    . 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'
10786            . '&reset_dependents('. $key . ');'
10787            . '&do_cmd_section_helper('.$val.','.$key.');}';
10788	print STDERR "\n*** sub do_cmd_$key failed:\n$@\n" if ($@);
10789	# Now define the *-form of the same commands. The difference is that the
10790	# $key is not passed as an argument.
10791	eval "sub do_cmd_$key" . "star {"
10792	    . 'local($after,$ot) = @_;'
10793	    . 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'
10794	    . '&do_cmd_section_helper(' . $val . ');}';
10795	print STDERR "\n*** sub do_cmd_${key}star failed:\n$@\n" if ($@);
10796	# Now define the macro  \the$key
10797	&process_commands_wrap_deferred("the$key \# {}\n");
10798###	local($_) = "<<1>>$key<<1>>";
10799	$body = "<<1>>$key<<1>>";
10800	&make_unique($body);
10801	$cmd = "the$key";
10802	eval "sub do_cmd_$cmd {"
10803	    . 'local($after,$ot) = @_;'
10804	    . 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'
10805	    . '&do_cmd_arabic(' . "\"$body\"" . ").\$after;};";
10806	print STDERR "\n*** sub do_cmd_$cmd failed:\n$@\n" if ($@);
10807	$raw_arg_cmds{$cmd} = 1;
10808    }
10809    &addto_dependents('chapter','section');
10810    &addto_dependents('section','subsection');
10811    &addto_dependents('subsection','subsubsection');
10812    &addto_dependents('subsubsection','paragraph');
10813    &addto_dependents('paragraph','subparagraph');
10814}
10815
10816sub addto_dependents {
10817    local($ctr, $dep) = @_;
10818    local($tmp, $depends);
10819    if ($depends = $depends_on{$dep}) {
10820	&remove_dependency($depends, $dep) }
10821    $depends_on{$dep} = $ctr;
10822
10823    $tmp = $dependent{$ctr};
10824    if ($tmp) {
10825	$dependent{$ctr} = join($delim, $tmp, $dep);
10826    } else { $dependent{$ctr} = $dep }
10827				      }
10828
10829sub remove_dependency {
10830    local($ctr, $dep) = @_;
10831    local(@tmp, $tmp, $dtmp);
10832    print "\nremoving dependency of counter {$dep} from {$ctr}\n";
10833    foreach $dtmp (split($delim, $dependent{$ctr})) {
10834	push(@tmp, $dtmp) unless ($dtmp =~ /$dep/);
10835    }
10836    $dependent{$ctr} = join($delim, @tmp);
10837}
10838
10839
10840# Uses $after which is defined in the caller (the caller is a generated subroutine)
10841# Also uses @curr_sec_id
10842#
10843#JCL(jcl-tcl) (changed almost everything)
10844#
10845sub do_cmd_section_helper {
10846    local($H,$key) = @_;
10847    local($section_number, $titletext, $title_key, @tmp, $align, $dummy);
10848    local($anchors,$pre,$run_title,$_) = ('', "\n", '', $after);
10849    local($open_tags_R) = [];
10850
10851    # if we have a $key the current section is not of the *-form, so we need
10852    # to update the counters.
10853    &do_cmd_stepcounter("${O}0$C$key${O}0$C")
10854	if ($key && !($unnumbered_section_commands{$key}));
10855    if ($key =~ /^paragraph/) {
10856	$H .=' class="bparagraph"' ;
10857    }
10858    if ($key =~ /^subparagraph/) {
10859	$H .=' class="bsubparagraph"' ;
10860    }
10861    local($br_id);
10862    local ($align, $dummy)=&get_next_optional_argument;
10863    if (($align =~/^(left|right|center)$/i)&&($HTML_VERSION > 2.0)) {
10864        $align = "ALIGN=\"$1\"";
10865    } elsif ($align) {
10866	# data was meant to be a running-head !
10867	$br_id = ++$global{'max_id'};
10868	$run_title = &translate_environments("$O$br_id$C$align$O$br_id$C");
10869	$run_title = &translate_commands($run_title) if ($run_title =~ /\\/);
10870	$run_title =~ s/($O|$OP)\d+($C|$CP)//g;
10871	$align = '';
10872    } else {
10873    }
10874    $titletext = &missing_braces
10875	unless s/$next_pair_rx/$titletext=$2;''/eo;
10876    $br_id = ++$global{'max_id'};
10877    $titletext = &translate_environments("$O$br_id$C$titletext$O$br_id$C");
10878
10879    $title_key = $run_title || $titletext;
10880    $title_key =~ s/$image_mark\#([^\#]+)\#(\\space)?/&purify_caption($1)/e;
10881    # This should reduce to the same information as contained in the .aux file.
10882    $title_key = &sanitize(&simplify($title_key));
10883
10884    # RRM: collect all anchors from \label and \index commands
10885    ($anchors,$titletext) = &extract_anchors($titletext);
10886    local($saved_title) = $titletext;
10887    do {
10888        # to ensure a style ID is not saved and re-used in (mini-)TOCs
10889	local($USING_STYLES) = 0;
10890	$titletext = &translate_environments($titletext);
10891	$titletext = &translate_commands($titletext)
10892	    if ($titletext =~/\\/);
10893    };
10894    # but the style ID can be used for the title on the HTML page
10895    if (!($titletext eq $saved_title)) {
10896	$saved_title = &translate_environments($saved_title);
10897	$saved_title = &translate_commands($saved_title)
10898	    if ($saved_title =~/\\/);
10899	$saved_title = &simplify($saved_title);
10900    }
10901    local($closures) = &close_all_tags();
10902    $saved_title .= $closures;
10903    $title_text .= $closures;
10904
10905    # This is the LaTeX section number read from the $FILE.aux file
10906    @tmp = split(/$;/,$encoded_section_number{$title_key});
10907    $section_number = shift(@tmp);
10908    $section_number = "" if ($section_number eq "-1");
10909    $encoded_section_number{$title_key} = join($;, @tmp)
10910#	unless (defined $title);
10911	unless ($title);
10912
10913    # need to check also &{wrap_cmd_... also, if \renewcommand has been used;
10914    # thanks Bruce Miller
10915    local($thehead,$whead) = ("do_cmd_the$key","wrap_cmd_the$key");
10916    $thehead = ((defined &$thehead)||(defined &$whead)
10917	? &translate_commands("\\the$key") : '');
10918    $thehead .= $SECNUM_PUNCT
10919	if ($SECNUM_PUNCT &&($thehead)&& !($thehead =~ /\./));
10920    $section_number = $thehead if (($thehead)&&($SHOW_SECTION_NUMBERS));
10921
10922    #JKR: Don't prepend whitespace
10923    if ($section_number) {
10924	$titletext = "$section_number " . $titletext;
10925	$saved_title = "$section_number " . $saved_title;
10926	$run_title = "$section_number " . $run_title if $run_title;
10927    }
10928
10929#    $toc_sec_title = $titletext;
10930#    $toc_sec_title = &purify($titletext);
10931    $toc_sec_title = &simplify($titletext);
10932    $titletext = &simplify($titletext);
10933#    $TITLE = &purify($titletext);
10934    local($after) = $_;
10935    do {
10936	local($_) = $titletext; &remove_anchors;
10937	if ($run_title) {
10938	    $TITLE = $run_title;
10939	} elsif ($_) {
10940	    $TITLE = $_
10941	} else { $TITLE = '.' };
10942    };
10943    $global{$key}-- if ($key && $making_name);
10944    return ($TITLE) if (defined $title);
10945
10946    #RRM: no preceding \n when this is the first section-head on the page.
10947    if (! $key || $key < $MAX_SPLIT_DEPTH) { $pre = '' };
10948    if ( defined &make_pre_title) {
10949	$pre = &make_pre_title($saved_title, $H);
10950    }
10951
10952    undef $open_tags_R;
10953    $open_tags_R = [ @save_open_tags ];
10954
10955    join('', $pre, &make_section_heading($saved_title, $H, $align.$anchors)
10956	, $open_all, $_);
10957}
10958
10959sub do_cmd_documentclass {
10960    local($_) = @_;
10961    local ($docclass)=('');
10962    local ($cloptions,$dum)=&get_next_optional_argument;
10963    $docclass = &missing_braces unless (
10964	(s/$next_pair_pr_rx/$docclass = $2;''/eo)
10965	||(s/$next_pair_rx/$docclass = $2;''/eo));
10966    local($rest) = $';
10967    &do_require_package($docclass);
10968    if (! $styles_loaded{$docclass}) {
10969	&no_implementation("document class",$docclass);
10970    } else {
10971	if($cloptions =~ /\S+/) { # are there any options?
10972	    &do_package_options($docclass,$cloptions);
10973	}
10974    }
10975    $rest;
10976				      }
10977sub do_cmd_documentstyle { &do_cmd_documentclass($_[0]); }
10978
10979sub do_cmd_usepackage {
10980    local($_) = @_;
10981    # RRM:  allow lists of packages and options
10982    local ($package, $packages)=('','');
10983    local ($options,$dum)=&get_next_optional_argument;
10984    $packages = &missing_braces unless (
10985	(s/$next_pair_pr_rx/$packages = $2;''/eo)
10986	||(s/$next_pair_rx/$packages = $2;''/eo));
10987    local($rest) = $_;
10988    # MRO: The files should have already been loaded by
10989    #      TMP_styles, but we better make it sure.
10990    foreach $package (split (',',$packages)) {	# allow multiple packages
10991	$package =~ s/\s|\%|$comment_mark\d*//g; # remove whitespace
10992	$package =~ s/\W/_/g; # replace non-alphanumerics
10993	&do_require_package($package);
10994	if (! $styles_loaded{$package}) {
10995	    &no_implementation("package",$package);
10996	} else {
10997	    if($options =~ /\S+/) { # are there any options?
10998		&do_package_options($package,$options);
10999	    }
11000	}
11001    }
11002    $rest;
11003}
11004
11005
11006sub no_implementation {
11007    local($what,$which)= @_;
11008    print STDERR "\nWarning: No implementation found for $what: $which\n";
11009}
11010
11011sub do_cmd_RequirePackage {
11012    local($_)= @_;
11013    local($file);
11014    local($options,$dum)=&get_next_optional_argument;
11015    $file = &missing_braces unless (
11016	(s/$next_pair_pr_rx/$file = $2;''/eo)
11017	||(s/$next_pair_rx/$file = $2;''/eo));
11018    local($rest) = $_;
11019    $file =~ s/^[\s\t\n]*//o;
11020    $file =~ s/[\s\t\n]*$//o;
11021    # load the package, unless that has already been done
11022    &do_require_package($file) unless ($styles_loaded{$file});
11023    # process any options
11024    if (! $styles_loaded{$file}) {
11025	    &no_implementation("style",$file);
11026    } else {
11027	# process any options
11028	&do_package_options($file,$options) if ($options);
11029    }
11030    $_ = $rest;
11031    # ignore trailing optional argument
11032    local($date,$dum)=&get_next_optional_argument;
11033    $_;
11034}
11035
11036sub do_cmd_PassOptionsToPackage {
11037    local($_) = @_;
11038    local($options,$file);
11039    $options = &missing_braces unless (
11040        (s/$next_pair_pr_rx/$options = $2;''/eo)
11041        ||(s/$next_pair_rx/$options = $2;''/eo));
11042    $file = &missing_braces unless (
11043        (s/$next_pair_pr_rx/$file = $2;''/eo)
11044        ||(s/$next_pair_rx/$file = $2;''/eo));
11045    $passedOptions{$file} = $options;
11046    $_;
11047}
11048sub do_cmd_PassOptionsToClass{ &do_cmd_PassOptionsToPackage(@_)}
11049
11050sub do_package_options {
11051    local($package,$options)=@_;
11052    local($option);
11053    if ($passedOptions{$package}) { $options = $passedOptions{$package}.'.'.$options };
11054    foreach $option (split (',',$options)) {
11055        $option =~ s/^[\s\t\n]*//o;
11056        $option =~ s/[\s\t\n]*$//o;
11057	$option =~ s/\W/_/g; # replace non-alphanumerics
11058	next unless ($option);
11059        if (!($styles_loaded{$package."_$option"})) {
11060            &do_require_packageoption($package."_$option");
11061            if (!($styles_loaded{$package."_$option"})) {
11062		&no_implementation("option","\`$option\' for \`$package\' package\n");
11063	    }
11064	}
11065    }
11066    $rest;
11067				      }
11068
11069sub do_class_options {
11070    local($class,$options)=@_;
11071    local($option);
11072    if ($passedOptions{$class}) { $options = $passedOptions{$class}.'.'.$options };
11073    foreach $option (split (',',$options)) {
11074        $option =~ s/^[\s\t\n]*//o;
11075        $option =~ s/[\s\t\n]*$//o;
11076	$option =~ s/\W/_/g; # replace non-alphanumerics
11077	next unless ($option);
11078        &do_require_package($option);
11079        if (!($styles_loaded{$class."_$option"})) {
11080            &do_require_packageoption($class."_$option");
11081            if (!($styles_loaded{$class."_$option"})) {
11082		&no_implementation("option","\`$option\' for document-class \`$class\'\n");
11083	    }
11084	}
11085    }
11086    $rest;
11087}
11088
11089sub do_require_package {
11090    local($file)= @_;
11091    local($dir);
11092    #RRM: make common ps/eps-packages use  epsfig.perl
11093    $file = 'epsfig' if ($file =~ /^(psfig|epsf)$/);
11094
11095    if ($file =~ /^graphicx$/) {
11096	# work-around the CVS repository bug: use graphixx , not graphicx
11097	foreach $dir (split(/$envkey/,$LATEX2HTMLSTYLES)) {
11098	    if (-f "$dir${dd}graphixx.perl") {
11099		$file = 'graphixx';
11100		last;
11101	    }
11102	}
11103    }
11104
11105
11106    if (! $styles_loaded{$file}) {
11107	# look for a file named ${file}.perl
11108	# MRO: use $texfilepath instead of `..'
11109	if ((-f "$texfilepath$dd${file}.perl") && ! $styles_loaded{$file}){
11110	    print STDOUT "\nPackage: loading $texfilepath$dd${file}.perl";
11111	    require("$texfilepath$dd${file}.perl");
11112	    $styles_loaded{$file} = 1;
11113	} else {
11114	    foreach $dir (split(/$envkey/,$LATEX2HTMLSTYLES)) {
11115		if ((-f "$dir$dd${file}.perl") && ! $styles_loaded{$file}){
11116		    print STDOUT "\nPackage: loading $dir$dd${file}.perl";
11117		    require("$dir$dd${file}.perl");
11118	    	    $styles_loaded{$file} = 1;
11119		    last;
11120		}
11121	    }
11122	}
11123    }
11124				      }
11125
11126sub do_require_extension {
11127    local($file)= @_;
11128    local($dir);
11129
11130    if (! $styles_loaded{$file}) {
11131	# look for a file named ${file}.pl
11132	# MRO: use $texfilepath instead of `..'
11133	if (-f "$texfilepath$dd${file}.pl") {
11134	    print STDOUT "\nExtension: loading $texfilepath$dd${file}.pl";
11135	    require("$texfilepath$dd${file}.pl");
11136	    ++$styles_loaded{$file};
11137	    $NO_UTF = 1 if (($file =~ /latin/)&&($charset =~/utf/));
11138	} else {
11139	    foreach $dir (split(/$envkey/,$LATEX2HTMLVERSIONS)) {
11140		if (-f "$dir$dd${file}.pl"){
11141		    print STDOUT "\nExtension: loading $dir$dd${file}.pl";
11142		    require("$dir$dd${file}.pl");
11143		    ++$styles_loaded{$file};
11144		    $NO_UTF = 1 if (($file =~ /latin/)&&($charset =~/utf/));
11145		    last;
11146		}
11147	    }
11148	}
11149    } else {
11150	if (($file =~ /latin|hebrew/)&&($charset =~/utf|10646/)
11151			&& $loading_extensions) {
11152	    $NO_UTF = 1;
11153	    $USE_UTF = 0;
11154	    print STDOUT "\n\n ...producing $CHARSET output\n";
11155	    $charset = $CHARSET;
11156	}
11157    }
11158}
11159
11160sub do_require_packageoption {
11161    local($option)= @_;
11162    local($do_option);
11163    # first look for a file named ${option}.perl
11164    &do_require_package($option) unless ($styles_loaded{$option});
11165    # next look for a subroutine named  do_$option
11166    $do_option = "do_$option";
11167    if (!($styles_loaded{$option}) && defined(&$do_option)) {
11168	&$do_option();
11169	$styles_loaded{$option} = 1;
11170    }
11171}
11172
11173############################ Environments ################################
11174
11175# This is a dummy environment used to synchronise the expansion
11176# of order-sensitive macros.
11177sub do_env_tex2html_deferred {
11178    local($_) = @_;
11179    local($tex2html_deferred) = 1;
11180    $_ = &process_command($single_cmd_rx,$_);
11181}
11182
11183# catch wrapped commands that need not have been
11184sub do_env_tex2html_nomath_inline {
11185    local($_) = @_;
11186    s/^\s+|\s+$//gs;
11187    my($cmd) = $_;
11188    if ($cmd=~s/^\\([a-zA-Z]+)//s) { $cmd = $1 };
11189    return (&translate_commands($_)) if ($raw_arg_cmds{$cmd}<1);
11190    &process_undefined_environment($env, $id, $_);
11191}
11192
11193# The following list environment subroutines still do not handle
11194# correctly the case where the list counters are modified (e.g. \alph{enumi})
11195# and the cases where user defined bullets are mixed with the default ones.
11196# e.g. \begin{enumerate} \item[(1)] one \item two \end{enumerate} will
11197# not produce the same bullets as in the dvi output.
11198sub do_env_itemize {
11199    local($_) = @_;
11200    $itemize_level++;
11201    #RRM - catch nested lists
11202    &protect_useritems($_);
11203    $_ = &translate_environments($_);
11204
11205    local($bullet,$bulletx)=('&nbsp;','');
11206    SWITCH: {
11207	if ($itemize_level==1) { $bulletx = "\\bullet"; last SWITCH; }
11208	if ($itemize_level==2) { $bulletx = "\\mathbf{\\circ}"; last SWITCH; }
11209	if ($itemize_level==3) { $bulletx = "\\mathbf{\\ast}"; last SWITCH; }
11210    }
11211    $itemize_level--;
11212
11213    if (/\s*$item_description_rx/) {
11214	# Contains user defined optional labels
11215	$bulletx = &do_cmd_mbox("${O}1$C\$$bulletx\$${O}1$C") if $bulletx;
11216	&do_env_description($_, " COMPACT", $bullet.$bulletx)
11217    } else { &list_helper($_,'UL'); }
11218				      }
11219
11220sub do_env_enumerate {
11221    local($_) = @_;
11222# Reiner Miericke provided the main code; integrated by RRM: 14/1/97
11223# works currently only with 'enumerate' and derived environments
11224# explicit styled labels are computed for each \item
11225# ultimately the environment is done as:  &do_env_description($_, " COMPACT")
11226    ++$enum_level;
11227    local(%enum) = %enum;		# to allow local changes
11228# Reiner: \begin{enumerate}[<standard_label>]
11229    local($standard_label) = "";
11230    local(@label_fields);
11231    local($label_func, $preitems, $enum_type);
11232    local($rlevel) = &froman($enum_level); # e.g. 3 => iii
11233
11234    # \begin{enumerate}[$standard_label]
11235    if (s/^$standard_label_rx//s) {		# multiline on/off ?
11236	# standard label should be used later to modify
11237	# entries in %enum
11238	$standard_label = $1;		# save the standard label
11239#	s/^$standard_label_rx//;	# and cut it off
11240	$standard_label =~ s/([\\\[\]\(\)])/\\$1/g; # protect special chars
11241
11242	# Search for [aAiI1] which is not between a pair of { }
11243	# Other cases like "\theenumi" are not handled
11244	@label_fields = $standard_label =~ /$enum_label_rx/;
11245	if (($standard_label =~ /^[aAiI1]$/)&&(not(/item\s*\[/))) {
11246	    $enum_type = ' TYPE="'.$standard_label.'"';
11247	    $standard_label = '';
11248	} else {
11249	    $label_func = $enum_label_funcs{$label_fields[$#label_fields-1]} .
11250		"(\'enum" . $rlevel . "\')";
11251	    $enum{'theenum' . $rlevel} = "\&$label_func";
11252#	local($thislabel) = "\&$label_func";
11253#	do { local($_) = $thislabel; &make_unique($_);
11254#	     $enum{'theenum' . $rlevel} = $_; };
11255	    $standard_label =
11256		"\"$label_fields[0]\" . eval(\$enum{\"theenum$rlevel\"})"
11257		. ".\"$label_fields[$#label_fields]\"";
11258	    $enum{'labelenum' . $rlevel} = $standard_label;
11259	}
11260    }  elsif (s/^((.|\n)+?)\\item/$preitems=$1;"\\item"/es) {
11261	my $pre_preitems; local($cmd); $label_part;
11262	my $num_styles = join('|', values %enum_label_funcs );
11263	while ($preitems =~
11264	    /\s*\\renew(ed)?command\s*(($O|$OP)\d+($C|$CP))\\?((label|the)enum(\w+))\s*\2/) {
11265	    # this catches one  \renewcommand{\labelenum}{....}
11266	    $pre_preitems .= $`; $preitems = $'; $cmd = $5;
11267	    &missing_braces unless (
11268	        ($preitems=~s/$next_pair_pr_rx\s*/$label_part=$2;''/oe)
11269	        ||($preitems=~s/$next_pair_rx\s*/$label_part=$2;''/oe));
11270	    $cmd =~ s/^label/the/;
11271	    $label_part=~s/\\($num_styles)\s*(($O|$OP)\d+($C|$CP))(\w+)\2/".\&$1\(\'$5\'\)."/g;
11272	    $label_part = '"'.$label_part.'"';
11273	    $enum{$cmd} = $label_part;
11274        }
11275	$standard_label =
11276	    "\"$label_fields[0]\" . eval(\$enum{\"theenum$rlevel\"})"
11277	    . ".\"$label_fields[$#label_fields]\"" if ($cmd);
11278	$_ = $pre_preitems . $preitems . $_ if ($pre_preitems||$preitems);
11279    } else {
11280	@enum_default_type = ('A', '1', 'a', 'i', 'A') unless (@enum_default_type);
11281	$enum_type = $enum_level%4;
11282	$enum_type = ' Type="'.@enum_default_type[$enum_type].'"';
11283    }
11284
11285    # enclose contents of user-defined labels within a group,
11286    # in case of style-change commands, which could bleed outside the label.
11287    &protect_useritems($_);
11288    $_ = &translate_environments($_);	#catch nested lists
11289
11290    local($enum_result);
11291    if (($standard_label)||(/\\item\[/)) {
11292	# split it into items
11293	@items = split(/\\item\b/,$_);
11294	# save anything (non-blank) before the items actually start
11295	$preitems = shift(@items);
11296	$preitems =~ s/^\s*$//;
11297	local($enum_label);
11298	# prepend each item with an item label: \item => \item[<label>]
11299	foreach $item (@items) {
11300#	  unless ( $item =~ /^\s*$/ ) { # first line may be empty
11301	    $enum{"enum" . $rlevel}++;	# increase enumi
11302	    $enum_label = eval("$enum{'labelenum' . $rlevel}");
11303	    # insert a label, removing preceding space, BUT...
11304	    # do NOT handle items with existing labels
11305	    $item =~ s/^\s*//;
11306	    if ($item =~ s/^\s*\[([^]]*)\]//) {
11307		$enum{"enum" . $rlevel}--;
11308		$enum_label = "$1";
11309		local($processed) = ($enum_label =~/$OP/);
11310		$enum_label = join('',($processed ? "<#0#>" : "<<0>>")
11311		    ,$enum_label ,($processed ? "<#0#>" : "<<0>>"))
11312			if ($enum_label =~ /\\/);
11313		if ($processed) { &make_unique_p($enum_label) }
11314		elsif ($enum_label =~ /$O/) { &make_unique($enum_label) };
11315		$item = "[${enum_label}]".$item;
11316	    } else {
11317		local($processed) = ($enum_label =~/$OP/);
11318		$enum_label = join('',($processed ? "<#0#>" : "<<0>>")
11319		    ,$enum_label ,($processed ? "<#0#>" : "<<0>>"))
11320			if ($enum_label =~ /\\/);
11321		if ($processed) { &make_unique_p($enum_label) }
11322		elsif ($enum_label =~ /$O/) { &make_unique($enum_label) };
11323		$item = "[$enum_label\]$item";
11324		$enum_label =~ s/\.$//;
11325	    }
11326	    if ($standard_label) {
11327	        $item =~ s/(\\labelitem$rlevel|$standard_label)/$enum_label/g
11328	    } else {
11329	        $item =~ s/(\\labelitem$rlevel)/$enum_label/g
11330	    }
11331	};
11332	$_ = join("\\item ", $preitems, @items);
11333
11334	# Original, but $enum_result
11335	$enum_result = &do_env_description($_, " COMPACT");
11336    } else {
11337	$enum_result = &list_helper($_, "OL$enum_type", '', '');
11338    }
11339
11340    #clean-up and revert the $enum_level
11341    $enum{"enum" . $rlevel} = 0;
11342    $enum{"enum" . &froman($enum_level)} = 0;
11343    --$enum_level;
11344    $enum_result;
11345				      }
11346
11347sub do_env_list {
11348    local ($_) = @_;
11349    local ($list_type,$labels,$lengths) = ('UL','','');
11350
11351    $labels = &missing_braces unless	 ( # get the label specifier
11352	(s/$next_pair_pr_rx/$labels=$2;''/e)
11353	||(s/$next_pair_rx/$labels=$2;''/e));
11354
11355    $lengths = &missing_braces unless ( # get the length declarations
11356	(s/$next_pair_pr_rx/$lengths=$2;''/e)
11357	||(s/$next_pair_rx/$lengths=$2;''/e));
11358    # switch to enumerated style if they include a \usecounter.
11359    $list_type = 'OL' if $lengths =~ /\\usecounter/;
11360
11361    /\\item\b/; local($preitems) = $`;
11362	$_ =~ s/^\Q$preamble//s if ($preitems);
11363    $preitems =~s/^\s*|\s*$//g;
11364    if ($preitems) {
11365	$preitems = &translate_environments($preitems);
11366	$preitems = &translate_commands($preitems) if ($preitems =~ /\\/);
11367#	&write_warnings("\nDiscarding: $preitems before 1st item in list")
11368#	    if ($preitems);
11369    }
11370
11371    #RRM - catch nested lists
11372    #RRM unfortunately any uses of the \\usecounter  within \item s
11373    #    may be broken --- sigh.
11374    &protect_useritems($_);
11375    $_ = &translate_environments($_);
11376
11377    if (($list_type =~ /OL/)&&($labels)) {
11378	local($br_ida,$br_idb,$label,$aft);
11379	$br_ida = ++$global{'max_id'};
11380	$lengths =~ s/\\usecounter((($O|$OP)\d+($C|$CP))[^<]+\2)/
11381		&make_nowrapper(1)."\\stepcounter$1".&make_nowrapper(0)/e;
11382	$labels = "$O$br_ida$C$lengths$O$br_ida$C".$labels;
11383
11384#	s/\\item\b\s*([^\[])/do {
11385#		$label = $labels; $aft = $1;
11386#		$br_id = ++$global{'max_id'};
11387#		$label = &translate_environments(
11388#			"$O$br_id$C$label$O$br_id$C");
11389#		join('',"\\item\[" , $label, "\]$aft" );
11390#	    }/eg;
11391#	$labels ='';
11392    }
11393
11394    if (($labels)||(/\\item\[/)) {
11395	$_ = &list_helper($_, 'DL', $labels, $lengths)
11396    } else {
11397	$_ = &list_helper($_, $list_type, '', $lengths)
11398    }
11399    $_;
11400}
11401
11402sub do_env_trivlist {
11403    local($_) = @_;
11404    local($compact,$item_sep,$pre_items) = ' COMPACT';
11405    &protect_useritems($_);
11406
11407    # assume no styles initially for this list
11408    local($close_tags,$reopens) = &close_all_tags();
11409    local($open_tags_R) = [];
11410    local(@save_open_tags) = ();
11411
11412    # include \label anchors from [...] items
11413    s/$item_description_rx\s*($labels_rx8)?\s*/
11414	(($9)? "<A NAME=\"$9\">$1<\/A>" : $1 ) ."\n"/eg;
11415    # remove unwanted space before \item s
11416    s/[ \t]*\\item\b/\\item/g;
11417
11418    local($this_item,$br_id) = ('','');
11419    local($this_sitem,$this_eitem) = ("\n<P>","</P>\n",'');
11420
11421    # assume no sub-lists, else...  why use {trivlist} ?
11422    # extract up to the 1st \item
11423    local(@items) = split(/\\item\b/, $_);
11424    $pre_items = shift @items;
11425    $_ = '';
11426    while (@items) {
11427	$br_id = ++$global{'max_id'};
11428	$this_item = shift @items;
11429	$this_item = &translate_environments(
11430	     "$O$br_id$C".$pre_items.$this_item."$O$br_id$C" );
11431	if ($this_item =~ /\\/) {
11432	    $this_item = &translate_commands($this_item);
11433	    $_ .= join('' , $this_sitem
11434		       , $this_item
11435		       # , $this_eitem
11436		       )
11437	} else { $_ .= $this_sitem . $this_item }
11438    }
11439
11440    $_ = &translate_environments($_);
11441    $_ = &translate_commands($_);
11442
11443    join('' , $close_tags , $_ , $reopens);
11444
11445}
11446
11447# enclose the contents of any user-defined labels within a group,
11448# else any style-change commands may bleed outside the label.
11449sub protect_useritems {
11450    # MRO: use $_[0] instead: local(*_) = @_;
11451    local($preitems, $thisitem);
11452    $_[0] =~ s/^$par_rx\s*//s; # discard any \par before 1st item
11453
11454    # locate \item with optional argument
11455    local($saveRS) = $/; undef $/;
11456    local(@preitems);
11457    # allow one level of nested []
11458    # MRO: Caution! We have a double-wildcarded RX here, this may cause
11459    # trouble. Should be re-coded.
11460    $_[0] =~ s/\\item[\s\r]*(\b(\[(([^\[\]]|\[[^]]*\])*)\])?|[^a-zA-Z\s])/
11461	$thisitem = " $1";
11462	if ($2) {
11463	    $br_id = ++$global{'max_id'};
11464	    $thisitem = '['.$O.$br_id.$C.$3.$O.$br_id.$C.']';
11465	};
11466	"\\item".$thisitem
11467    /egm;
11468
11469    $/ = $saveRS;
11470    $_[0] = join(@preitems, $_[0]);
11471}
11472
11473sub do_env_description {
11474    local($_, $compact, $bullet) = @_;
11475    #RRM - catch nested lists
11476    &protect_useritems($_);
11477    $_ = &translate_environments($_) unless ($bullet);
11478
11479    # MRO: replaced $* with /m
11480    $compact = "" unless $compact;
11481    if ($compact) {		# itemize/enumerate with optional labels
11482	s/\n?$item_description_rx\s*($labels_rx8)?\s*/"\n<\/DD>\n<DT>".
11483	    (($9)? "<A NAME=\"$9\">$1<\/A>" : $1 ) ."<\/DT>\n<DD>"/egm;
11484    } else {
11485	s/\n?$item_description_rx\s*($labels_rx8)?\s*/"\n<\/DD>\n<DT>".
11486	    (($9)? "<A NAME=\"$9\"><STRONG>$1<\/STRONG><\/A>"
11487	     : "<STRONG>$1<\/STRONG>") ."<\/DT>\n<DD>"/egm;
11488    }
11489    # and just in case the description is empty ...
11490#JCL(jcl-del) - $delimiter_rx -> ^$letters
11491    s/\n?\\item\b\s*([^$letters\\]|)\s*/\n<\/DD>\n<DT>$bullet<\/DT>\n<DD>$1/gm;
11492    s/^\s+//m;
11493
11494    $_ = '<DD>'.$_ unless ($_ =~ s/^\s*<\/D(T|D)>\n?//s);
11495    $_ =~ s/\n$//s;
11496    "<DL$compact>\n$_\n</DD>\n</DL>";
11497}
11498
11499sub list_helper {
11500    local($_, $tag, $labels, $lengths) = @_;
11501    local($item_sep,$pre_items,$compact,$etag,$ctag);
11502    $ctag = $tag; $ctag =~ s/^(.*)\s.*$/$1/;
11503
11504    # assume no styles initially for this list
11505    local($close_tags,$reopens) = &close_all_tags();
11506    local($open_tags_R) = [];
11507    local(@save_open_tags) = ();
11508
11509#    #RRM: cannot have anything before the first <LI>
11510#    local($savedRS) = $/; $/='';
11511#    $_ =~ /\\item[\b\r]/s;
11512#    if ($`) {
11513#	$preitems = $`; $_ = $&.$';
11514#	$preitems =~ s/<P( [^>]*)?>//g;
11515#	$close_tags .= "\n".$preitems if $preitems;
11516#    }
11517#    $/ = $savedRS;
11518#
11519
11520    if (($tag =~ /DL/)&&$labels) {
11521	local($label,$aft,$br_id);
11522	s/\\item\b[\s\r]*([^\[])/do {
11523		$label = $labels; $aft = $1;
11524		$br_id = ++$global{'max_id'};
11525		$label = &translate_environments(
11526			"$O$br_id$C$label$O$br_id$C");
11527		join('',"\\item\[" , $label, "\]$aft" );
11528	    }/egm;
11529    }
11530
11531    # This deals with \item[xxx] ...
11532    if ($tag =~ /DL/) {
11533	$compact = ' COMPACT';
11534	# include \label anchors in the <DT> part
11535	# and  $pre_item  tags in the <DD> part:
11536	if ($labels && $lengths) {
11537	    $item_sep = "\n</DD>\n<DT>";
11538	} else {
11539	    $item_sep = ($labels ? "<DT>$labels\n" : '') ."</DT>\n<DD>";
11540	}
11541	$etag = "\n</DD>";
11542	s/$item_description_rx[\r\s]*($labels_rx8)?[\r\s]*/"<DT>" .
11543	    (($9)? "<A NAME=\"$9\">$1<\/A>" : $1 ) ."\n<DD>"/egm;
11544    } else {
11545	$item_sep = "\n</LI>\n<LI>";
11546	$etag = "\n</LI>";
11547    }
11548
11549    # remove unwanted space before \item s
11550    s/[ \t]*\\item\b/\\item/gm;
11551
11552    #JCL(jcl-del) - $delimiter_rx -> ^$letters
11553    s/\n?\\item\b[\r\s]*/$item_sep/egm;
11554
11555    #RRM: cannot have anything before the first <LI>
11556    local($savedRS) = $/; $/='';
11557    $_ =~ /\Q$item_sep\E|<DT>|<LI>/s;
11558    #RRM: ...try putting it before the list-open tag
11559    if ($`) {
11560	$preitems = $`; $_ = $&.$';
11561	$preitems =~ s/<P( [^>]*)?>//gm;
11562	$close_tags .= "\n".$preitems if $preitems;
11563    }
11564    $_ =~ s/^\s*<\/[^>]+>\s*//s;
11565
11566    # remove \n from end of the last item
11567    $_ =~ s/\n$//s;
11568    $/ = $savedRS;
11569
11570    join('' , $close_tags , "\n<$tag$compact>\n"
11571	 , $_ , "$etag\n</$ctag>" , $reopens);
11572				      }
11573
11574
11575# RRM:  A figure environment generates a picture UNLESS it contains a
11576# {makeimage} sub-environment; in which case it creates a <DIV>
11577# inside which the contents are interpreted as much as is possible.
11578# When there are captions, this modifies $before .
11579sub do_env_figure {
11580    local($_) = @_;
11581    local($halign, $anchors) = ('CENTER','');
11582    local ($border, $attribs );
11583    local($cap_width) = $cap_width;
11584    my ($opt, $dummy) = &get_next_optional_argument;
11585
11586    my $abovedisplay_space = $ABOVE_DISPLAY_SPACE||"<P></P>\n";
11587    my $belowdisplay_space = $BELOW_DISPLAY_SPACE||"<P></P>\n";
11588
11589    ($_,$anchors) = &extract_labels($_); # extract labels
11590    # Try to establish the alignment
11591    if (/^(\[[^\]]*])?\s*\\begin\s*<<\d*>>(\w*)<<\d*>>|\\(\w*)line/) {
11592	$halign = $2.$3;
11593	if ($halign =~ /right/i)  { $halign = 'RIGHT' }
11594	elsif ($halign =~ /left/i) { $halign = 'LEFT' }
11595	elsif ($halign =~ /center/i) { $halign = 'CENTER' }
11596	else { $halign = 'CENTER' }
11597    }
11598
11599    # allow caption-alignment to be variable
11600    local($cap_align);
11601    if ($FIGURE_CAPTION_ALIGN =~ /^(TOP|BOTTOM|LEFT|RIGHT)/i) {
11602	$cap_align = join('', ' ALIGN="', $&, $','"')};
11603
11604    local($cap_env, $captions,$has_minipage) = ('figure','');
11605    if ((/\\begin\s*($O\d+$C)\s*(makeimage|minipage)\s*\1|\\docode/)||
11606	(/\\includegraphics/&&(!/$htmlborder_rx|$htmlborder_pr_rx|\\htmlimage/))){
11607	$has_minipage = ($2 =~ /minipage/sg );
11608	$_ = &translate_environments($_);
11609	if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11610	elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11611	do { local($contents) = $_;
11612	    &extract_captions($cap_env); $_ = $contents;
11613	} if (/\\caption/);
11614	$_ = &translate_commands($_);
11615	while ($_ =~ s/(^\s*<BR>\s*|\s*<BR>\s*$)//sg){}; # remove unneeded breaks
11616    } else {
11617	do { local($contents) = $_;
11618	    # MRO: no effect: &extract_captions($cap_env, *cap_width); $_ = $contents;
11619	    &extract_captions($cap_env); $_ = $contents;
11620	} if (/\\caption/);
11621	# Generate picture of the whole environment
11622	if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11623	elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11624	$_ = &process_undefined_environment($env, $id, $_);
11625	$_ = &post_latex_do_env_figure($_);
11626	$_ =~ s/\s*<BR>\s*$//g;
11627    }
11628
11629    if ($captions) {
11630        # MRO: replaced $* with /m
11631        $captions =~ s/^\n//m;
11632        $captions =~ s/\n$//m;
11633    }
11634    s/$caption_mark//g;
11635
11636    local($close_tags) = &close_all_tags;
11637    $_ .= $close_tags;
11638
11639    # place all the pieces inside a TABLE, if available
11640    if ($HTML_VERSION > 2.1) {
11641	if ($captions) {
11642	    local($pxs,$len) = &convert_length($cap_width,$MATH_SCALE_FACTOR)
11643		if $cap_width;
11644	    local($table) = "<TABLE$env_id"; # WIDTH="65%"';
11645	    $table .= " WIDTH=\"$pxs\"" if ($pxs);
11646	    if ($border) { $table .= " BORDER=\"$border\"" } # no checking !!
11647	    $table .= ">";
11648	    s/^\s*|\s*$//g;
11649	    join (''
11650		    , $above_display_space
11651		    , "\n<DIV", ($halign ? " ALIGN=\"$halign\"" :'')
11652		    , '>', $anchors , $cap_anchors
11653		    , "\n$table\n<CAPTION", $cap_align, '>'
11654		    , $captions , "</CAPTION>\n<TR><TD>"
11655		    , ($cap_width ? '</TD><TD>' : '')
11656		    , $_ , '</TD>'
11657		    , ($cap_width ? '<TD></TD>' : '')
11658		    , "</TR>\n</TABLE>\n</DIV>\n"
11659		    , $below_display_space
11660	    )
11661	} elsif ($halign) {
11662	    if ($border||($attributes)||$env_id) {
11663		&make_table( $border, $attribs, $anchors, '', $halign, $_ );
11664	    } else {
11665		join (''
11666			, $above_display_space
11667			, "\n<DIV ALIGN=\"$halign\">\n"
11668			, ($anchors ? "\n<P>$anchors</P>" : '')
11669			, $_
11670			, "\n</DIV>"
11671			, $below_display_space
11672		)
11673	    }
11674	} else {
11675	    if ($border||($attributes)||$env_id) {
11676		join (''
11677			, $above_display_space
11678			, "\n<DIV", ($halign ? " ALIGN=\"$halign\"":'')
11679			, '>'
11680			, &make_table( $border, $attribs, $anchors, '', $halign, $_ )
11681			, "\n</DIV><BR"
11682			, (($HTML_VERSION > 3.1)? " CLEAR=\"ALL\"" :'')
11683			, '>'
11684			, $below_display_space
11685		);
11686	    } else {
11687		join (''
11688			, $above_display_space
11689			, "\n<DIV", ($halign ? " ALIGN=\"$halign\"":'')
11690			, ">$anchors\n" , $_ , "\n</DIV><BR"
11691			, (($HTML_VERSION > 3.1)? " CLEAR=\"ALL\"" :'')
11692			, '>'
11693			, $below_display_space
11694		);
11695	    }
11696	}
11697    } else {
11698	# MRO: replaced $* with /m
11699        s/^\n//m;
11700        s/\n$//m;
11701	if ($captions) {
11702	    join('', "\n<BR>\n", (($anchors) ? "$anchors" : '')
11703		, "$cap_anchors\n$captions\n<BR>"
11704		, "\n<P", ($halign ? " ALIGN=\"$halign\"":'')
11705		, '>', $_ , "\n</P>");
11706	} elsif ($halign) {
11707	    join ('', "<BR>\n$anchors", $_ , "\n<BR>" )
11708	} else {
11709	    join('', "<BR>\n<P", ($halign ? " ALIGN=\"$halign\"":'')
11710		, ">$anchors\n" , $_ , "\n</P><BR>");
11711	}
11712    }
11713}
11714
11715sub do_env_figurestar { &do_env_figure(@_) }
11716
11717sub do_env_table {
11718    local($_) = @_;
11719    local($halign, $anchors) = ('','');
11720    local ( $border, $attribs );
11721    &get_next_optional_argument;
11722
11723    # Try to establish the alignment
11724    if (/^(\[[^\]]*])?\s*\\begin\s*<<\d*>>(\w*)<<\d*>>|\\(\w*)line/) {
11725	$halign = $2.$3;
11726	if ($halign =~ /right/i)  { $halign = 'RIGHT' }
11727	elsif ($halign =~ /left/i) { $halign = 'LEFT' }
11728	elsif ($halign =~ /center/i) { $halign = 'CENTER' }
11729	else { $halign = '' }
11730    }
11731
11732    local($cap_env, $captions) = ('table','');
11733
11734    # allow caption-alignment to be variable
11735    local($cap_align);
11736    if ($TABLE_CAPTION_ALIGN =~ /^(TOP|BOTTOM|LEFT|RIGHT)/i) {
11737	$cap_align = join('', ' ALIGN="', $&, $','"')};
11738
11739    if ((/\\(begin|end)\s*($O\d+$C)\s*makeimage\s*\2/)||
11740	    ($HTML_VERSION > 2.0 && (
11741	        /\\begin\s*($O\d+$C)\s*((super)?tabular|longtable)\s*\1/))) {
11742	$_ = &translate_environments($_);
11743	($_,$anchors) = &extract_labels($_); # extract labels
11744	do { local($contents) = $_;
11745	    &extract_captions($cap_env); $_ = $contents;
11746	} if (/\\caption/);
11747	if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11748	elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11749	$_ = &translate_commands($_);
11750	while ($_ =~ s/(^\s*<BR>\s*|\s*<BR>\s*$)//g){};
11751    } else {
11752	# Make an image of the whole environment.
11753	($_,$anchors) = &extract_labels($_); # extract labels
11754	do { local($contents) = $_;
11755	    &extract_captions($cap_env); $_ = $contents;
11756	} if (/\\caption/);
11757	if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11758	elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11759	$_ = &process_undefined_environment($env, $id, $_);
11760	$_ = &post_latex_do_env_table($_);
11761	$_ =~ s/\s*<BR>\s*$//g;
11762    }
11763
11764    if ($captions) {
11765        # MRO: replaced $* with /m
11766        $captions =~ s/^\n//m;
11767        $captions =~ s/\n$//m;
11768    }
11769    s/$caption_mark//g;
11770
11771    local($close_tags) = &close_all_tags;
11772    $_ .= $close_tags;
11773
11774    #  when $captions remain place all the pieces inside a TABLE, if available
11775    if ($HTML_VERSION > 2.1) {
11776	if ($captions) {
11777	    $halign = 'CENTER' unless $halign;
11778	    local($table) = '<TABLE';
11779	    if ($border) { $table .= " BORDER=\"$border\"" } # no checking !!
11780	    $table .= ">";
11781	    join ('', "<BR><P></P>\n<DIV$env_id ALIGN=\"$halign\">"
11782		, "$anchors$cap_anchors\n$table\n<CAPTION", $cap_align, '>'
11783		, $captions , "</CAPTION>\n<TR><TD>"
11784		, $_ , "</TD></TR>\n</TABLE>\n</DIV><P></P><BR>" )
11785	} elsif ($halign) {
11786	    if ($halign) {
11787		# MRO: replaced $* with /m
11788		s/^\s*(<(P|DIV)$env_id ALIGN=\"\w+[^>]+>)/$1$anchors/m
11789                    if ($anchors);
11790		join('', "<BR>", $_, "\n<BR>" )
11791	    } else {
11792		join ('', "<BR>\n$anchors", $_ , "\n<BR>" )
11793	    }
11794        } else {
11795            join ('', "<BR><P></P>\n<DIV$env_id ALIGN=\"CENTER\">$anchors\n", $_ , "\n</DIV><BR>" )
11796        }
11797    } else {
11798        # MRO: replaced $* with /m
11799        s/^\n//m;
11800        s/\n$//m;
11801        if ($captions) {
11802            join('', "<BR>\n", (($anchors) ? "$anchors" : ''), "$cap_anchors\n$captions\n<BR>"
11803                , "\n<P ALIGN=\"$halign\">", $_, "\n</P><BR>");
11804        } elsif ($halign) {
11805            join ('', "<BR><P></P>\n$anchors", $_ , "\n<P></P>" )
11806        } else {
11807            join('', "<BR>\n<P ALIGN=\"CENTER\">$anchors\n", $_, "\n</P><BR>");
11808        }
11809    }
11810}
11811
11812sub do_env_tablestar { &do_env_table(@_) }
11813
11814# RRM:  A makeimage environment generates a picture of its entire contents,
11815#  UNLESS it is empty.
11816#
11817sub do_env_makeimage {
11818    local($_) = @_;
11819    local($attribs, $border);
11820    s/^\s*//;
11821    if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11822    elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11823    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") }
11824    if (/^(\s\%?\n)+$/s) { return() }
11825    $_ = &process_undefined_environment($env, $id, $_);
11826    if (($border||($attributes))&&($HTML_VERSION > 2.1 ))
11827	{ $_ = &make_table( $border, $attribs, '', '', '', $_ ) }
11828    $_ . ((!$_=~/^\s*$/)? "\n<BR>\n" :'');
11829				      }
11830
11831sub do_env_abstract { &make_abstract($_[0]) }
11832
11833sub do_env_minipage {
11834    local($_) = @_;
11835    &get_next_optional_argument;
11836    local($width);
11837    $width = &missing_braces unless (
11838    	(s/$next_pair_pr_rx/$width=$2;''/e)
11839    	||(s/$next_pair_rx/$width=$2;''/e));
11840    local($pxs,$len) = &convert_length($width,$MATH_SCALE_FACTOR) if $width;
11841    $width = " WIDTH=\"$pxs\"";
11842
11843    local ( %mpfootnotes, $mpfootnotes ) unless ($MINIPAGE);
11844    local ( $border, $attribs, $footfile);
11845    $global{'mpfootnote'} = 0 unless ($MINIPAGE);
11846    $MINIPAGE++;
11847    print "\n *** doing minipage *** " if ($VERBOSITY > 1);
11848    local($open_tags_R) = [ @$open_tags_R ];
11849    local($close_tags,$reopens) = &close_all_tags();
11850    local(@save_open_tags) = @$open_tags_R;
11851
11852    local($minipage_caption) if $cap_env;
11853    if ($cap_env &&($HTML_VERSION>2.1)) {
11854	do {
11855	    local($captions);
11856	    local($contents) = $_;
11857	    &extract_captions($cap_env) if ($_ =~ /\\caption/m);
11858	    $minipage_caption = $captions;
11859	    $_ = $contents;
11860	    undef $contents; undef $captions;
11861	};
11862    }
11863
11864    if (s/^\s*$htmlborder_rx//so) {
11865	$attribs = $2; $border = (($4)? "$4" : 1)
11866    } elsif (s/^\s*$htmlborder_pr_rx//so) {
11867	$attribs = $2; $border = (($4)? "$4" : 1)
11868    }
11869    if (/^\s*\\/) {
11870	local($tmp) = ++$global{'max_id'};
11871	$_ = $O.$tmp.$C.$_.$O.$tmp.$C
11872    }
11873    $_ = &translate_environments($_);
11874    if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11875    elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
11876    $_ = &translate_commands($_);
11877    $MINIPAGE--; $MINIPAGE='' if ($MINIPAGE==0);
11878
11879    $_ .= &balance_tags();
11880    $attribs .= $width unless ($attribs =~ /WIDTH/i);
11881#    if (($border||$attribs)&&$MINIPAGE&&($HTML_VERSION>2.1)) {
11882    if (($border||$attribs||$env_id)&&$MINIPAGE&&($HTML_VERSION>2.1)) {
11883	$_ = &make_table( $border, $attribs, '', '', '', $_ );
11884    } elsif ($MINIPAGE) {
11885	$_ = join ('', '<BR><HR>', $_ , '<BR><HR><BR>' );
11886    } elsif (($border||($attribs)||$minipage_caption)&&($HTML_VERSION > 2.1 )) {
11887	$mpfootnotes = '<DL>'.$mpfootnotes.'</DL>' if $mpfootnotes;
11888	$_ = &make_table( $border, $attribs, '', $mpfootnotes, '', $_ );
11889	$_ = join('','<BR><HR'
11890		, (($HTML_VERSION > 3.0)? ' WIDTH="50\%" ALIGN="CENTER"' : '')
11891		, '>', $_ , '<BR><HR'
11892		, (($HTML_VERSION > 3.0)? ' WIDTH="50\%" ALIGN="CENTER"' : '')
11893		, '><BR>') unless ($border||$attribs||$mpfootnotes);
11894    } else {
11895	$global{'mpfootnote'} = 0;
11896	if ($mpfootnotes) {
11897	    $mpfootnotes = '<DD>'.$mpfootnotes unless ($mpfootnotes =~ /^\s*<D(T|D)>/);
11898	    $_ = join('','<BR><HR>', $_ , '<BR><HR'
11899		, (($HTML_VERSION > 3.0)? ' WIDTH="200" ALIGN="LEFT"' : '')
11900		, '><DL>', $mpfootnotes , '</DL><HR><BR'
11901		, (($HTML_VERSION > 3.0)? ' CLEAR="all"' : '')
11902		, '>' );
11903	} else {
11904	    $_ = join ('', '<BR><HR><P></P>', $_ , '<BR><HR><BR>' );
11905	}
11906    }
11907    join('', $close_tags, $_, $reopens);
11908}
11909
11910if (($HTML_VERSION > 2.1)&&($HTML_VERSION < 4.0)) {
11911    $TABLE_attribs = ",ALIGN,";
11912    $TABLE__ALIGN = ",left,right,center,";
11913    $TABLE_attribs_rx_list = ",CELLPADDING,BORDER,WIDTH,CELLSPACING,";
11914    $TABLE__WIDTH_rx = "\^\\d+%?";
11915    $TABLE__BORDER_rx = $TABLE__CELLSPACING_rx = $TABLE__CELLPADDING_rx = "\^\\d+";
11916}
11917
11918sub make_table {
11919    local($border, $attribs, $anchors, $extra_cell, $halign, $_) = @_;
11920    local($table,$caption,$div,$end,$Tattribs);
11921    $caption = join('',"<CAPTION$cap_align>"
11922	, $minipage_caption
11923	,'</CAPTION>') if ($minipage_caption);
11924    $end = "</TD></TR>\n</TABLE>";
11925    $table = join('', "<TABLE$env_id"
11926	, ((($caption)&&!($attribs =~/WIDTH/i)) ? " WIDTH=\"100\%\"" : '')
11927	, ((($border)&&!($attribs =~/BORDER/i)) ? " BORDER=\"$border\"" : '')
11928	);
11929    if ($attribs) {
11930	if (!($attribs =~ /=/)) {
11931	    $Tattribs = &parse_valuesonly($attribs,"TABLE");
11932	} else {
11933	    $Tattribs = &parse_keyvalues($attribs,"TABLE");
11934	}
11935	$table .= " $Tattribs" if ($Tattribs);
11936    }
11937    print STDOUT "\nTABLE: $table>" if ($VERBOSITY >2 );
11938    $table .= ">".$caption."\n<TR><TD>";
11939    if ($extra_cell) {
11940	local($sep) = "</TD></TR>\n<TR ALIGN=\"LEFT\">\n<TD>";
11941	join ('', $div, $anchors, $table, $_ , $sep, $extra_cell, $end );
11942    } else {
11943	join ('', $div, $anchors, $table, $_ , $end );
11944    }
11945}
11946
11947sub do_cmd_etalchar {
11948    local($_) = @_;
11949    my $etalchar;
11950    $etalchar = &missing_braces unless (
11951	(s/$next_pair_pr_rx/$etalchar = $2;''/eo)
11952	||(s/$next_pair_rx/$etalchar = $2;''/eo));
11953    $etalchar = &translate_commands($etalchar) if ($etalchar =~ /\\/);
11954    if ($HTML_VERSION < 3.0) {
11955	$etalchar = &process_in_latex("\$^\{$etalchar\}\$");
11956    } else {
11957	$etalchar = '<SUP>'.$etalchar.'</SUP>';
11958    }
11959    $etalchar . $_
11960}
11961
11962sub do_env_thebibliography {
11963    # Sets $citefile and $citations defined in translate
11964    local($_) = @_;
11965    $bibitem_counter = 0;
11966    $citefile = $CURRENT_FILE;
11967    $citefiles{$bbl_nr} = $citefile;
11968    local($dummy,$title);
11969    $dummy = &missing_braces unless (
11970	(s/$next_pair_pr_rx/$dummy=$2;''/e)
11971	||(s/$next_pair_rx/$dummy=$2;''/e));
11972    # MRO: replaced $* with /m
11973    s/^\s*$//gm; # Remove empty lines (otherwise will have paragraphs!)
11974    s/^\s*//m;
11975
11976    # Replace non-breaking spaces, particularly in author names.
11977#    s/([^\\])~/$1 /g; # Replace non-breaking spaces.
11978
11979    $_ = &translate_environments($_);
11980    $_ = &translate_commands($_);
11981
11982    # RRM: collect all anchors from initial \label and \index commands
11983    local($anchors) = &extract_anchors('',1);
11984    $_ = '<DD>'.$_ unless ($_ =~ /^\s*<D(T|D)>/);
11985    $citations = join('',"<DL COMPACT>", $_, "</DL>");
11986    $citations{$bbl_nr} = $citations;
11987    local($br_id);
11988    if ((defined &do_cmd_bibname)||$new_command{'bibname'}) {
11989	$br_id=++$global{'max_id'};
11990	$title = &translate_environments("$O$br_id$C\\bibname$O$br_id$C");
11991    } else { $title = $bib_title }
11992    if (! $title ) {
11993	if ((defined &do_cmd_refname)||$new_command{'refname'}) {
11994	    $br_id=++$global{'max_id'};
11995	    $title = &translate_environments("$O$br_id$C\\refname$O$br_id$C");
11996	} else { $title = $ref_name }
11997    }
11998    local($closures,$reopens) = &preserve_open_tags();
11999    $toc_sec_title = $title ;
12000    local $bib_head = $section_headings{'bibliography'};
12001    $_ = join('', $closures
12002	    , &make_section_heading($title, $bib_head, $anchors)
12003	    , "$bbl_mark#$bbl_nr#" , $reopens );
12004    $bbl_nr++ if $bbl_cnt > 1;
12005    $_ =~ s/;SPMnbsp;/ /g;  # replace non-breaking spaces with real ones
12006    $_;
12007}
12008# IGNORE - We construct our own index
12009sub do_env_theindex { "" }
12010
12011# This is defined in html.sty
12012sub do_env_comment { "" }
12013
12014
12015sub do_env_equation{
12016    local($_)=@_;
12017    local($attribs, $border, $no_num);
12018    if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
12019    elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
12020    if (/\\nonumber/) {
12021	$no_num = 1;
12022	$_ = &process_undefined_environment($env,$id,$_);
12023    } else {
12024	$latex_body .= join('', "\n\\setcounter{equation}{"
12025			, $global{'eqn_number'}, "}\n");
12026
12027	#include equation-number into the key, with HTML 2.0
12028#	$_ = join("\n", "%EQNO:".$global{'eqn_number'}, $_)
12029	$_ .= "%EQNO:".$global{'eqn_number'}."\n" if ($HTML_VERSION < 2.2);
12030
12031	$_ = &process_undefined_environment($env,$id,$_);
12032	$global{'eqn_number'}++;
12033	local($save) = $_;
12034	$_ = join('', $save, &post_latex_do_env_equation($eqno_prefix));
12035    }
12036    if (($border||($attribs))&&($HTML_VERSION > 2.1 )) {
12037	join('',"<BR>\n<DIV$env_id ALIGN=\"CENTER\">\n"
12038	    , &make_table( $border, $attribs, '', '', '', $_ )
12039	    , "\n<BR CLEAR=\"ALL\">");
12040    } elsif ($HTML_VERSION < 2.2 ) {
12041	join('', "\n<P>", $_ , "\n<BR></P>" )
12042    } elsif ($HTML_VERSION > 2.1 ) {
12043	join('', "\n<P ALIGN="
12044	    , ((!$no_num &&($EQN_TAGS =~ /L/))?
12045		'"LEFT"':($no_num ?'"CENTER"':'"RIGHT"'))
12046	    , '>', $_ , "\n<BR></P>" )
12047    } else { $_ }
12048}
12049
12050sub do_env_eqnarray{
12051    local($_)=@_;
12052    local($attribs, $border, $no_num);
12053    if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
12054    elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
12055    local($contents) = $_;
12056#    $_ = join("\n", "%EQNO:".$global{'eqn_number'}, $_)
12057#	if ($HTML_VERSION < 3.2);  #include equation-number into the key.
12058    $_ .= "%EQNO:".$global{'eqn_number'}."\n" if ($HTML_VERSION < 2.2);
12059    $_ = &process_undefined_environment($env,$id,$_);
12060    $_ .= &post_latex_do_env_eqnarray($eqno_prefix,$contents);
12061    if (($border||($attribs))&&($HTML_VERSION > 2.1 )) {
12062	join('',"<BR>\n<DIV ALIGN=\"CENTER\">\n"
12063            , &make_table( $border, $attribs, '', '', '', $_ )
12064	    , "\n<BR CLEAR=\"ALL\">");
12065    } elsif ($HTML_VERSION < 2.2 ) {
12066	join('', "\n<P>", $_ , "\n<BR></P>" )
12067    } elsif ($HTML_VERSION > 3.1 ) {
12068	join('',"<BR>\n<DIV ALIGN=\"CENTER\">\n", $_
12069	     , "\n</DIV><BR CLEAR=\"ALL\">" );
12070    } else {
12071	join('', "\n<P ALIGN="
12072	     , (($EQN_TAGS =~ /L/)? '"LEFT"' : '"RIGHT"')
12073	     , '>' , $_ , "\n<BR></P>" )
12074    }
12075}
12076
12077#RRM: these are needed with later versions, when {eqnarray}
12078#  environments are split into <TABLE> cells.
12079
12080sub protect_array_envs {
12081    local($_) = @_;
12082    local($cnt, $arraybit, $thisbit, $which) = (0,'','','');
12083    # MRO: replaced $* with /m
12084    while (/\\(begin|end)\s*(<(<|#)\d+(#|>)>)($sub_array_env_rx)(\*|star)?\2/m ) {
12085        $thisbit = $` . $&; $_ = $'; $which = $1;
12086        do {
12087            # mark rows/columns in nested arrays
12088            $thisbit =~ s/;SPMamp;/$array_col_mark/g;
12089            $thisbit =~ s/\\\\/$array_row_mark/g;
12090            $thisbit =~ s/\\text/$array_text_mark/g;
12091            $thisbit =~ s/\\mbox/$array_mbox_mark/g;
12092        } if ($cnt > 0);
12093        $arraybit .= $thisbit;
12094        if ($which =~ /begin/) {$cnt++} else {$cnt--};
12095    }
12096    $_ = $arraybit . $_;
12097
12098    local($presub,$thisstack) = '';
12099    for (;;) {
12100      # find \\s needing protection within \substack commands
12101      # a while-loop is simpler syntax, but uses longer strings
12102      if ( /(\\substack\s*(<(<|#)\d+(#|>)>)(.|\n)*)\\\\((.|\n)*\2)/m ) {
12103        $presub .= $`; $thisstack =$1.${array_row_mark}.$6; $_ = $';
12104        # convert all \\s in the \substack
12105        $thisstack =~ s/\\\\/${array_row_mark}/og;
12106        $presub .= $thisstack;
12107        } else { last }
12108    }
12109    $_ = $presub . $_ if ($presub);
12110    $_;
12111}
12112
12113sub revert_array_envs {
12114    local($array_contents) = @_;
12115    $array_contents =~ s/$array_col_mark/$html_specials{'&'}/go;
12116    $array_contents =~ s/$array_row_mark/\\\\/go;
12117    $array_contents =~ s/$array_text_mark/\\text/go;
12118    $array_contents =~ s/$array_mbox_mark/\\mbox/go;
12119    $array_contents;
12120}
12121
12122
12123
12124sub do_env_tabbing {
12125    local($_) = @_;
12126    local($attribs, $border);
12127    if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
12128    elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
12129    $_ = &tabbing_helper($_);
12130    if (/$image_mark/) {
12131	local($tab_warning) =
12132	   "*** Images are not strictly valid within HTML <pre> tags\n"
12133	   . "Please change your use of {tabbing} to a {tabular} environment.\n\n";
12134	   &write_warnings("\n".$tab_warning);
12135	   print "\n\n **** invalid tabbing environment ***\n";
12136	   print $tab_warning;
12137    }
12138    if (($border||($attribs))&&($HTML_VERSION > 2.1 )) {
12139	join('',"<BR>\n<DIV$env_id ALIGN=\"CENTER\">\n"
12140            , &make_table( $border, $attribs, '', '', '', $_ )
12141	    , "\n</DIV><BR CLEAR=\"ALL\">");
12142    } else { $_ }
12143}
12144
12145sub tabbing_helper {
12146    local($_) = @_;
12147    s/\\=\s*//go;  # cannot alter the tab-stops
12148    s/\t/ /g;      # convert any tabs to spaces
12149    # MRO: replaced $* with /m
12150    s/(^|\n)[^\n]*\\kill *\n/\n/gm;
12151    s/( )? *\n/$1/gm; # retain at most 1 space for a \n
12152    # replace \\ by \n ... , ignoring any trailing space
12153#    s/\\\\ */\n/gm;
12154    # ...but make sure successive \\ do not generate a <P> tag
12155#    s/\n( *)?\n/\n&nbsp;\n/gm;
12156    s/\\\&gt;//go;
12157    s/(^| *([^\\]))\\[>]/$2\t\t/go;
12158    s/([^\\])\\>/$1\t\t/go;
12159    s/\n$//; s/^\n//;           # strip off leading/trailing \n
12160    local($inside_tabbing) = 1;
12161    $_ = &translate_commands(&translate_environments($_));
12162    "<PRE><TT>\n$_\n</TT></PRE>";
12163				      }
12164
12165################# Post Processing Latex Generated Images ################
12166
12167# A subroutine of the form post_latex_do_env_<ENV> can be used to
12168# format images that have come back from latex
12169
12170# Do nothing (avoid the paragraph breaks)
12171sub post_latex_do_env_figure { $_[0] }
12172sub post_latex_do_env_figurestar { &post_latex_do_env_figure(@_) }
12173
12174sub post_latex_do_env_table { $_[0] }
12175sub post_latex_do_env_tablestar { &post_latex_do_env_table(@_) }
12176
12177sub post_latex_do_env_equation {
12178    local($prefix) = @_;
12179    $global{'eqn_number'}+=1;
12180    # include equation number at the side of the image -- HTML 3.2
12181    if ($HTML_VERSION >= 3.2){
12182	join('',"<P ALIGN=\"" , (($EQN_TAGS eq "L") ? "left" : "right")
12183		, "\">$EQNO_START" , $prefix
12184		, &translate_commands('\theequation')
12185		, "$EQNO_END</P>\n<BR CLEAR=\"all\">" );
12186    # </P> creates unwanted space in some browsers, but others need it.
12187    } else { "" }
12188}
12189
12190sub do_cmd_theequation {
12191    if ($USING_STYLES) {
12192	$txt_style{'eqn-number'} = " " unless ($txt_style{'eqn-number'});
12193	join('', "<SPAN CLASS=\"eqn-number\">"
12194		,&get_counter_value('eqn_number'),"</SPAN>", $_[0]);
12195    } else { join('',&get_counter_value('eqn_number'), $_[0]); }
12196}
12197
12198sub post_latex_do_env_eqnarray {
12199    local($prefix,$body) = @_;
12200    local($num_string,$line,@lines) = '';
12201    local($side) = (($EQN_TAGS eq "L") ? "\"left\"" : "\"right\"" );
12202    # MRO: replaced $* with /m
12203    @lines = split(/\\\\\\\\/m, $body);
12204    $line = pop(@lines);
12205    if (!($line=~/^\s*$/)&&!($line =~/\\nonumber/)) {
12206	$global{'eqn_number'}++;
12207	$num_string .= join('', "<BR><BR>\n" , $EQNO_START , $prefix
12208	    , &translate_commands('\theequation')
12209	    , $EQNO_END);
12210    }
12211    foreach $line (@lines) {
12212	next if ($line=~/^\s*$/);
12213	$num_string .= "\n<BR>". (($MATH_SCALE_FACTOR > 1.3)? '<BR>' : '')
12214	                . "<BR CLEAR=$side>";
12215	if (!($line =~/\\(nonumber|(no)?tag)/)) {
12216	    $global{'eqn_number'}+=1;
12217	    $num_string .= join('', $EQNO_START , $prefix
12218		, &translate_commands('\theequation')
12219		, $EQNO_END);
12220	 }
12221    }
12222    # include equation numbers at the side of the image -- HTML 3.2
12223    if ($HTML_VERSION >= 3.2){
12224	"<P ALIGN=\"" . (($EQN_TAGS eq "L") ? "left" : "right")
12225	    . "\">" . (($DISP_SCALE_FACTOR >= 1.2 ) ? '<BIG>' : '')
12226	    . ${num_string}
12227	    . (($DISP_SCALE_FACTOR >= 1.2 ) ? '</BIG>' : '')
12228	    . "</P>\n<BR CLEAR=\"all\">"
12229    # </P> creates unwanted space in some browsers, but others need it.
12230    } else { "" };
12231}
12232
12233sub post_latex_do_env_eqnarraystar {
12234    local($_) = @_;
12235    if (($HTML_VERSION >= 3.2)&&(!$NO_SIMPLE_MATH)){
12236	join('', "<BR>\n<DIV ALIGN=\"CENTER\">\n"
12237	    , $_ , "\n<BR CLEAR=\"ALL\">\n<P>");
12238    } elsif (($HTML_VERSION >= 2.2)&&(!$NO_SIMPLE_MATH)) {
12239	join('', "\n<BR><P ALIGN=\"CENTER\">\n", $_ , "\n<BR></P>\n<P>");
12240    } else {
12241	join('', "\n<BR><P>\n", $_ , "\n<BR></P>\n<P>");
12242    }
12243}
12244
12245############################ Grouping ###################################
12246
12247sub do_cmd_begingroup { $latex_body .= "\n\\begingroup\n"; $_[0] }
12248sub do_cmd_endgroup { $latex_body .= "\\endgroup\n\n"; $_[0] }
12249sub do_cmd_bgroup { $latex_body .= "\n\\bgroup\n"; $_[0] }
12250sub do_cmd_egroup { $latex_body .= "\\egroup\n\n"; $_[0] }
12251
12252sub do_env_tex2html_begingroup {
12253    local($_) = @_;
12254    $latex_body .= "\\begingroup ";
12255    $_ = &translate_environments($_);
12256    $_ = &translate_commands($_);
12257    $latex_body .= "\\endgroup\n";
12258    $_;
12259}
12260
12261sub do_env_tex2html_bgroup {
12262    local($_) = @_;
12263    $latex_body .= "\\bgroup ";
12264    $_ = &translate_environments($_);
12265    $_ = &translate_commands($_);
12266    $latex_body .= "\\egroup\n";
12267    $_;
12268				      }
12269
12270
12271############################ Commands ###################################
12272
12273# Capitalizes what follows the \sc declaration
12274# *** POTENTIAL ERROR ****
12275# (This is NOT the correct meaning of \sc in the cases when it
12276# is followed by another declaration (e.g. \em).
12277# The scope of \sc should be limited to the next occurence of a
12278# declaration.
12279#sub do_cmd_sc {
12280#    local($_) = @_;
12281#    local(@words) = split(" ");
12282# Capitalize the words which are not commands and do not contain any markers
12283#   grep (do {tr/a-z/A-Z/ unless /(^\\)|(tex2html)/}, @words);
12284#    grep (do {s/([a-z]+)/<small>\U$1\E<\/small>/g unless /(^\\)|(tex2html)/}, @words);
12285#    join(" ", @words);
12286#}
12287sub do_cmd_sc { &process_smallcaps(@_) }
12288sub do_cmd_scshape { &do_cmd_sc(@_) }
12289
12290# This is supposed to put the font back into roman.
12291# Since there is no HTML equivalent for reverting
12292# to roman we keep track of the open font tags in
12293# the current context and close them.
12294# *** POTENTIAL ERROR ****#
12295# This will produce incorrect results in the exceptional
12296# case where \rm is followed by another context
12297# containing font tags of the type we are trying to close
12298# e.g. {a \bf b \rm c {\bf d} e} will produce
12299#       a <b> b </b> c   <b> d   e</b>
12300# i.e. it should move closing tags from the end
12301sub do_cmd_rm { # clean
12302    my ($str, $ot) = @_;
12303    $ot = $open_tags_R unless(defined $ot);
12304    return("<\#rm\#>".$str) if ($inside_tabular);
12305
12306    my ($size,$color,$tags);
12307    while (@$ot) {
12308	my $next = pop (@$ot);
12309	print STDOUT "\n</$next>" if $VERBOSITY > 2;
12310	if ($next =~ /$sizechange_rx/) {
12311	    $size = $next unless ($size);
12312	}
12313#	if ($next =~ /$colorchange_rx/) {
12314#	    $color = $next unless ($color);
12315#	}
12316	$declarations{$next} =~ m|</.*$|;
12317	$tags .= $& unless ($` =~ /^<>/);
12318    }
12319    if ($size) {
12320	$declarations{$size} =~ m|</.*$|;
12321	$tags .= $` unless ($` =~ /^<>/);
12322	push (@$ot,$size);
12323	print STDOUT "\n<$size>" if $VERBOSITY > 2;
12324    }
12325    $tags.$str;
12326}
12327
12328sub do_cmd_rmfamily{ &do_cmd_rm(@_) }
12329
12330sub do_cmd_textrm {
12331    local($_) = @_;
12332    local($text,$br_id)=('','0');
12333    $text = &missing_braces unless (
12334	(s/$next_pair_pr_rx/$text=$2;$br_id=$1;''/eo)
12335	||(s/$next_pair_rx/$text=$2;$br_id=$1;''/eo));
12336    join ('' ,
12337	  &translate_environments("$O$br_id$C\\rm $text$O$br_id$C")
12338	  , $_ );
12339}
12340
12341sub do_cmd_emph {
12342    local($_) = @_;
12343    local($ifstyle,$join_tags) = ('',join(',',@$open_tags_R));
12344    $join_tags =~ s/(^|,)(text)?(it|rm|normalfont)/$if_style=$3;''/eg;
12345    if ($if_style =~ /it/) {
12346	($ifstyle,$join_tags) = ('',join(',',@$open_tags_R));
12347	$join_tags =~ s/(^|,)(text)?(bf|rm|normalfont)/$if_style=$3;''/eg;
12348	if ($if_style =~ /bf/) { &do_cmd_textrm(@_) }
12349	else { &do_cmd_textbf(@_) }
12350    } else { &do_cmd_textit(@_) }
12351				      }
12352
12353#RRM: These cope with declared commands for which one cannot
12354#     simply open a HTML single tag.
12355#     The do_cmd_... gets found before the $declaration .
12356
12357sub do_cmd_upshape{&declared_env('upshape',$_[0],$tex2html_deferred)}
12358sub do_cmd_mdseries{&declared_env('mdseries',$_[0],$tex2html_deferred)}
12359sub do_cmd_normalfont{&declared_env('normalfont',$_[0],$tex2html_deferred)}
12360
12361
12362# This is supposed to put the font back into normalsize.
12363# Since there is no HTML equivalent for reverting
12364# to normalsize we keep track of the open size tags in
12365# the current context and close them.
12366sub do_cmd_normalsize { # clean
12367    my ($str, $ot) = @_;
12368    $ot = $open_tags_R unless(defined $ot);
12369
12370    my ($font,$fontwt,$closures,$reopens,@tags);
12371
12372    while (@$ot) {
12373	my $next = pop @$ot;
12374	$declarations{$next} =~ m|</.*$|;
12375	my ($pre,$post) = ($`,$&);
12376	if ($post =~ /$block_close_rx|$all_close_rx/ ) {
12377	    push (@$ot, $next);
12378	    last;
12379	}
12380	$closures .= $post unless ($pre =~ /^<>/);
12381	print STDOUT "\n</$next>" if $VERBOSITY > 2;
12382
12383	if ($next =~ /$fontchange_rx/) {
12384	    $font = $next unless ($font);
12385	} elsif ($next =~ /$fontweight_rx/) {
12386	    $fontwt = $next unless ($fontwt);
12387	} elsif ($next =~ /$sizechange_rx/) {
12388	    # discard it
12389	} else {
12390	    unshift (@tags, $next);
12391	    print STDOUT "\n<<$next>" if $VERBOSITY > 2;
12392	    $reopens .= $pre unless ($pre =~ /^<>/);
12393	}
12394    }
12395    push (@$ot, @tags);
12396    if ($font) {
12397	$declarations{$font} =~ m|</.*$|;
12398	$reopens .= $` unless ($` =~ /^<>/);
12399	push (@$ot,$font);
12400	print STDOUT "\n<$font>" if $VERBOSITY > 2;
12401    }
12402    if ($fontwt) {
12403	$declarations{$fontwt} =~ m|</.*$|;
12404	$reopens .= $` unless ($` =~ /^<>/);
12405	push (@$ot,$fontwt);
12406	print STDOUT "\n<$fontwt>" if $VERBOSITY > 2;
12407    }
12408    join('', $closures, $reopens, $str);
12409				      }
12410
12411
12412
12413#JCL(jcl-tcl)
12414# changed everything
12415#
12416sub do_cmd_title {
12417    local($_) = @_;
12418    &get_next_optional_argument;
12419    local($making_title,$next) = (1,'');
12420    $next = &missing_braces unless (
12421	(s/$next_pair_pr_rx/$next = $2;''/eo)
12422	||(s/$next_pair_rx/$next = $2;''/eo));
12423    $t_title = &translate_environments($next);
12424    $t_title = &translate_commands($t_title);
12425#    $toc_sec_title = &simplify(&translate_commands($next));
12426    $toc_sec_title = &purify(&translate_commands($next));
12427    $TITLE = (($toc_sec_title)? $toc_sec_title : $default_title)
12428	unless ($TITLE && !($TITLE =~ /^($default_title|\Q$FILE\E)$/));
12429#    $TITLE = &purify($TITLE);
12430
12431    #RRM: remove superscripts inserted due to \thanks
12432    $TITLE =~ s/<A[^>]*><SUP>\d+<\/SUP><\/A>/$1/g;
12433    $_;
12434}
12435
12436sub do_cmd_author {
12437    local($_) = @_;
12438    &get_next_optional_argument;
12439    my $next;
12440    $next = &missing_braces unless (
12441	(s/$next_pair_pr_rx/$next = $2;''/seo)
12442	||(s/$next_pair_rx/$next = $2;''/seo));
12443    local($after) = $_;
12444    if ($next =~ /\\and/) {
12445	my @author_list = split(/\s*\\and\s*/, $next);
12446	my $t_author, $t_affil, $t_address;
12447	foreach (@author_list) {
12448	    $t_author = &translate_environments($_);
12449	    $t_author =~ s/\s+/ /g;
12450	    $t_author = &simplify(&translate_commands($t_author));
12451	    ($t_author,$t_affil,$t_address) = split (/\s*<BR>s*/, $t_author);
12452	    push @authors, $t_author;
12453	    push @affils, $t_affil;
12454	    push @addresses, $t_address;
12455	}
12456    } else {
12457	$_ = &translate_environments($next);
12458	$next = &translate_commands($_);
12459	($t_author) = &simplify($next);
12460	($t_author,$t_affil,$t_address) = split (/\s*<BR>s*/, $t_author);
12461	push @authors, $t_author;
12462	push @affils, $t_affil if $t_affil;
12463	push @addresses, $t_address if $t_address;
12464    }
12465    $after;
12466}
12467
12468sub do_cmd_address {
12469    local($_) = @_;
12470    &get_next_optional_argument;
12471    local($next);
12472    $next = &missing_braces unless (
12473	(s/$next_pair_pr_rx/$next = $&;''/eo)
12474	||(s/$next_pair_rx/$next = $&;''/eo));
12475    ($t_address) = &simplify(&translate_commands($next));
12476    push @addresses, $t_address;
12477    $_;
12478				      }
12479
12480sub do_cmd_institute {
12481    local($_) = @_;
12482    &get_next_optional_argument;
12483    local($next);
12484    $next = &missing_braces unless (
12485	(s/$next_pair_pr_rx/$next = $&;''/eo)
12486	||(s/$next_pair_rx/$next = $&;''/eo));
12487    ($t_institute) = &simplify(&translate_commands($next));
12488    push @affils, $t_institute;
12489    $_;
12490}
12491
12492sub do_cmd_dedicatory {
12493    local($_) = @_;
12494    &get_next_optional_argument;
12495    local($next);
12496    $next = &missing_braces unless (
12497	(s/$next_pair_pr_rx/$next = $&;''/eo)
12498	||(s/$next_pair_rx/$next = $&;''/eo));
12499    ($t_affil) = &simplify(&translate_commands($next));
12500    push @affils, $t_affil;
12501    $_;
12502				      }
12503
12504sub do_cmd_email {
12505    local($_) = @_;
12506    local($next,$target)=('','notarget');
12507    $next = &missing_braces unless (
12508	(s/$next_pair_pr_rx/$next = $2;''/eo)
12509	||(s/$next_pair_rx/$next = $2;''/eo));
12510    local($mail) = &translate_commands($next);
12511    ($t_email) = &make_href("mailto:$mail","$mail");
12512    push @emails, $t_email;
12513    $_;
12514}
12515
12516sub do_cmd_authorURL {
12517    local($_) = @_;
12518    local($next);
12519    $next = &missing_braces unless (
12520	(s/$next_pair_pr_rx/$next = $2;''/eo)
12521	||(s/$next_pair_rx/$next = $2;''/eo));
12522    ($t_authorURL) =  &translate_commands($next);
12523    push @authorURLs, $t_authorURL;
12524    $_;
12525				      }
12526
12527sub do_cmd_date {
12528    local($_) = @_;
12529    local($next);
12530    $next = &missing_braces unless (
12531	(s/$next_pair_pr_rx/$next = $&;''/eo)
12532	||(s/$next_pair_rx/$next = $&;''/eo));
12533    ($t_date) = &translate_commands($next);
12534    $_;
12535}
12536
12537sub make_multipleauthors_title {
12538    local($alignc, $alignl) = (@_);
12539    local($t_author,$t_affil,$t_institute,$t_date,$t_address,$t_email,$t_authorURL)
12540	= ('','','','','','','');
12541    local ($t_title,$auth_cnt) = ('',0);
12542    if ($MULTIPLE_AUTHOR_TABLE) {
12543	$t_title = '<TABLE' .($USING_STYLES? ' CLASS="author_info_table"' : '')
12544		.' WIDTH="90%" ALIGN="CENTER" CELLSPACING=15>'
12545		."\n<TR VALIGN=\"top\">";
12546    }
12547    foreach $t_author (@authors) {
12548	$t_affil = shift @affils;
12549	$t_institute = ''; # shift @institutes;
12550	$t_address = shift @addresses;
12551	$t_email = shift @emails;
12552	$t_authorURL = shift @authorURLs;
12553	if ($MULTIPLE_AUTHOR_TABLE) {
12554	    if ($auth_cnt == $MAX_AUTHOR_COLS) {
12555		$t_title .= join("\n", '</TR><TR>', '');
12556		$auth_cnt -= $MAX_AUTHOR_COLS;
12557	    }
12558	    $t_title .= join("\n"
12559		, '<TD>'
12560		, &make_singleauthor_title($alignc, $alignl ,$t_author
12561		    , $t_affil,$t_institute,$t_date,$t_address,$t_email,$t_authorURL)
12562		, '</TD>' );
12563	    ++$auth_cnt;
12564	} else {
12565	    $t_title .= &make_singleauthor_title($alignc, $alignl ,$t_author
12566		, $t_affil,$t_institute,$t_date,$t_address,$t_email,$t_authorURL);
12567	}
12568    }
12569    if ($MULTIPLE_AUTHOR_TABLE) {
12570	$t_title .= "\n</TR></TABLE>\n";
12571    }
12572    $t_title;
12573				      }
12574
12575sub do_cmd_maketitle {
12576    local($_) = @_;
12577    local($the_title) = '';
12578    local($alignc, $alignl);
12579    if ($HTML_VERSION > 2.1) {
12580	$alignc = " ALIGN=\"CENTER\"";
12581	$alignl = " ALIGN=\"LEFT\"";
12582	$alignl = $alignc if ($MULTIPLE_AUTHOR_TABLE);
12583    }
12584    if ($t_title) {
12585	$the_title .= "<H1$alignc>$t_title</H1>";
12586    } else { &write_warnings("\nThis document has no title."); }
12587    if (($#authors >= 1)||$MULTIPLE_AUTHOR_TABLE) {
12588	$the_title .= &make_multipleauthors_title($alignc,$alignl);
12589	if ($t_date&&!($t_date=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12590	    $the_title .= "\n<P$alignc><STRONG>$t_date</STRONG></P>";}
12591    } else {
12592	$the_title .= &make_singleauthor_title($alignc,$alignl ,$t_author
12593	    , $t_affil,$t_institute,$t_date,$t_address,$t_email,$t_authorURL);
12594    }
12595    $the_title . $_ ;
12596				      }
12597
12598sub make_singleauthor_title {
12599    local($alignc, $alignl , $t_author
12600	, $t_affil,$t_institute,$t_date,$t_address,$t_email,$t_authorURL) = (@_);
12601    my $t_title = '';
12602    my ($s_author_info, $e_author_info) = ('<DIV','</DIV>');
12603    $s_author_info .= ($USING_STYLES ? ' CLASS="author_info"' : '').'>';
12604
12605    if ($t_author) {
12606	if ($t_authorURL) {
12607	    local($href) = &translate_commands($t_authorURL);
12608	    $href = &make_named_href('author'
12609			, $href, "<STRONG>${t_author}</STRONG>");
12610	    $t_title .= "\n<P$alignc>$href</P>";
12611	} else {
12612	    $t_title .= "\n<P$alignc><STRONG>$t_author</STRONG></P>";
12613	}
12614    } else { &write_warnings("\nThere is no author for this document."); }
12615
12616    if ($t_institute&&!($t_institute=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12617	$t_title .= "\n<P$alignc><SMALL>$t_institute</SMALL></P>";}
12618    if ($t_affil&&!($t_affil=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12619	$t_title .= "\n<P$alignc><I>$t_affil</I></P>";}
12620    if ($t_date&&!($t_date=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12621	$t_title .= "\n<P$alignc><STRONG>$t_date</STRONG></P>";}
12622    if ($t_address&&!($t_address=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12623	$t_title .= "\n<P$alignl><SMALL>$t_address</SMALL></P>";
12624    }  # else { $t_title .= "\n<P$alignl>"}
12625    if ($t_email&&!($t_email=~/^\s*(($O|$OP)\d+($C|$CP))\s*\1\s*$/)) {
12626	$t_title .= "\n<P$alignl><SMALL>$t_email</SMALL></P>";
12627    }  # else { $t_title .= "</P>" }
12628    join("\n", $s_author_info, $t_title, $e_author_info);
12629				      }
12630
12631sub do_cmd_abstract {
12632    local($_) = @_;
12633    local($abstract);
12634    $abstract = &missing_braces unless (
12635	(s/$next_pair_pr_rx/$abstract = $&;''/eo)
12636	||(s/$next_pair_rx/$abstract = $&;''/eo));
12637    join('', &make_abstract($abstract), $_);
12638}
12639
12640sub make_abstract {
12641    local($_) = @_;
12642    # HWS  Removed emphasis (hard to read)
12643    $_ = &translate_environments($_);
12644    $_ = &translate_commands($_);
12645    local($title);
12646    if ((defined &do_cmd_abstractname)||$new_command{'abstractname'}) {
12647	local($br_id)=++$global{'max_id'};
12648	$title = &translate_environments("$O$br_id$C\\abstractname$O$br_id$C");
12649    } else { $title = $abs_title }
12650    local($env_id) = " CLASS=\"ABSTRACT\"" if ($USING_STYLES);
12651    join('',"\n<H3>", $title, ":</H3>\n"
12652	, (($HTML_VERSION > 3)? "<DIV$env_id>" : "<P>"), $_
12653	, (($HTML_VERSION > 3)? "</DIV>" : "</P>"), "\n<P>");
12654				      }
12655
12656sub set_default_language {
12657    # MRO: local($lang,*_) = @_;
12658    my $lang = shift;
12659    push(@language_stack, $default_language);
12660    $default_language = $lang;
12661    $_[0] .= '\popHtmlLanguage';
12662}
12663
12664sub do_cmd_popHtmlLanguage {
12665    $default_language = pop(@language_stack);
12666    $_[0];
12667}
12668
12669sub do_cmd_today {
12670    local($lang);
12671    if ($PREAMBLE) {
12672	$lang = $TITLES_LANGUAGE || $default_language ;
12673    } else {
12674	$lang = $current_language || $default_language ;
12675    }
12676    local($today) = $lang . '_today';
12677    if (defined &$today) { join('', eval "&$today()", $_[0]) }
12678    else { join('', &default_today(), $_[0]) }
12679				      }
12680
12681sub default_today {
12682    #JKR: Make it more similar to LaTeX
12683    ## AYS: moved french-case to styles/french.perl
12684    my $today = &get_date();
12685
12686    $today =~ s|(\d+)/0?(\d+)/|$Month[$1] $2, |;
12687    join('',$today,$_[0]);
12688				      }
12689
12690sub do_cmd_textbackslash { join('','&#92;', $_[0]);}
12691sub do_cmd_textbar { join('','|', $_[0]);}
12692sub do_cmd_textless { join('',';SPMlt;', $_[0]);}
12693sub do_cmd_textgreater { join('',';SPMgt;', $_[0]);}
12694sub do_cmd_textasciicircum { join('','&#94;', $_[0]);}
12695sub do_cmd_textasciitilde { join('','&#126;', $_[0]);}
12696sub do_cmd_textquoteleft { join('','&#96;', $_[0]);}
12697sub do_cmd_textquoteright { join('','&#39;', $_[0]);}
12698
12699sub do_cmd_textcompwordmark { join('','', $_[0]);}
12700sub do_cmd_texttrademark { join('','<SUP><SMALL>TM</SMALL></SUP>', $_[0]);}
12701
12702sub do_cmd_textsubscript   { &make_text_supsubscript('SUB',$_[0]);}
12703sub do_cmd_textsuperscript { &make_text_supsubscript('SUP',$_[0]);}
12704
12705sub make_text_supsubscript {
12706    local ($supsub, $_) = (@_);
12707    my $arg = '';
12708    $arg = &missing_braces unless (
12709	(s/$next_pair_pr_rx/$arg = $&;''/eo)
12710	||(s/$next_pair_rx/$arg = $&;''/eo));
12711    $arg = &translate_commands($arg) if ($arg =~ m!\\!);
12712    join('', "<$supsub>", $arg, "</$supsub>", $_);
12713				      }
12714
12715sub do_cmd_textcircled {
12716    local ($_) = (@_);
12717    my $arg = '';
12718    $arg = &missing_braces unless (
12719	(s/$next_pair_pr_rx/$arg = $&;''/eo)
12720	||(s/$next_pair_rx/$arg = $&;''/eo));
12721    my $after = $_;
12722    join('', &process_undefined_environment("tex2html_nomath_inline"
12723	   , ++$global{'max_id'}
12724	   , "\\vbox{\\kern3pt\\textcircled{$arg}}" )
12725	, $after );
12726				      }
12727
12728# these can be overridded in charset (.pl) extension files:
12729sub do_cmd_textemdash { join('','---', $_[0]);}
12730sub do_cmd_textendash { join('','--', $_[0]);}
12731#sub do_cmd_exclamdown { join('','', $_[0]);}
12732#sub do_cmd_questiondown { join('','', $_[0]);}
12733sub do_cmd_textquotedblleft { join('',"``", $_[0]);}
12734sub do_cmd_textquotedblright { join('',"''", $_[0]);}
12735sub do_cmd_textbullet { join('','*', $_[0]);}
12736sub do_cmd_textvisiblespace { join('','_', $_[0]);}
12737
12738sub do_cmd_ldots {
12739    join('',(($math_mode&&$USE_ENTITY_NAMES) ? ";SPMldots;" : "..."),$_[0]);
12740}
12741
12742sub do_cmd_dots {
12743    join('',(($math_mode&&$USE_ENTITY_NAMES) ? ";SPMldots;" : "..."),$_[0]);
12744				      }
12745
12746sub do_cmd_hrule {
12747    local($_) = @_;
12748    &ignore_numeric_argument;
12749    #JKR: No need for <BR>
12750    local($pre,$post) = &minimize_open_tags('<HR>');
12751    join('',$pre,$_);
12752				      }
12753
12754#sub do_cmd_hrulefill {
12755#    "<HR ALIGN=\"right\">\n<BR CLEAR=\"right\">";
12756#}
12757
12758sub do_cmd_linebreak {
12759    local($num,$dum) = &get_next_optional_argument;
12760    if (($num)&&($num<4)) { return $_[0] }
12761    join('',"<BR>", $_[0]);
12762				      }
12763
12764sub do_cmd_pagebreak {
12765    local($_) = @_;
12766    local($num,$dum) = &get_next_optional_argument;
12767    if (($num)&&($num<4)) { return($_) }
12768    elsif (/^ *\n *\n/) {
12769	local($after) = $';
12770	local($pre,$post) = &minimize_open_tags("<BR>\n<P>");
12771	join('',$pre, $')
12772    } else { $_ }
12773				      }
12774
12775
12776sub do_cmd_newline { join('',"<BR>", $_[0]); }
12777# this allows for forced newlines in tables, etc.
12778sub do_cmd_endgraf { join('',"<BR>", $_[0]); }
12779
12780sub do_cmd_space { join(''," ",$_[0]); }
12781sub do_cmd_enspace { join('',"\&nbsp;",$_[0]); }
12782sub do_cmd_quad { join('',"\&nbsp;"x4,$_[0]); }
12783sub do_cmd_qquad { join('',"\&nbsp;"x8,$_[0]); }
12784
12785sub do_cmd_par {
12786    local ($_) = @_;
12787    my ($pre,$post) = &preserve_open_tags();
12788    my ($spar, $lcode) = ("\n<P", '');
12789    if (($USING_STYLES) &&(!($default_language eq $TITLES_LANGUAGE))) {
12790	$lcode = &get_current_language();
12791	$spar .= $lcode if $lcode;
12792    }
12793    join('', $pre, $spar, ">\n",$post,$_);
12794				      }
12795
12796sub do_cmd_medskip {
12797    local ($_) = @_;
12798    local($pre,$post) = &preserve_open_tags();
12799    join('',$pre,"\n<P><BR>\n",$post,$_);
12800				      }
12801
12802sub do_cmd_smallskip {
12803    local ($_) = @_;
12804    local($pre,$post) = &preserve_open_tags();
12805    join('',$pre,"\n<P></P>\n",$post,$_);
12806				      }
12807
12808sub do_cmd_bigskip {
12809    local ($_) = @_;
12810    local($pre,$post) = &preserve_open_tags();
12811    join('',$pre,"\n<P><P><BR>\n",$post,$_);
12812				      }
12813
12814# MEH: Where does the slash command come from?
12815# sub do_cmd_slash {
12816#    join('',"/",$_[0]);
12817#}
12818sub do_cmd_esc_slash { $_[0]; }
12819sub do_cmd_esc_hash { "\#". $_[0]; }
12820sub do_cmd_esc_dollar { "\$". $_[0]; }
12821sub do_cmd__at_ { $_[0]; }
12822sub do_cmd_lbrace { "\{". $_[0]; }
12823sub do_cmd_rbrace { "\}". $_[0]; }
12824sub do_cmd_Vert { "||". $_[0]; }
12825sub do_cmd_backslash { "\\". $_[0]; }
12826
12827#RRM: for subscripts outside math-mode
12828# e.g. in Chemical formulae
12829sub do_cmd__sub {
12830    local($_) = @_;
12831    local($next);
12832    $next = &missing_braces unless (
12833        (s/$next_pair_pr_rx/$next = $2;''/e)
12834        ||(s/$next_pair_rx/$next = $2;''/e));
12835    join('',"<SUB>",$next,"</SUB>",$_);
12836				      }
12837
12838#JCL(jcl-del) - the next two ones must only have local effect.
12839# Yet, we don't have a mechanism to revert such changes after
12840# a group has closed.
12841#
12842sub do_cmd_makeatletter {
12843    $letters =~ s/@//;
12844    $letters .= '@';
12845    &make_letter_sensitive_rx;
12846    $_[0];
12847				      }
12848
12849sub do_cmd_makeatother {
12850    $letters =~ s/@//;
12851    &make_letter_sensitive_rx;
12852    $_[0];
12853				      }
12854
12855
12856################## Commands to be processed by Latex #################
12857#
12858# The following commands are passed to Latex for processing.
12859# They cannot be processed at the same time as normal commands
12860# because their arguments must be left untouched by the translator.
12861# (Normally the arguments of a command are translated before the
12862# command itself).
12863#
12864# In fact, it's worse:  it is not correct to process these
12865# commands after we process environments, because some of them
12866# (for instance, \parbox) may contain unknown or wrapped
12867# environments.  If math mode occurs in a parbox, the
12868# translate_environments routine should *not* process it, lest
12869# we encounter the lossage outlined above.
12870#
12871# On the other hand, it is not correct to process these commands
12872# *before* we process environments, or figures containing
12873# parboxes, etc., will be mishandled.
12874#
12875# RRM: (added for V97.1)
12876#  \parbox now uses the  _wrap_deferred  mechanism, and has a  do_cmd_parbox
12877#  subroutine defined. This means that environments where parboxes are
12878#  common (.g. within table cells), can detect the \parbox command and
12879#  adjust the processing accordingly.
12880#
12881# So, the only way to handle these commands is to wrap them up
12882# in null environments, as for math mode, and let translate_environments
12883# (which can handle nesting) figure out which is the outermost.
12884#
12885# Incidentally, we might as well make these things easier to configure...
12886
12887sub process_commands_in_tex {
12888    local($_) = @_;
12889    local($arg,$tmp);
12890    foreach (/.*\n?/g) {
12891	chop;
12892	# For each line
12893	local($cmd, @args) = split('#',$_);
12894	print "PCT: process_commands_in_tex: cmd: $cmd - $_\n" if ($VERBOSITY > 10) ;
12895	next unless $cmd;
12896	$cmd =~ s/ //g;
12897
12898	# skip if a proper implementation already exists
12899	$tmp = "do_cmd_$cmd";
12900	print "PCT: process_commands_in_tex: tmp: $tmp\n" if ($VERBOSITY > 10) ;
12901	next if (defined &$tmp);
12902
12903	# Build routine body ...
12904	local ($body, $code, $thisone) = ("", "");
12905
12906	# alter the pattern here to debug particular commands
12907#	$thisone = 1 if ($cmd =~ /mathbb/);
12908
12909	print "\n$cmd: ".scalar(@args)." arguments" if ($thisone);
12910	foreach $arg (@args) {
12911	    print "\nARG: $arg" if ($thisone);
12912	    print "\nARG: $next_pair_rx" if ($thisone);
12913	    if ($arg =~ /\{\}/) {
12914# RRM: the $` is surely wrong, allowing no error-checking.
12915# Use <<...>> for specific patterns
12916#		$body .= '$args .= "$`$&" if s/$next_pair_rx//o;'."\n";
12917		$body .= '$args .= join("","{", &missing_braces, "}") unless ('."\n";
12918		$body .= '  (s/$next_pair_pr_rx/$args.=$`.$&;""/es)'."\n";
12919		$body .= '  ||(s/$next_pair_rx/$args.=$`.$&;""/es));'."\n";
12920		print "\nAFTER:$'" if (($thisone)&&($'));
12921		$body .= $' if ($');
12922	    } elsif ($arg =~ /\[\]/) {
12923		$body .= '($dummy, $pat) = &get_next_optional_argument;'
12924		    . '$args .= $pat;'."\n";
12925		print "\nAFTER:$'" if (($thisone)&&($'));
12926		$body .= $' if ($');
12927	    } elsif ($arg =~ /^\s*\\/) {
12928		$body .= '($dummy, $pat) = &get_next_tex_cmd;'
12929		    . '$args .= $pat;'."\n";
12930		print "\nAFTER:$'" if (($thisone)&&($'));
12931		$body .= $' if ($');
12932	    } elsif ($arg =~ /<<\s*/) {
12933		$arg = $';
12934		if ($arg =~ /\s*>>/) {
12935                    # MRO: replaced $* with /m
12936		    $body .= '$args .= "$`$&" if (/\\'.$`.'/m);' . "\n"
12937#		    $body .= '$args .= "$`$&" if (/\\\\'.$`.'/);' . "\n"
12938			. "\$_ = \$\';\n";
12939		    print "\nAFTER:$'" if (($thisone)&&($'));
12940		    $body .= $' if ($');
12941		} else { $body .= $arg ; }
12942	    } else {
12943	        print "\nAFTER:$'" if (($thisone)&&($arg));
12944		$body .= $arg ;
12945	    }
12946	}
12947
12948	# Generate a new subroutine
12949	local($padding) = " ";
12950	$padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
12951	$code = "sub wrap_cmd_$cmd {" . "\n"
12952	    . 'local($cmd, $_) = @_; local ($args, $dummy, $pat) = "";' . "\n"
12953	    . $body
12954	    . (($thisone)? "print STDERR \"\\n$cmd:\".\$args.\"\\n\";\n" : '')
12955	    . '(&make_wrapper(1).$cmd'
12956	    . ($padding ? '"'.$padding.'"' : '')
12957	    . '.$args.&make_wrapper(0), $_)}'
12958	    . "\n";
12959	print "\nWRAP_CMD: $code " if ($thisone); # for debugging
12960	eval $code; # unless ($thisone);
12961	print STDERR "\n*** sub wrap_cmd_$cmd  failed: $@" if ($@);
12962
12963	# And make sure the main loop will catch it ...
12964#	$raw_arg_cmds{$cmd} = 1;
12965	++$raw_arg_cmds{$cmd};
12966    }
12967				      }
12968
12969sub process_commands_nowrap_in_tex {
12970    local($_) = @_;
12971    local($arg);
12972    foreach (/.*\n?/g) {
12973	chop;
12974	local($cmd, @args) = split('#',$_);
12975	next unless $cmd;
12976	$cmd =~ s/ //g;
12977	# Build routine body ...
12978	local ($bodyA, $codeA, $bodyB, $codeB, $thisone) = ("", "", "", "");
12979
12980	# alter the pattern here to debug particular commands
12981#	$thisone = 1 if ($cmd =~ /epsf/);
12982
12983	print "\n$cmd: ".scalar(@args)." arguments" if ($thisone);
12984	foreach $arg (@args) {
12985	    print "\nARG: $arg" if ($thisone);
12986	    if ($arg =~ /\{\}/) {
12987#		$bodyA .= '$args .= "$`"."$&" if (s/$any_next_pair_rx//);'."\n";
12988		$bodyA .= 'if (s/$next_pair_rx//s){$args.="$`"."$&"; $_='."\$'};\n";
12989		$bodyB .= '$args .= &missing_braces'."\n unless (";
12990		$bodyB .= '(s/$any_next_pair_pr_rx/$args.=$`.$&;\'\'/eo)'."\n";
12991		$bodyB .= '  ||(s/$any_next_pair_rx/$args.=$`.$&;\'\'/eo));'."\n";
12992		print "\nAFTER:$'" if (($thisone)&&($'));
12993#		$bodyA .= $'.";\n" if ($');
12994		$bodyB .= $'.";\n" if ($');
12995	    } elsif ($arg =~ /\[\]/) {
12996		$bodyA .= '($dummy, $pat) = &get_next_optional_argument;'
12997		    . '$args .= $pat;'."\n";
12998		print "\nAFTER:$'" if (($thisone)&&($'));
12999#		$bodyA .= $'.";\n" if ($');
13000		$bodyB .= $'.";\n" if ($');
13001	    } elsif ($arg =~ /^\s*\\/) {
13002		$bodyA .= '($dummy, $pat) = &get_next_tex_cmd;'
13003		    . '$args .= $pat;'."\n";
13004		$bodyB .= '($dummy, $pat) = &get_next_tex_cmd;'
13005		    . '$args .= $pat;'."\n";
13006		print "\nAFTER:$'" if (($thisone)&&($'));
13007		$bodyA .= $'.";\n" if ($');
13008		$bodyB .= $'.";\n" if ($');
13009	    } elsif ($arg =~ /<<\s*/) {
13010		$arg = $';
13011		if ($arg =~ /\s*>>/) {
13012                    # MRO: replaced $* with /m
13013		    $bodyA .= '$args .= "$`$&" if (/\\'.$`.'/m);' . "\n"
13014#		    $bodyA .= '$args .= $`.$& if (/\\\\'.$`.'/);' . "\n"
13015			. "\$_ = \$\';\n";
13016		    $bodyB .= '$args .= "$`$&" if (/\\'.$`.'/m);' . "\n"
13017			. "\$_ = \$\';\n";
13018		    print "\nAFTER:$'" if (($thisone)&&($'));
13019#		    $bodyA .= $'.";\n" if ($');
13020		    $bodyB .= $'.";\n" if ($');
13021		} else {
13022		    print "\nAFTER:$arg" if (($thisone)&&($arg));
13023#		    $bodyA .= $arg.";\n" if ($arg);
13024		    $bodyB .= $arg.";\n" if ($arg);
13025		}
13026	    } else {
13027		print "\nAFTER:$arg" if (($thisone)&&($arg));
13028		$bodyA .= '$args .= '.$arg.";\n" if ($');
13029		$bodyB .= $arg.";\n" if ($');
13030	    }
13031	}
13032	local($padding) = " ";
13033	$padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
13034	# Generate 2 new subroutines
13035	$codeA = "sub wrap_cmd_$cmd {" . "\n"
13036	    .'local($cmd, $_) = @_; local($args, $dummy, $pat) = "";'."\n"
13037	    . $bodyA
13038	    . (($thisone)? "print \"\\nwrap $cmd:\\n\".\$args.\"\\n\";\n" : '')
13039	    . '(&make_nowrapper(1)."\n".$cmd.'."\"$padding\""
13040	    . '.$args.&make_nowrapper(0)," ".$_)}'
13041	    ."\n";
13042	print "\nWRAP_CMD: $codeA " if ($thisone); # for debugging
13043	eval $codeA;
13044	print STDERR "\n\n*** sub wrap_cmd_$cmd  failed: $@\n" if ($@);
13045	$codeB = "do_cmd_$cmd";
13046	do {
13047	    $bodyB = '"";' if !($bodyB);
13048	    $codeB = "sub do_cmd_$cmd {" . "\n"
13049		. 'local($_,$ot) = @_;'."\n"
13050		. 'local($open_tags_R) = defined $ot ? $ot : $open_tags_R;'."\n"
13051		. 'local($cmd,$args,$dummy,$pat)=("'.$cmd.'","","","");'."\n"
13052		. $bodyB
13053		. (($thisone)? "print \"\\ndo $cmd:\".\$args.\"\\n\";\n" : '')
13054#		. '$latex_body.="\\n".&revert_to_raw_tex("'."\\\\$cmd$padding".'$args")."\\n\\n";'
13055		. "\$_;}\n";
13056	    print STDOUT "\nDO_CMD: $codeB " if ($thisone); # for debugging
13057	    eval $codeB;
13058	    print STDERR "\n\n*** sub do_cmd_$cmd  failed: $@\n" if ($@);
13059	} unless (defined &$codeB );
13060
13061	# And make sure the main loop will catch it ...
13062#	$raw_arg_cmds{$cmd} = 1;
13063	++$raw_arg_cmds{$cmd};
13064    }
13065}
13066
13067sub process_commands_wrap_deferred {
13068    local($_) = @_;
13069    local($arg,$thisone);
13070    foreach (/.*\n?/g) {
13071	chop;
13072	local($cmd, @args) = split('#',$_);
13073	print "PCT: process_commands_wrap_deferred: cmd: $cmd\n" if ($VERBOSITY > 10) ;
13074	next unless $cmd;
13075	$cmd =~ s/ //g;
13076	# Build routine body ...
13077	local ($bodyA, $codeA, $bodyB, $codeB, $after, $thisone);
13078
13079	# alter the pattern here to debug particular commands
13080	#	$thisone = 1 if ($cmd =~ /selectlanguage/);
13081
13082	print "\n$cmd: ".scalar(@args)." arguments" if ($thisone);
13083	foreach $arg (@args) {
13084	    print "\nARG: $arg" if ($thisone);
13085	    if ($arg =~ /\{\}/) {
13086		#		$bodyA .= '$args .= "$`$&" if (s/$any_next_pair_rx//o);';
13087		$bodyA .= '$args .= "$`$&" if (s/$next_pair_rx//so);';
13088		$after = $';
13089		print "\nAFTER:$'" if (($thisone)&&($'));
13090	    } elsif ($arg =~ /\[\]/) {
13091		$bodyA .= '($dummy, $pat) = &get_next_optional_argument;' .
13092									    "\n". '$args .= $pat;';
13093		$after = $';
13094		print "\nAFTER:$'" if (($thisone)&&($'));
13095	    } elsif ($arg =~ /^\s*\\/) {
13096		$bodyA .= '($dummy, $pat) = &get_next_tex_cmd;'
13097								  . '$args .= $pat;'."\n";
13098		print "\nAFTER:$'" if (($thisone)&&($'));
13099		$bodyA .= $'.";\n" if ($');
13100	    } elsif (/<<\s*([^>]*)[\b\s]*>>/) {
13101		local($endcmd, $afterthis) = ($1,$');
13102		$afterthis =~ s/(^\s*|\s*$)//g;
13103		$endcmd =~ s/\\/\\\\/g;
13104		$bodyA .= join('',
13105			       "\n",
13106			       'if (/',
13107			       $endcmd,
13108			       '/) { $args .= $`.$& ; $_ = $',
13109			       "'",
13110			       '};') ;
13111		$after .= $afterthis if ($afterthis);
13112		print "\nAFTER:$'" if (($thisone)&&($'));
13113	    } else {
13114		print "\nAFTER:$arg" if (($thisone)&&($arg));
13115		$bodyB .= $arg.";\n" ; $after = ''
13116            }
13117	    $after =~ s/(^\s*|\s*$)//g if ($after);
13118	    $bodyB .= $after . ";" if ($after);
13119	    $bodyA .= "\$args .= ".$after . ";" if ($after);
13120	}
13121	local($padding) = " ";
13122	$padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
13123	# Generate 2 new subroutines
13124	$codeA = join('',
13125		      "sub wrap_cmd_$cmd {",
13126		      "\n",
13127		      'local($cmd, $_) = @_; local ($args, $dummy, $pat) = "";',
13128		      "\n",
13129		      $bodyA, #. ($bodyA ? "\n" : '')
13130		      (($thisone)? ";print \"\\nwrap $cmd:\".\$args.\"\\n\";\n" : ''),
13131		      '(&make_deferred_wrapper(1).$cmd.',
13132		      $padding,
13133		      '$args.&make_deferred_wrapper(0),$_)}',
13134		      "\n") ;
13135	print STDERR "\nWRAP_CMD: $codeA " if ($thisone); # for debugging
13136	eval $codeA;
13137	print STDERR "\n\n*** sub wrap_cmd_$cmd  failed: $@\n" if ($@);
13138
13139	#RRM: currently these commands only go to LaTeX or access counters.
13140	#   They could be implemented more generally, as below with  do_dcmd_$cmd
13141	#   requiring replacement to be performed before evaluation.
13142	$codeB = join('',
13143		      "sub do_dcmd_$cmd {" . "\n",
13144		      'local($cmd, $_) = @_; local ($args, $dummy, $pat) = "";',
13145		      "\n",
13146		      $bodyA,
13147		      "\n",
13148		      (($thisone)? ";print \"\\ndo_def $cmd:\".\$args.\"\\n\";\n" : ''),
13149		      $bodyB,
13150		      "}",
13151		      "\n") ;
13152	print "\nDEF_CMD: $codeB " if ($thisone); # for debugging
13153	local($tmp) = "do_cmd_$cmd";
13154	eval $codeB unless (defined &$tmp);
13155	print STDERR "\n\n*** sub do_dcmd_$cmd  failed: $@\n" if ($@);
13156
13157	# And make sure the main loop will catch it ...
13158	#	$raw_arg_cmds{$cmd} = 1;
13159	++$raw_arg_cmds{$cmd};
13160    }
13161}
13162
13163sub process_commands_inline_in_tex {
13164    local($_) = @_;
13165    foreach (/.*\n?/g) {
13166	chop;
13167	local($cmd, @args) = split('#',$_);
13168	next unless $cmd;
13169	$cmd =~ s/ //g;
13170	# Build routine body ...
13171	local ($body, $code, $thisone) = ("", "");
13172
13173	# uncomment and alter the pattern here to debug particular commands
13174	#	$thisone = 1 if ($cmd =~ /L/);
13175
13176	print "\n$cmd: ".scalar(@args)." arguments" if ($thisone);
13177	foreach (@args) {
13178	    print "\nARG: $_" if ($thisone);
13179	    if (/\{\}/) {
13180		#		$body .= '$args .= $`.$& if (/$any_next_pair_rx/);' . "\n"
13181		#		    . "\$_ = \$\';\n";
13182		$body .= '$args .= $`.$& if (s/$next_pair_rx//s);' . "\n"
13183	    } elsif (/\[\]/) {
13184		$body .= join('',
13185			      'local($dummy, $pat) = &get_next_optional_argument;',
13186			      "\n",
13187			      '$args .= $pat;') ;
13188	    } elsif ($arg =~ /^\s*\\/) {
13189		$body .= join('',
13190			      '($dummy, $pat) = &get_next_tex_cmd;',
13191			      '$args .= $pat;',
13192			      "\n") ;
13193		print "\nAFTER:$'" if (($thisone)&&($'));
13194		$body .= $'.";\n" if ($');
13195	    } elsif (/<<\s*/) {
13196		$_ = $';
13197		if (/\s*>>/) {
13198                    # MRO: replaced $* with /m
13199		    $body .= join('','$args .= "$`$&" if (/\\',
13200				  $`,
13201				  '/m);',
13202				  "\n",
13203				  "\$_ = \$\';\n") ;
13204		} else { $body .= $_.";\n" ; }
13205	    } else { $body .= $_.";\n" ; }
13206	}
13207	local($padding) = " ";
13208	$padding = '' if (($cmd =~ /\W$/)||(!$args)||($args =~ /^\W/));
13209	# Generate a new subroutine
13210	my $itype = ($cmd =~ /^f.*box$/ ? 'inline' : 'nomath');
13211	$code = join('',
13212		     "sub wrap_cmd_$cmd {" . "\n",
13213		     'local($cmd, $_) = @_; local ($args) = "";',
13214		     "\n",
13215		     $body,
13216		     "\n",
13217		     (($thisone)? ";print \"\\ndo $cmd:\".\$args.\"\\n\";\n" : ''),
13218		     '(&make_'.$itype.'_wrapper(1).$cmd.$padding.$args.',
13219		     '&make_'.$itype.'_wrapper(0),$_)}',
13220		     "\n") ;
13221	print "\nWRAP_CMD:$raw_arg_cmds{$cmd}: $code "
13222	    if ($thisone); # for debugging
13223	eval $code;
13224	print STDERR "\n\n*** sub wrap_cmd_$cmd  failed: $@\n" if ($@);
13225	# And make sure the main loop will catch it ...
13226	#	$raw_arg_cmds{$cmd} = 1;
13227	++$raw_arg_cmds{$cmd};
13228    }
13229}
13230
13231
13232# Invoked before actual translation; wraps these commands in
13233# tex2html_wrap environments, so that they are properly passed to
13234# TeX in &translate_environments ...
13235# JCL(jcl-del) - new usage of $raw_arg_cmd_rx
13236sub wrap_raw_arg_cmds {
13237    local ($processed_text, $cmd, $wrapper, $wrap, $after);
13238    print "\nwrapping raw arg commands " if ($VERBOSITY>1);
13239    local($seg, $par_wrap, $teststar, @processed);
13240    #   local(@segments) = split(/\\par\b/,$_);
13241    #   foreach (@segments) {
13242    #      $par_wrap = join('',&make_deferred_wrapper(1), "\\par"
13243    #			, &make_deferred_wrapper(0));
13244    #     push(@processed, $par_wrap ) if ($seg); ++$seg;
13245    if (%renew_command) {
13246	local($key);
13247	foreach $key (keys %renew_command) {
13248	    $raw_arg_cmds{$key} = 1;
13249	    $raw_arg_cmd_rx =~ s/^(\(\)\\\\\()/$1$key\|/;
13250	}
13251    }
13252    print "\n" if (/$raw_arg_cmd_rx/);
13253
13254    # MRO: replaced $* with /m
13255    while (/$raw_arg_cmd_rx/m) {
13256	local($star);
13257	push (@processed, $`); print "\@";
13258	$after = $';
13259	#JCL(jcl-del) - status of starred raw arg cmds yet unclear
13260	($cmd, $star) = ($1.$2,$4);
13261	if ($star eq '*') {
13262	    $star = 'star';
13263	}
13264	else {
13265	    $after = $star.$after; $star = '';
13266	}
13267	$wrapper = "wrap_cmd_$cmd"; $teststar = $wrapper.'star';
13268	if ($star && defined &$teststar) { $wrapper = $teststar; $star = '*'; }
13269        # MRO: make {\bf**} work
13270	elsif($star) { $after = '*'.$after; $star = '' }
13271	print "\nWRAPPED: $cmd as $wrapper" if ($VERBOSITY > 5);
13272
13273	# ensure that the result is separated from following words...
13274	my $padding = ($after =~ /^[a-zA-Z]/s)? ($cmd =~ /\W$/ ? '':' '):'';
13275
13276	if ($raw_arg_cmds{$cmd} && defined &$wrapper) {
13277	    ($wrap, $_) = &$wrapper("\\$cmd$star", $padding . $after);
13278	    # ...but don't leave an unwanted space at the beginning
13279	    $_ =~ s/^ //s if($padding && $wrap !~ /\w$/m
13280			     && (length($_) == length($after)+1) );
13281	    push (@processed, $wrap);
13282	} elsif ($raw_arg_cmds{$cmd}) {
13283	    print STDERR "\n*** $wrapper not defined, cannot wrap \\$cmd";
13284	    &write_warnings("\n*** $wrapper not defined, cannot wrap \\$cmd ");
13285	    push (@processed, "\\$cmd$padding");
13286	    $_ = $after;
13287	} else {
13288	    push (@processed, "\\$cmd$padding");
13289	    $_ = $after;
13290	}
13291        last unless ($after =~ /\\/);
13292    }
13293
13294    # recombine the pieces
13295    $_ = join('',@processed, $_);
13296}
13297
13298#########################################################################
13299
13300# To make a table of contents, list of figures and list of tables commands
13301# create a link to corresponding files which do not yet exist.
13302# The binding of the file variable in each case acts as a flag
13303# for creating the actual file at the end, after all the information
13304# has been gathered.
13305
13306sub do_cmd_tableofcontents { } ;
13307#&do_real_tableofcontents(@_) }
13308sub do_real_tableofcontents {
13309    #    local($_) = @_;
13310    if ((defined &do_cmd_contentsname)||$new_command{'contentsname'}) {
13311	local($br_id)=++$global{'max_id'};
13312	$TITLE = &translate_environments("$O$br_id$C\\contentsname$O$br_id$C");
13313    }
13314    else {
13315	$TITLE = $toc_title ;
13316    }
13317    $toc_sec_title = $TITLE;
13318    $tocfile = $CURRENT_FILE;  # sets  $tocfile  this globally
13319    local $toc_head = $section_headings{'tableofcontents'};
13320    if ($toc_style) {
13321	$toc_head .= " CLASS=\"$toc_style\"";
13322	$env_style{"$toc_head.$toc_style"} = " "
13323	    unless ($env_style{"$toc_head.$toc_style"});
13324    }
13325    local($closures,$reopens) = &preserve_open_tags();
13326    join('',
13327	 "<BR>\n",
13328	 $closures,
13329	 &make_section_heading($TITLE, $toc_head),
13330	 $toc_mark,
13331	 $reopens,
13332	 @_[0]);
13333}
13334sub do_cmd_listoffigures {
13335    local($_) = @_;
13336    local($list_type) = ($SHOW_SECTION_NUMBERS ? 'UL' : 'OL' );
13337    if ((defined &do_cmd_listfigurename)||$new_command{'listfigurename'}) {
13338	local($br_id)=++$global{'max_id'};
13339	$TITLE = &translate_environments("$O$br_id$C\\listfigurename$O$br_id$C");
13340    } else { $TITLE = $lof_title }
13341    $toc_sec_title = $TITLE;
13342    $loffile = $CURRENT_FILE;  # sets  $loffile  this globally
13343    local $lof_head = $section_headings{'listoffigures'};
13344    local($closures,$reopens) = &preserve_open_tags();
13345    join('',
13346	 "<BR>\n",
13347	 $closures,
13348	 &make_section_heading($TITLE, $lof_head),
13349	 "<$list_type>",
13350	 $lof_mark,
13351	 "</$list_type>",
13352	 $reopens,
13353	 $_);
13354}
13355sub do_cmd_listoftables {
13356    local($_) = @_;
13357    local($list_type) = ($SHOW_SECTION_NUMBERS ? 'UL' : 'OL' );
13358    if ((defined &do_cmd_listtablename)||$new_command{'listtablename'}) {
13359	local($br_id)=++$global{'max_id'};
13360	$TITLE = &translate_environments("$O$br_id$C\\listtablename$O$br_id$C");
13361    } else { $TITLE = $lot_title }
13362    $toc_sec_title = $TITLE;
13363    $lotfile = $CURRENT_FILE;  # sets  $lotfile  this globally
13364    local $lot_head = $section_headings{'listoftables'};
13365    local($closures,$reopens) = &preserve_open_tags();
13366    join('', "<BR>\n", $closures
13367	 , &make_section_heading($TITLE, $lot_head)
13368	 , "<$list_type>", $lot_mark, "</$list_type>"
13369	 , $reopens, $_);
13370}
13371
13372# Indicator for where to put the CHILD_LINKS table.
13373sub do_cmd_tableofchildlinks {
13374    local($_) = @_;
13375    local($thismark) = $childlinks_mark;
13376    local($option,$dum) = &get_next_optional_argument;
13377    $thismark = &check_childlinks_option($option) if ($option);
13378    local($pre,$post) = &minimize_open_tags("$thismark\#0\#");
13379    join('', "<BR>", $pre, $_);
13380}
13381
13382# leave out the preceding <BR>
13383sub do_cmd_tableofchildlinksstar {
13384    local($_) = @_;
13385    local($thismark) = $childlinks_mark;
13386    local($option,$dum) = &get_next_optional_argument;
13387    $thismark = &check_childlinks_option($option) if ($option);
13388    local($pre,$post) = &minimize_open_tags("$thismark\#1\#");
13389    join('', $pre, $_);
13390}
13391
13392sub check_childlinks_option {
13393    local($option) = @_;
13394    if ($option =~ /none/i) {
13395	$childlinks_mark = $childlinks_null_mark;
13396	$childlinks_null_mark }
13397    elsif ($option =~ /off/i) { $childlinks_null_mark }
13398    elsif ($option =~ /all/i) {
13399	$childlinks_mark = $childlinks_on_mark;
13400	$childlinks_on_mark }
13401    elsif ($option =~ /on/i) { $childlinks_on_mark }
13402}
13403
13404sub remove_child_marks {
13405    # Modifies $_
13406    s/($childlinks_on_mark|$childlinks_null_mark)\#\d\#//go;
13407}
13408
13409
13410sub do_cmd_htmlinfo {
13411    local($_) = @_;
13412    local($option,$dum) = &get_next_optional_argument;
13413    if ($option =~ /^(off|none)/i) { $INFO = 0; return ($_) }
13414    local($pre,$post) = &minimize_open_tags($info_title_mark.$info_page_mark);
13415    join('', "<BR>", $pre, $_);
13416}
13417sub do_cmd_htmlinfostar {
13418    local($_) = @_;
13419    local($option,$dum) = &get_next_optional_argument;
13420    if ($option =~ /^(off|none)/i) { $INFO = 0; return ($_) }
13421    local($pre,$post) = &minimize_open_tags($info_page_mark);
13422    join('', $pre, $_);
13423}
13424
13425# $idx_mark will be replaced with the real index at the end
13426sub do_cmd_textohtmlindex {
13427    local($_) = @_;
13428    if ((defined &do_cmd_indexname )||$new_command{'indexname'}) {
13429	local($br_id)=++$global{'max_id'};
13430	$TITLE = &translate_environments("$O$br_id$C\\indexname$O$br_id$C");
13431    } else { $TITLE = $idx_title }
13432    $toc_sec_title = $TITLE;
13433    $idxfile = $CURRENT_FILE;
13434    if (%index_labels) { &make_index_labels(); }
13435    if (($SHORT_INDEX) && (%index_segment)) { &make_preindex(); }
13436    else { $preindex = ''; }
13437    local $idx_head = $section_headings{'textohtmlindex'};
13438    local($heading) = join(''
13439	, &make_section_heading($TITLE, $idx_head)
13440	, $idx_mark );
13441    local($pre,$post) = &minimize_open_tags($heading);
13442    join('',"<BR>\n" , $pre, $_);
13443}
13444
13445#RRM: added 17 May 1996
13446# allows labels within the printable key of index-entries,
13447# when using  makeidx.perl
13448sub make_index_labels {
13449    local($key, @keys);
13450    @keys = keys %index_labels;
13451    foreach $key (@keys) {
13452	if (($ref_files{$key}) && !($ref_files{$key} eq "$idxfile")) {
13453	    local($tmp) = $ref_files{$key};
13454	    &write_warnings("\nmultiple label $key , target in $idxfile masks $tmp ");
13455	}
13456	$ref_files{$key} .= "$idxfile";
13457    }
13458}
13459#RRM: added 17 May 1996
13460# constructs a legend for the SHORT_INDEX, with segments
13461# when using  makeidx.perl
13462sub make_preindex { &make_real_preindex }
13463sub make_real_preindex {
13464    local($key, @keys, $head, $body);
13465    $head = "<HR>\n<H4>Legend:</H4>\n<DL COMPACT>";
13466    @keys = keys %index_segment;
13467    foreach $key (@keys) {
13468	local($tmp) = "segment$key";
13469	$tmp = $ref_files{$tmp};
13470	$body .= "\n<DT>$key<DD>".&make_named_href('',$tmp,$index_segment{$key});
13471#	$body .= "\n<DT>$key<DD>".&make_named_href('',
13472#		$tmp."\#CHILD\_LINKS",$index_segment{$key})
13473#	             unless ($CHILD_STAR);
13474    }
13475    $preindex = join('', $head, $body, "\n</DL>") if ($body);
13476}
13477
13478sub do_cmd_printindex { &do_real_printindex(@_); }
13479sub do_real_printindex {
13480    print "PCT: do_real_printindex\n" if ($VERBOSITY > 200) ;
13481    local($_) = @_;
13482    local($which) = &get_next_optional_argument;
13483    print "PCT: do_real_printindex: which: $which\n" if ($VERBOSITY > 200) ;
13484    $idx_name = $index_names{$which}
13485	if ($which && $index_names{$which});
13486    @_;
13487}
13488
13489				    sub do_cmd_newindex {
13490    local($_) = @_;
13491    local($dum,$key,$title);
13492    $key = &missing_braces unless (
13493	(s/$next_pair_pr_rx/$key=$2;''/eo)
13494	||(s/$next_pair_rx/$key=$2;''/eo));
13495    $dum = &missing_braces unless (
13496	(s/$next_pair_pr_rx/$dum=$2;''/eo)
13497	||(s/$next_pair_rx/$dum=$2;''/eo));
13498    $dum = &missing_braces unless (
13499	(s/$next_pair_pr_rx/$dum=$2;''/eo)
13500	||(s/$next_pair_rx/$dum=$2;''/eo));
13501    $title = &missing_braces unless (
13502	(s/$next_pair_pr_rx/$title=$2;''/eo)
13503	||(s/$next_pair_rx/$title=$2;''/eo));
13504    $index_names{$key} = $title if ($key && $title);
13505    @_;
13506}
13507
13508# FOOTNOTES , also within Mini-page environments
13509# allow easy way to override and inherit; e.g. for frames
13510
13511sub do_cmd_footnotestar { &do_real_cmd_footnote(@_) }
13512sub do_cmd_footnote { &do_real_cmd_footnote(@_) }
13513sub do_real_cmd_footnote {
13514    local($_) = @_;
13515    local($cnt,$marker,$smark,$emark)=('', $footnote_mark);
13516    local($mark,$dum) = &get_next_optional_argument;
13517    local($anchor_name);
13518
13519    $footfile = "${PREFIX}$FOOT_FILENAME$EXTN"
13520	unless ($footfile||$MINIPAGE||$NO_FOOTNODE);
13521
13522    if ($mark) {
13523	$cnt = $mark;
13524	if ($MINIPAGE) { $global{'mpfootnote'} = $cnt }
13525	else { $global{'footnote'} = $cnt }
13526    } else {
13527	$cnt = (($MINIPAGE)? ++$global{'mpfootnote'} : ++$global{'footnote'});
13528    }
13529    local($br_id, $footnote)=(++$global{'max_id'},'');
13530    $footnote = &missing_braces unless (
13531        (s/$next_pair_pr_rx/${br_id}=$1; $footnote=$2;''/eo)
13532	||(s/$next_pair_rx/${br_id}=$1; $footnote=$2;''/eo));
13533    $br_id = "mp".$br_id if ($MINIPAGE);
13534    $marker = &get_footnote_mark($MINIPAGE);
13535    local($last_word) = &get_last_word();
13536    local($href) = &make_href("$footfile#foot$br_id",$marker);
13537    if ($href =~ /NAME="([^"]*)"/) { $anchor_name=$1 }
13538    $last_word .= $marker unless ($anchor_name);
13539    &process_footnote($footnote,$cnt,$br_id,$last_word,$mark
13540	      ,($MINIPAGE? $marker : '')
13541	      ,($MINIPAGE? '' : "$marker:$anchor_name") );
13542    # this may not work if there is a <BASE> tag and !($file) !!! #
13543#   join('',&make_href("$file#foot$br_id",$marker),$_);
13544    $href . $_
13545				   }
13546
13547sub process_image_footnote {
13548    # MRO: modified to use $_[0]
13549    # local(*math) = @_;
13550    local($in_image, $keep, $pre, $this_anchor, $out, $foot_counters_recorded, @foot_anchors) = (1,'','');
13551    local($image_contents) = $_[0];
13552    $image_contents =~ s/\\(begin|end)(($O|$OP)\d+($C|$CP))tex2html_\w+\2//go;
13553    $image_contents =~ s!(\\footnote(mark\b\s*(\[[^\]]*\])?|\s*(\[[^\]]*\])?\s*(($O|$OP)\d+($C|$CP))(.*)\5))!
13554	$keep = $`; $out = '\footnotemark '.$3.$4;
13555        #MRO: $*=1; local($saveRS) = $/; $/='';
13556	if ($8) {
13557	    $this_anchor = &do_cmd_footnote($2);
13558	} else {
13559	    $this_anchor = &do_cmd_footnotemark($3);
13560	}
13561        #MRO: $*=0; $/ = $saveRS;
13562	$foot_counters_recorded = 1;
13563	push(@foot_anchors, $this_anchor);
13564	$out!oesg;
13565    $_[0] = $image_contents;
13566    @foot_anchors;
13567				   }
13568
13569sub do_cmd_thanks { &do_cmd_footnote(@_); }
13570
13571sub get_footnote_mark {
13572    local($mini) = @_;
13573    return($footnote_mark) if ($HTML_VERSION < 3.0 );
13574    local($cmd,$tmp,@tmp,$marker);
13575    $cmd = "the". (($mini)? 'mp' : '') . "footnote";
13576    if ($new_command{$cmd}) {
13577	$tmp = "do_cmd_$cmd";
13578	@tmp = split (':!:', $new_command{$cmd});
13579	pop @tmp; $tmp = pop @tmp;
13580	if ($tmp =~ /$O/) {
13581###	    local($_) = &translate_commands($tmp);
13582	    $marker = &translate_commands(&translate_environments($tmp));
13583	    &make_unique($marker);
13584###	    $marker = $_;
13585	} else { $marker = &translate_commands(&translate_environments($tmp)); }
13586    } elsif ($mini) {
13587    	$marker = &translate_commands('\thempfootnote');
13588    } elsif ((defined &do_cmd_thefootnote)||$new_command{'thefootnote'}) {
13589	local($br_id)=++$global{'max_id'};
13590	$marker = &translate_environments("$O$br_id$C\\thefootnote$O$br_id$C");
13591    } else { $marker = $footnote_mark; }
13592    join('','<SUP>',$marker,'</SUP>');
13593				   }
13594
13595sub make_numbered_footnotes {
13596    eval "sub do_cmd_thefootnote {\&numbered_footnotes}" }
13597sub numbered_footnotes { &do_cmd_arabic('<<0>>footnote<<0>>');}
13598
13599# default numbering style for minipage notes
13600sub do_cmd_thempfootnote { &do_cmd_arabic('<<0>>mpfootnote<<0>>'); }
13601
13602sub do_cmd_footnotemark { &do_real_cmd_footnotemark(@_) }
13603sub do_real_cmd_footnotemark {
13604    local($_) = @_;
13605    local($br_id, $footnote,$marker,$mpnote,$tmp,$smark,$emark);
13606    # Don't use ()'s for the optional argument!
13607    local($mark,$dum) = &get_next_optional_argument;
13608    local ($cnt,$text_known) = ('','');
13609    if ($mark) {
13610	$cnt = (($mark =~ /\\/)? &translate_commands($mark) : $mark);
13611	if (($MINIPAGE)&&($mpfootnotes{$cnt})) {
13612	    $mpnote = 1;
13613	    $br_id  = $mpfootnotes{$cnt};
13614	    $text_known = 1;
13615	} else {
13616	    $global{'footnote'} = $cnt;
13617	    local($tmp) = $footnotes{$cnt};
13618	    if ($tmp) {
13619		$br_id  = $tmp;
13620		$text_known = 1;
13621	    } else { $footnotes{$cnt} = $br_id }
13622	}
13623    } else {
13624	$cnt = ++$global{'footnote'};
13625	$text_known = 1 if ($footnotes{$cnt});
13626    }
13627    if ($text_known) {
13628	$br_id = ($MINIPAGE ? $mpfootnotes{$cnt} : $footnotes{$cnt});
13629	$marker = &get_footnote_mark($mpnote);
13630	return (join('', &make_href("$footfile#foot$br_id",$marker),$_));
13631    }
13632
13633    local($last_word) = &get_last_word() unless ($mpnote);
13634
13635    # Try to find a  \footnotetext  further on.
13636    do {
13637	if (s/\\footnotetext\s*\[\s*$cnt\s*]*\]\s*$any_next_pair_pr_rx//o) {
13638	    ($br_id, $footnote) = ($2, $3);
13639	} else {
13640	    $br_id = "fnm$cnt";
13641	    $footnotes{$cnt} = $br_id;
13642	}
13643    } unless ($br_id);
13644
13645    $marker = &get_footnote_mark($mpnote);
13646    $last_word .= $marker unless ($marker =~ /$footnote_mark/ );
13647    if ($footnote) {
13648	# found a  \footnotetext  further on
13649	&process_footnote($footnote,$cnt,$br_id,$last_word,$mark);
13650	join('',&make_named_href("foot$br_id","$footfile#$br_id",$marker),$_);
13651    } elsif ($br_id =~ /fnm/) {
13652	# no  \footnotetext  yet, so make the entry in $footnotes
13653	&process_footnote('',$cnt,$br_id,$last_word,$mark);
13654	# this may not work if there is a <BASE> tag and !($footfile) !!! #
13655	join('',&make_named_href("foot$br_id","$footfile#$br_id",$marker),$_);
13656    } elsif ($br_id) {
13657	# \footnotetext  already processed
13658	if ($mpnote) {
13659	    $mpfootnotes =~ s/(=\"$br_id\">...)(<\/A>)/$1$last_word$3/
13660		if ($last_word);
13661	    # this may not work if there is a <BASE> tag !!! #
13662	    join('',&make_named_href("foot$br_id","#$br_id",$marker),$_);
13663	} else {
13664	    $footnotes =~ s/(=\"$br_id\">...)(<\/A>)/$1$last_word$3/;
13665	    # this may not work if there is a <BASE> tag and !($footfile) !!! #
13666	    join(''
13667		,&make_named_href("foot$br_id","$footfile#$br_id",$marker),$_);
13668	}
13669    } else {
13670	print "\nCannot find \\footnotetext for \\footnotemark $cnt";
13671	# this may not work if there is a <BASE> tag and !($footfile) !!! #
13672	join('',&make_named_href("foot$br_id","$footfile",$marker),$_);
13673    }
13674				   }
13675
13676# Under normal circumstances this is never executed. Any commands \footnotetext
13677# should have been processed when the corresponding \footnotemark was
13678# encountered. It is possible however that when processing pieces of text
13679# out of context (e.g. \footnotemarks in figure and table captions)
13680# the pair of commands gets separated. Until this is fixed properly,
13681# this command just puts the footnote in the footnote file in the hope
13682# that its context will be obvious ....
13683sub do_cmd_footnotetext {
13684    local($_) = @_;
13685    local($mark,$dum) = &get_next_optional_argument;
13686    local($br_id, $footnote, $prev, $key)=(1,'','','');
13687    $footnote = &missing_braces unless (
13688	(s/$next_pair_pr_rx/($br_id,$footnote)=($1,$2);''/eo)
13689	||(s/$next_pair_rx/($br_id,$footnote)=($1,$2);''/eo));
13690
13691    $mark = $global{'footnote'} unless $mark;
13692    $prev = $footnotes{$mark};
13693    if ($prev) {
13694	$prev = ($MINIPAGE ? 'mp' : '') . $prev;
13695	# first prepare the footnote-text
13696	$footnote = &translate_environments("${OP}$br_id$CP$footnote${OP}$br_id$CP")
13697            if ($footnote);
13698	$footnote = &translate_commands($footnote) if ($footnote =~ /\\/);
13699
13700	# now merge it onto the Footnotes page
13701	$footnotes =~ s/(=\"$prev\">\.\.\.)(.*<\/A>)(<\/DT>\n<DD>)\n/
13702		$1.'<html_this_mark>'.$3.$footnote/e;
13703	local($this_mark) = $2;
13704	$this_mark =~ s|(<SUP>)(?:<#\d+#>)?(\d+)(?:<#\d+#>)?(<\/SUP>)(<\/A>)$|
13705		"$4<A\n HREF=\"$CURRENT_FILE\#foot$prev\">$1$2$3$4"|e;
13706	$footnotes =~ s/<html_this_mark>/$this_mark/;
13707    } else {
13708	&process_footnote($footnote,$mark,$br_id,'','') if $footnote;
13709    }
13710    $_;
13711				   }
13712
13713
13714sub process_footnote {
13715    # Uses $before
13716    # Sets $footfile defined in translate
13717    # Modifies $footnotes defined in translate
13718    local($footnote, $cnt, $br_id, $last_word, $mark, $mini, $same_page) = @_;
13719    local($target) = $target;
13720
13721    # first prepare the footnote-text
13722    local($br_idd, $fcnt); $br_id =~ /\D*(\d+)/; $br_idd = $1;
13723    $footnote = &translate_environments("$O$br_idd$C$footnote$O$br_idd$C")
13724	if ($footnote);
13725    $footnote = &translate_commands($footnote) if ($footnote =~ /\\/);
13726
13727    local($space,$sfoot_style,$efoot_style) = ("\n",'','');
13728    if ((!$NO_FOOTNODE)&&(!$mini)&&(!$target)) {
13729	$footfile = "${PREFIX}$FOOT_FILENAME$EXTN";
13730	$space = ".\n" x 30;
13731	$space = "\n<PRE>$space</PRE>";
13732    } elsif ($target) {
13733	$target = $frame_body_name
13734	    if (($frame_body_name)&&($target eq $frame_foot_name));
13735	$sfoot_style = '<SMALL>';
13736	$efoot_style = '</SMALL>';
13737    }
13738
13739    if ($mark) {
13740	if ($mini) {
13741	    $cnt = $mpfootnotes{$mark};
13742	    if ($in_image) {
13743		$fcnt = $global{'mpfootnote'}; --$fcnt if $fcnt;
13744		$latex_body .= '\setcounter{mpfootnote}{'.($fcnt||"0")."}\n"
13745		    unless ($foot_counters_recorded);
13746	    }
13747	} else {
13748	    $cnt = $footnotes{$mark};
13749	    if ($in_image) {
13750		$fcnt = $global{'footnote'}; --$fcnt if $fcnt;
13751		$latex_body .= '\setcounter{footnote}{'.($fcnt||"0")."}\n"
13752		    unless ($foot_counters_recorded);
13753	    }
13754	}
13755	if ($cnt) {
13756	    &write_warnings("\nredefined target for footnote $mark" )
13757		unless ( $cnt eq $br_id )
13758	}
13759	if ($mini) { $mpfootnotes{$mark} = "$br_id" }
13760	elsif ($br_id =~ /fnm\d+/) {
13761	    $mark = "$footnotes{$cnt}";
13762	    $footnotes{$cnt} = "$br_id";
13763#	    $footnotes .= "\n<DT>$sfoot_style<A NAME=\"foot$br_id\">..."
13764	    $footnotes .= "\n<DT>$sfoot_style<A NAME=\"$br_id\">..."
13765		. $last_word . "</A>$efoot_style</DT>\n<DD>\n"
13766		. $space . "\n</DD>";
13767	    return;
13768	} else { $footnotes{$mark} = "$br_id" }
13769    } else {
13770	if ($mini) {
13771	    $mpfootnotes{$cnt} = "$br_id";
13772	    if ($in_image) {
13773		$fcnt = $global{'mpfootnote'}; --$fcnt if $fcnt;
13774		$latex_body .= '\setcounter{mpfootnote}{'.($fcnt||"0")."}\n"
13775		    unless ($foot_counters_recorded);
13776	    }
13777	} else {
13778	    $footnotes{$cnt} = "$br_id";
13779	    if ($in_image) {
13780		$fcnt = $global{'footnote'}; --$fcnt if $fcnt;
13781		$latex_body .= '\setcounter{footnote}{'.($fcnt||"0")."}\n"
13782		    unless ($foot_counters_recorded);
13783	    }
13784	}
13785    }
13786
13787    # catch a \footnotemark *after* the \footnotetext
13788    if ((!$footnote)&&($last_word)&&(!$mini)) {
13789#	$footnotes .= "\n<DT>$sfoot_style<A NAME=\"foot$br_id\">..."
13790	$footnotes .= "\n<DT>$sfoot_style<A NAME=\"$br_id\">..."
13791	    . $last_word
13792	    . "</A>$efoot_style</DT>\n<DD>\n" . $space . "\n</DD>";
13793
13794    } elsif ($mini) {
13795	if ($HTML_VERSION < 3.0) { $mini .= "." }
13796	$mpfootnotes .= "\n<DD>$sfoot_style<A NAME=\"foot$br_id\">$mini</A> " .
13797	    $footnote . $efoot_style . "\n</DD>\n";
13798    } elsif ($same_page) {
13799	local($link,$text);
13800	$same_page =~ s/:/$text=$`;$link=$';''/e;
13801	$same_page = &make_named_href("","$CURRENT_FILE\#$link",$text) if($link);
13802	$footnotes .= "\n<DT>$sfoot_style<A NAME=\"foot$br_id\">...$last_word</A>"
13803	    . $same_page . $efoot_style . "</DT>\n<DD>" . $sfoot_style
13804	    . $footnote . $efoot_style . "\n". $space . "\n</DD>";
13805    } else {
13806	$footnotes .= "\n<DT>$sfoot_style<A NAME=\"foot$br_id\">...$last_word</A>"
13807		. $efoot_style . "</DT>\n<DD>" . $sfoot_style
13808		. $footnote . "$efoot_style\n" . $space . "\n</DD>";
13809    }
13810				   }
13811
13812
13813sub do_cmd_appendix {
13814    $latex_body .= "\\appendix\n";
13815    if ($section_commands{$outermost_level} == 3) {
13816	$global{'section'} = 0;
13817	&reset_dependents('section');
13818	eval "sub do_cmd_thesection{ &do_cmd_the_appendix(3,\@_) }";
13819    } else {
13820	$global{'chapter'} = 0;
13821	&reset_dependents('chapter');
13822	eval "sub do_cmd_thechapter{ &do_cmd_the_appendix(2,\@_) }";
13823    }
13824    $_[0];
13825				   }
13826
13827sub do_cmd_the_appendix {
13828    local($val,$level) = (0,$_[0]);
13829    if ($level == 3) { $val=$global{'section'} }
13830    elsif ($level == 2) { $val=$global{'chapter'} }
13831    join('', &fAlph($val), '.', $_[1]);
13832				   }
13833
13834sub do_cmd_appendixname { $app_title . $_[0] }
13835sub do_cmd_abstractname { $abs_title . $_[0] }
13836sub do_cmd_keywordsname { $key_title . $_[0] }
13837sub do_cmd_subjclassname { $sbj_title . $_[0] }
13838sub do_cmd_indexname { $idx_title . $_[0] }
13839sub do_cmd_contentsname { $toc_title . $_[0] }
13840sub do_cmd_datename { $date_name . $_[0] }
13841sub do_cmd_refname { $ref_title . $_[0] }
13842sub do_cmd_bibname { $bib_title . $_[0] }
13843sub do_cmd_figurename { $fig_name . $_[0] }
13844sub do_cmd_listfigurename { $lof_title . $_[0] }
13845sub do_cmd_tablename { $tab_name . $_[0] }
13846sub do_cmd_listtablename { $lot_title . $_[0] }
13847sub do_cmd_partname { $part_name . $_[0] }
13848sub do_cmd_chaptername { $chapter_name . $_[0] }
13849sub do_cmd_sectionname { $section_name . $_[0] }
13850sub do_cmd_subsectionname { $subsection_name . $_[0] }
13851sub do_cmd_subsubsectionname { $subsubsection_name . $_[0] }
13852sub do_cmd_paragraphname { $paragraph_name . $_[0] }
13853sub do_cmd_thmname { $thm_title . $_[0] }
13854sub do_cmd_proofname { $prf_name . $_[0] }
13855sub do_cmd_footnotename { $foot_title . $_[0] }
13856sub do_cmd_childlinksname { '<STRONG>'.$child_name.'</STRONG>'. $_[0] }
13857sub do_cmd_infopagename { $info_title . $_[0] }
13858
13859
13860sub do_cmd_ref {
13861    local($_) = @_;
13862    &bprocess_ref('bilink','');
13863				   }
13864
13865sub do_cmd_eqref {
13866    local($_) = @_;
13867    join('','(',&process_ref($cross_ref_mark,$cross_ref_mark,'',')'));
13868				   }
13869
13870sub do_cmd_pageref {
13871    local($_) = @_;
13872    &process_ref($cross_ref_mark,$cross_ref_visible_mark);
13873				   }
13874
13875# This is used by external style files ...
13876sub process_ref {
13877    local($ref_mark, $visible_mark, $use_label, $after_label) = @_;
13878    $use_label = &balance_inner_tags($use_label)
13879	if $use_label =~ (/<\/([A-Z]+)>($math_verbatim_rx.*)<\1>/);
13880    $use_label = &translate_environments($use_label);
13881    $use_label = &simplify(&translate_commands($use_label))
13882	if ($use_label =~ /\\/ );
13883    local($label,$id);
13884    local($pretag) = &get_next_optional_argument;
13885    $pretag = &translate_commands($pretag) if ($pretag =~ /\\/);
13886    $label = &missing_braces unless (
13887	(s/$next_pair_pr_rx/($id, $label) = ($1, $2);''/eo)
13888	||(s/$next_pair_rx/($id, $label) = ($1, $2);''/eo));
13889    if ($label) {
13890	$label =~ s/<[^>]*>//go ; #RRM: Remove any HTML tags
13891	$label =~ s/$label_rx/_/g;	# replace non alphanumeric characters
13892
13893	$symbolic_labels{"$pretag$label$id"} = $use_label if ($use_label);
13894	if (($symbolic_labels{$pretag.$label})&&!($use_label)) {
13895	    $use_label = $symbolic_labels{$pretag.$label}
13896	}
13897#	if (!($use_label eq $label)) {
13898#	    $symbolic_labels{"$label$id"} = $use_label;
13899#	};
13900     	# if $use_label is empty then $label is used as the cross_ref_mark
13901	# elseif $use_label is a string then $use_label is used
13902        # else the usual mark will be used
13903	$use_label = ( (!$use_label && $label) || $use_label);
13904
13905	print "\nLINK: $ref_mark\#$label\#$id  :$use_label:" if ($VERBOSITY > 3);
13906	# The quotes around the HREF are inserted later
13907	join('',"<A HREF=$ref_mark#$label#$id>$visible_mark<\/A>",$after_label, $_);
13908    }
13909    else {
13910	print "Cannot find label argument after <$last_word>\n" if $last_word;
13911	$after_label . $_;
13912    }
13913				   }
13914
13915#RRM:  This removes unbalanced tags, due to closures for math inside
13916#      the label-text for an <A> anchor.
13917sub balance_inner_tags {
13918    local($text) = @_;
13919    return($text) unless ($text =~ /<\/([A-Z]+)>(\s*$math_verbatim_rx.*)(<\1( [^>]*)?>)/);
13920    local($beforeT,$afterT,$tag,$math_verb,$stag) = ($`,$',$1,$2,$3);
13921    if (!($beforeT =~ /<$tag>/)) {
13922	$text = join('', $beforeT, $math_verb, $afterT);
13923	return (&balance_inner_tags($text));
13924    }
13925    local(@pieces) = split (/<$tag>/, $beforeT );
13926    $beforeT = shift (@pieces);
13927    local($cnt,$this) = (0,'');
13928    while (@pieces) {
13929	$this = shift @pieces;
13930	$cnt++;
13931	$beforeT .= "<$tag>".$this;
13932	$cnt = $cnt - ($this =~ /<\/$tag>/g);
13933    }
13934    if ($cnt) {
13935	$beforeT .= "<\/$tag>" . $math_verb . $stag;
13936	$text = $beforeT . $afterT;
13937    } else {
13938	$beforeT .= $math_verb;
13939	$text = join('', $beforeT, $math_verb, $afterT);
13940	return (&balance_inner_tags($text));
13941    }
13942    $text;
13943				   }
13944
13945# Uses $CURRENT_FILE defined in translate
13946sub do_cmd_label {
13947    local($_) = @_;
13948    local($label);
13949    $label = &missing_braces unless (
13950	(s/$next_pair_pr_rx\n?/$label = $2;''/eo)
13951	||(s/$next_pair_rx\n?/$label = $2;''/eo));
13952    &anchor_label($label,$CURRENT_FILE,$_);
13953				   }
13954
13955# This subroutine is also used to process labels in undefined environments
13956sub anchor_label { &real_anchor_label(@_) }
13957sub real_anchor_label {
13958    # Modifies entries in %ref_files defined in translate
13959    local($label,$filename,$context) = @_;
13960    $label =~ s/<[^>]*>//go;	#RRM: Remove any HTML tags
13961    $label =~ s/$label_rx/_/g;	# replace non alphanumeric characters
13962    # Associate the label with the current file
13963    if ($ref_files{$label} ne $filename) {
13964	$ref_files{$label} = $filename;
13965	$noresave{$label} = 0; $changed = 1; }
13966    print "<LABEL: $label>" if ($VERBOSITY > 3);
13967    join('',"<A NAME=\"$label\">$anchor_mark</A>",$context);
13968}
13969
13970sub do_cmd_cite {
13971    local($_) = @_;
13972    &process_cite('','');
13973				   }
13974
13975
13976# This just creates a link from a label (yet to be determined) to the
13977# cite_key in the citation file.
13978sub process_cite { &process_real_cite(@_) }
13979sub process_real_cite {
13980    local($mode,$text) = @_;
13981    my $has_text = (($text)? 1 : 0);
13982#    local($target) = 'contents';print "\nCITE:$text";
13983    # process the text from \htmlcite or \hypercite
13984    if ($has_text) {
13985	$text = &balance_inner_tags($text)
13986	    if $use_label =~ (/<\/([A-Z]+)>($math_verbatim_rx.*)<\1>/);
13987	$text = &translate_environments($text);
13988	$text = &simplify(&translate_commands($text))
13989	    if ($use_label =~ /\\/ );
13990    }
13991
13992    my $label, $cite_key, $pretag, @cite_keys;
13993    local($optional_text,$dummy) =  &get_next_optional_argument;
13994    if ($mode =~ /external/) {
13995#	$target = '';
13996	$pretag = $optional_text; $optional_text = '';
13997	$pretag = &translate_commands($pretag) if ($pretag =~ /\\/);
13998    } else {
13999	$optional_text = ", $optional_text" if $optional_text;
14000    }
14001    s/^\s*\\space//o;		# Hack - \space is inserted in .aux
14002    s/$next_pair_pr_rx//o||s/$next_pair_rx//o;
14003    if (!($cite_key = $2)) {
14004	print "\n *** Cannot find citation argument\n";
14005	return ($_);
14006    }
14007    @cite_keys = (split(/,/,$cite_key));
14008    my ($citations, $join) = ('',',');
14009    $join  = '' if ($text);
14010    foreach $cite_key (@cite_keys) {
14011	$cite_key =~ s/(^\s+|\s+$)//g;
14012	$cite_key =~ s/(^\s+|\s+$)//g;
14013    # RRM:  if the URL and printable-key are known already, then use them...
14014	$cite_key =~ s/$label_rx/_/g;
14015	$label = $cite_key;
14016	if ($mode eq "nocite") {
14017	    # nothing more to do, no citations
14018	} elsif ( ($SEGMENT) && ($cite_info{$cite_key})
14019		&& ($ref_files{"cite_$cite_key"}) ) {
14020	    $join  = "," unless ($text);
14021	    $text = $cite_info{$cite_key} unless ($text);
14022	    $citations .= join('', $join
14023		, &make_named_href($label,$ref_files{'cite_'."$cite_key"},$text));
14024	} elsif (($mode eq "external")&&($external_labels{$pretag."cite_$cite_key"})) {
14025	    $join  = "," unless ($text);
14026	    $text = $cross_ref_visible_mark unless ($text);
14027	    $citations .= join('', $join
14028		, &make_named_href($label
14029		    , $external_labels{$pretag.'cite_'."$cite_key"}."\#$label"
14030		    , $text)
14031		);
14032	} elsif ($mode eq 'external') {
14033	    $join  = "," unless ($text);
14034	    &write_warnings("\nExternal reference missing for citation: $pretag$cite_key");
14035	    $citations .= "$text$join#!$pretag$cite_key!#";
14036        } else {
14037	    $join  = "," unless ($text);
14038	    #Replace the key...
14039	    $citations .= "$join#$cite_key#$cite_mark#$bbl_nr#$text#$cite_mark#";
14040        }
14041	$text = '';
14042    }
14043    $citations =~ s/^\s*,\s*//;
14044    if ($has_text) { join('', $citations,  $optional_text, $_) }
14045    else { join('', "[", $citations,  $optional_text, "]", $_) }
14046				   }
14047
14048sub do_cmd_index { &do_real_index(@_) }
14049sub do_real_index {
14050    local($_) = @_;
14051    local($br_id, $str);
14052    local($idx_option) = &get_next_optional_argument;
14053    $str = &missing_braces unless (
14054	(s/$next_pair_pr_rx/($br_id, $str) = ($1, $2);''/eo)
14055	||(s/$next_pair_rx/($br_id, $str) = ($1, $2);''/eo));
14056    join('',&make_index_entry($br_id,$str),$_);
14057				   }
14058sub do_cmd_indexstar { &do_cmd_index(@_) }
14059
14060# RRM: \bibcite supplies info via the .aux file; necessary with segmented docs.
14061sub do_cmd_bibcite {
14062    local($_) = @_;
14063    local($br_id, $cite_key,$print_key);
14064    $cite_key = &missing_braces unless (
14065	(s/$next_pair_pr_rx/($br_id, $cite_key) = ($1, $2);''/eo)
14066	||(s/$next_pair_rx/($br_id, $cite_key) = ($1, $2);''/eo));
14067    $print_key = &missing_braces unless (
14068	(s/$next_pair_pr_rx/($br_id, $print_key) = ($1, $2);''/eo)
14069	||(s/$next_pair_rx/($br_id, $print_key) = ($1, $2);''/eo));
14070    $cite_key =~ s/$label_rx/_/g;
14071    $cite_info{$cite_key} = $print_key;
14072    $_;
14073				   }
14074
14075# This command will only be encountered inside a thebibliography environment.
14076sub do_cmd_bibitem { &do_real_bibitem($CURRENT_FILE, @_) }
14077sub do_real_bibitem {
14078    local($thisfile, $_) = @_;
14079    # The square brackets may contain the label to be printed
14080    local($label, $dummy) = &get_next_optional_argument;
14081    # Support for the "named" bibliography style
14082    if ($label) {
14083 	$label =~ s/\\protect//g;
14084 	$label = &translate_commands($label) if ($label =~ /\\/);
14085    }
14086    local($cite_key);
14087    $cite_key = &missing_braces unless (
14088	( s/$next_pair_pr_rx/$cite_key=$2;''/e )
14089	||( s/$next_pair_rx/$cite_key=$2;''/e ));
14090
14091    $cite_key =~ s/$label_rx/_/g;
14092    $label = $cite_info{$cite_key} unless $label; # read from .aux file
14093    $label = ++$bibitem_counter unless $label; # Numerical labels
14094
14095    if ($cite_key) {
14096	# Associate the cite_key with the printed label.
14097	# The printed label will be substituted back into the document later.
14098	$cite_info{$cite_key} = &translate_commands($label);
14099	if (!($ref_files{'cite_'."$cite_key"} eq $thisfile)) {
14100	    $ref_files{'cite_'."$cite_key"} = $thisfile;
14101	    $changed = 1; }
14102
14103        #RRM: apply any special styles, as defined below
14104	$label = &bibitem_style($label) if (defined &bibitem_style);
14105	# Create an anchor around the citation
14106	join('',"<P></P><DT><A NAME=\"$cite_key\">$label</A>\n<DD>", $_);
14107
14108    } else {
14109	print "Cannot find bibitem labels: $label\n";
14110
14111	#RRM: apply any special styles, as defined below
14112	$label = &bibitem_style($label) if (defined &bibitem_style);
14113	join('',"<P></P><DT>$label\n<DD>", $_); # AFEB added this line
14114    }
14115				   }
14116
14117#RRM: override this with a personal style, defined in  .latex2html-init
14118#sub bibitem_style { join('','<STRONG>',$_[0],'</STRONG>') }
14119sub bibitem_style {
14120    return ($_[0]) unless $BIBITEM_STYLE;
14121    local($text) = join(''
14122	,"${O}0$C",$BIBITEM_STYLE,"${O}1$C", @_, "${O}1$C","${O}0$C");
14123    $text = &translate_environments($text);
14124    &translate_commands($text);
14125				   }
14126
14127sub do_cmd_newblock {
14128    "<BR>".$_[0]
14129				   }
14130
14131# This just reads in the $FILE.bbl file if it is available and appends
14132# it to the items that are still to be processed.
14133# The $FILE.bbl should contain a thebibliography environment which will
14134# cause its contents to be processed later in the appropriate way.
14135# (Note that it might be possible for both the \bibliography command and
14136# the thebibliography environment to be present as the former may have been
14137# added by the translator as a sectioning command. In this case (both present)
14138# the $citefile would have already been set by the thebibliography environment)
14139
14140sub do_cmd_bibliography { &do_real_bibliography($CURRENT_FILE, @_) }
14141sub do_real_bibliography {
14142    local($thisfile, $after) = @_;
14143    if ((defined &do_cmd_bibname)||$new_command{'bibname'}) {
14144	local($br_id)=++$global{'max_id'};
14145	$TITLE = &translate_environments("$O$br_id$C\\bibname$O$br_id$C");
14146    } else { $TITLE = $bib_title }
14147    $toc_sec_title = $TITLE;
14148    return($_[0]) if ($making_name);
14149    local($bibfile);
14150    $bibfile = &missing_braces unless (
14151	($after =~ s/$next_pair_rx/$bibfile=$2;''/eo)||
14152	($after =~ s/$next_pair_rx_rx/$bibfile=$2;''/eo));
14153
14154    do {
14155	unless ($citefile) {
14156	    $citefile = $thisfile;
14157	    if (&process_ext_file("bbl")) { # *** BINDS $_ as a side effect ***
14158		$after = join('',$_,$after);}
14159	    else {
14160		print "\nCannot open $FILE.bbl $!\n";
14161		&write_warnings("\nThe bibliography file was not found.");
14162		$after = join('',"\n<H2>No References!</H2>", $after);
14163	    }
14164	}
14165    print "\n";
14166    } if $bibfile;
14167    $after;
14168				   }
14169
14170# allow for customised info-pages, for different languages
14171sub do_cmd_textohtmlinfopage {
14172    local($_) = @_;
14173    local($linfo) = $TITLES_LANGUAGE . '_infopage';
14174    if (defined &$linfo) { eval "&$linfo"; }
14175    else { &default_textohtmlinfopage }
14176				   }
14177
14178sub default_textohtmlinfopage {
14179    local($_) = @_;
14180    local($argv) = $argv;
14181    if (-f "../$argv") { $argv = &make_href ("../$argv", $argv, ); }
14182    $_ = ($INFO && $INFO =~ /^\d+$/
14183      ? join('', $close_all
14184	, "<STRONG>$t_title</STRONG><P>\nThis document was generated using the\n"
14185	, "<A HREF=\"$TEX2HTMLADDRESS\"><STRONG>LaTeX</STRONG>2<tt>HTML</tt></A>"
14186	, " translator Version $TEX2HTMLVERSION\n"
14187	, "<P>Copyright &#169; 1993, 1994, 1995, 1996,\n"
14188	, "Nikos Drakos, \n"
14189	, "Computer Based Learning Unit, University of Leeds.\n"
14190	, "<BR>Copyright &#169; 1997, 1998, 1999,\n"
14191	, "<A HREF=\"$AUTHORADDRESS2\">Ross Moore</A>, \n"
14192	, "Mathematics Department, Macquarie University, Sydney.\n"
14193	, "<P>The command line arguments were: <BR>\n "
14194	, "<STRONG>latex2html</STRONG> <TT>$argv</TT>\n"
14195	, (($SHOW_INIT_FILE && ($INIT_FILE ne ''))?
14196	   "\n<P>with initialization from: <TT>$INIT_FILE</TT>\n$init_file_mark\n" :'')
14197	, "<P>The translation was initiated by $address_data[0] on $address_data[1]"
14198	, $open_all, $_)
14199      : join('', $close_all, "$INFO\n", $open_all, $_));
14200    $_;
14201				   }
14202
14203
14204# Try to translate LaTeX vertical space in a number of <BR>'s.
14205# Eg. 1cm results in one + two extra <BR>'s.
14206# To help the browser rendering is quite ugly, but why not.
14207#
14208sub get_vspace {
14209    local($_) = @_;
14210    local($vh) = 0;
14211
14212    return("<BR>") if /-/;
14213
14214    $vh = int($1 * $vspace_12pt{$2} + 0.5)
14215	if (/([0-9.]+)\s*([a-z]+)/);
14216    join('',"<BR>","\n<BR>" x $vh);
14217				   }
14218
14219sub do_cmd_vskip {
14220    local($_) = @_;
14221    &ignore_numeric_argument;
14222    join('',&get_vspace($1),$_);
14223				   }
14224
14225sub do_cmd_break {
14226    local($_) = @_;
14227    join('',"<BR>",$_);
14228				   }
14229
14230sub do_cmd_vspace {
14231    local($_) = @_;
14232    local($how_much);
14233    $how_much = &missing_braces unless (
14234	(s/$next_pair_pr_rx/$how_much = $2;''/e)
14235	||(s/$next_pair_rx/$how_much = $2;''/e));
14236    join('',&get_vspace($how_much),$_);
14237}
14238
14239sub do_cmd_vspacestar {
14240    &do_cmd_vspace;
14241}
14242
14243sub do_cmd_d_backslash {
14244    local($_) = @_;
14245
14246    # Eat space from &pre_process.
14247    # We could also modifiy $single_cmd_rx and %normalize, but why not here.
14248    s/^ \*?//;
14249    local($spc,$dum)=&get_next_optional_argument;
14250    # If the [...] occurs on the next line, then it is *not* an argument to \\ .
14251    # MRO: replaced $* with /m
14252    if ($dum =~ /\n/m) {
14253	$spc = $`;
14254        $spc =~ s/\s//gm;
14255        $_ = $'.$_
14256    }
14257    join('',(($spc)? &get_vspace($spc): "\n<BR>"),$_);
14258				   }
14259
14260
14261################## Commands used in the $FILE.aux file #######################
14262
14263sub do_cmd_jobname { $FILE . $_[0] }
14264
14265# This is used in $FILE.aux
14266sub do_cmd_newlabel {
14267    local($_) = @_;
14268    local($label,$val,$tmp);
14269    $label = &missing_braces unless (
14270	(s/$next_pair_pr_rx/$label = $2;''/eo)
14271	||(s/$next_pair_rx/$label = $2;''/eo));
14272    $tmp = &missing_braces unless (
14273	(s/$next_pair_pr_rx/$tmp=$2;''/eo)
14274	||(s/$next_pair_rx/$tmp=$2;''/eo));
14275    $val = &missing_braces unless (
14276	($tmp =~ s/$next_pair_pr_rx/$val=$2;''/eo)
14277	||($tmp =~ s/$next_pair_rx/$val=$2;''/eo));
14278    $val =~ s/(^\s+|\s+$)//gs;
14279    $label =~ s/$label_rx/_/g;	# Replace non alphanumeric characters
14280    $latex_labels{$label} = $val;
14281    &do_labels_helper($label);
14282    $_;
14283				   }
14284sub do_cmd_oldnewlabel { &do_cmd_newlabel(@_) }
14285
14286#
14287# Sets %encoded_(section|figure|table)_number, which maps encoded
14288# section titles to LaTeX numbers
14289# .= \$number . \"$;\"";
14290sub do_cmd_oldcontentsline { &do_cmd_contentsline(@_) }
14291sub do_cmd_contentsline {
14292    local($_) = @_;
14293    local($arg,$after,$title,$number,$hash,$stype,$page);
14294    # The form of the expression is:
14295    # \contentsline{SECTION} {... {SECTION_NUMBER} TITLE}{PAGE}
14296    $stype = &missing_braces unless (
14297        (s/$next_pair_pr_rx/$stype = $2;''/e)
14298        ||(s/$next_pair_rx/$stype = $2;''/e));
14299    $arg = &missing_braces unless (
14300        (s/$next_pair_pr_rx/$arg = $2;''/e)
14301        ||(s/$next_pair_rx/$arg = $2;''/e));
14302    $page = &missing_braces unless (
14303        (s/$next_pair_pr_rx/$page = $2;''/e)
14304        ||(s/$next_pair_rx/$page = $2;''/e));
14305
14306#    s/$any_next_pair_pr_rx/$stype = $2;''/eo; # Chop off {SECTION}
14307#    s/$any_next_pair_pr_rx/$arg   = $2;''/eo; # Get {... {SECTION_NUMBER} TITLE}
14308#    s/$any_next_pair_pr_rx/$page  = $2;''/eo; # Get page number
14309    $hash = $stype if (($stype =~ /^(figure|table)$/)||($SHOW_SECTION_NUMBERS));
14310    $hash =~ s/(sub)*(section|chapter|part)/section/;
14311    $after = $_;
14312    if ($hash) {
14313	if ($arg =~ /^$OP/) {
14314	    $number = &missing_braces unless (
14315		($arg =~ s/$next_pair_pr_rx/$number = $2;''/eo)
14316		||($arg =~ s/$next_pair_rx/$number = $2;''/eo));
14317	}
14318	if ($stype eq "part") {
14319 	    while ($arg =~ s/$next_pair_pr_rx//o) {};
14320  	    $number =~ tr/a-z/A-Z/;
14321   	    $number = "Part $number:"}
14322	# This cause problem when picking figure numbers...
14323	# while ($tmp =~ s/$next_pair_pr_rx//o) {};
14324	$number = -1 unless $number;
14325#JCL(jcl-tcl)
14326##	$_ = $arg;
14327#	$title = &sanitize($arg);
14328##	&text_cleanup;
14329##	$title = &encode_title($_);
14330##
14331	#remove surrounding brace-numbering
14332	$arg =~ s/^($O|$OP)\d+($C|$CP)|($O|$OP)\d+($C|$CP)$//g;
14333	$arg =~ s/\\footnote(mark|text)?//g;
14334	# \caption arguments should have had environments translated already
14335	$arg = &translate_environments($arg) if ($arg =~ /\\begin/);
14336	#replace image-markers by the image params
14337	$arg =~ s/$image_mark\#([^\#]+)\#/&purify_caption($1)/e;
14338
14339	#RRM: resolve any embedded cross-references first
14340	local($checking_caption) = 1;
14341	$title = &simplify($arg);
14342	$title = &sanitize($title);
14343	$checking_caption = '';
14344	eval "\$encoded_${hash}_number{\$title} .= \$number . \"$;\"";
14345    }
14346    $after;
14347				   }
14348
14349#
14350#  Before normalizing this was \@input.  Used in .aux files.
14351#
14352sub do_cmd__at_input {
14353    local ($_) = @_;
14354    local ($file, $after);
14355    $file = &missing_braces unless (
14356	(s/$next_pair_pr_rx/$file=$2;''/eo)
14357	||(s/$next_pair_rx/$file=$2;''/eo));
14358    local($prefix, $suffix) = split(/\./, $file);
14359    $after = $_;
14360    local($EXTERNAL_FILE) = $prefix;
14361    &process_ext_file($suffix);
14362    $after;
14363				   }
14364
14365
14366########################### Counter Commands #################################
14367# Removes the definition from the input string, adds to the preamble
14368# and stores the body in %new_counter;
14369sub get_body_newcounter {
14370#    local(*_) = @_;
14371    local($after_R) = @_;
14372    local($_) = $$after_R;
14373    local($within,$ctr,$cmd,$tmp,$body,$pat);
14374    local($new_ctr) = 'counter';
14375    ($ctr,$pat) = &get_next(1);	# Get counter name
14376    &write_warnings ("\n*** LaTeX Error: backslash found in counter-name: $ctr")
14377	if ($pat =~ s/\\//);
14378    $ctr =~ s/^\s*\\//;
14379    $new_ctr .= $pat;
14380
14381    ($within,$pat) = &get_next(0);	# Get optional within, currently ignored
14382    &addto_dependents($within,$ctr);
14383    $new_ctr .= $pat;
14384    do {
14385###	local($_) = "\\arabic<<1>>$ctr<<1>>";
14386	$body = "\\arabic<<1>>$ctr<<1>>";
14387	&make_unique($body);
14388	$cmd = "the$ctr";
14389	$tmp = "do_cmd_$cmd";
14390	$new_command{$cmd} = join(':!:',0,$body,'}') unless (defined &$tmp);
14391	    &write_mydb("new_command", $cmd, $new_command{$cmd});
14392	undef $body;
14393    };
14394    &do_body_newcounter($ctr);
14395
14396    $$after_R = $_;
14397    if (!$PREAMBLE) {
14398	my $new_cmd = join(''
14399	    , "counter{$ctr}", ($within ? "[$within]" : '') );
14400	&add_to_preamble('counter','\\new'.$new_cmd);
14401	return ();
14402    }
14403    'newed'.$new_ctr;
14404				   }
14405
14406sub do_body_newcounter {
14407    local($ctr) = @_;
14408    $latex_body .= &revert_to_raw_tex("\\newcounter{$ctr}\n")
14409	unless ($preamble =~ /\\new(counter|theorem){$ctr}/);
14410    $global{$ctr} = 0;
14411    &process_commands_wrap_deferred("the$ctr ");
14412    $_;
14413				   }
14414
14415
14416#RRM: This doesn't work properly yet.
14417#     The new booleans need to be stored for use in all partitions.
14418#     \if... \else  \fi  is not yet implemented.
14419
14420sub get_body_newboolean {
14421#    local(*_) = @_;
14422    local($after_R) = @_;
14423    local($_) = $$after_R;
14424    my $bool;
14425    $bool = &missing_braces unless (
14426	(s/$next_pair_pr_rx/$bool=$2;''/e)
14427	||(s/$next_pair_rx/$bool=$2;''/e));
14428    $bool =  &process_body_newif('',$bool);
14429    $$after_R = $_;
14430    'newed'.$bool;
14431				   }
14432
14433sub get_body_newif {
14434#    local(*_) = @_;
14435    local($after_R) = @_;
14436    local($_) = $$after_R;
14437    local($bool);
14438    if (!(s/^\s*\\if([a-zA-Z]+)//)) {
14439	$$after_R = $_;
14440	return();
14441    }
14442    $bool = $1;
14443    $$after_R = $_;
14444    join('','newed', &process_body_newif('', $bool));
14445				   }
14446
14447
14448sub process_body_newif {
14449    local($texif, $bool) = @_;
14450    local($body,$ifbool,$cmd,$tmp,$pat);
14451
14452#    ($bool,$pat) = &get_next(1);	# Get boolean name
14453
14454#    # change the brace-type around the command-name
14455#    $pat =~ s/$O/$OP/; $pat =~ s/$C/$CP/; $new_cmd .= $pat;
14456
14457    $ifbool = "if".$bool;
14458    $global{$ifbool} = 0;
14459
14460    do {
14461	$body = "\$global{'$ifbool'} = 1;";
14462	$cmd = $bool."true";
14463	$code = "sub do_cmd_$cmd { ".$body." \$_[0];}";
14464	eval $code;
14465	print STDERR "\n*** sub do_cmd_$cmd failed:\n$@\n" if ($@);
14466	$raw_arg_cmds{$cmd} = 1;
14467
14468	$body = "\$global{$ifbool} = 0;";
14469	$cmd = $bool."false";
14470	$code = "sub do_cmd_$cmd { ".$body." \$_[0];}";
14471	eval $code;
14472	print STDERR "\n*** sub do_cmd_$cmd failed:\n$@\n" if ($@);
14473	$raw_arg_cmds{$cmd} = 1;
14474
14475	undef $body;
14476    };
14477    &process_commands_wrap_deferred("${bool}true\n${bool}false\nif$bool\n");
14478
14479#    $latex_body .= &revert_to_raw_tex("\\newif\\$ifbool\n")
14480#	unless ($preamble =~ /\\newif\s*\\$ifbool/);
14481
14482    if (!$PREAMBLE) {
14483	local($new_cmd) = "boolean{\\$bool}";
14484	&add_to_preamble ('newif', "\\new$new_cmd" );
14485	return ();
14486    }
14487    local($br_id) = ++$global{'max_id'};
14488    'boolean'."$O$br_id$C$bool$O$br_id$C";
14489				   }
14490
14491
14492sub do_cmd_value {
14493    local($_) = @_;
14494    local($ctr,$val);
14495    $ctr = &missing_braces
14496	unless ((s/$next_pair_pr_rx/$ctr = $2;''/eo)
14497	      ||(s/$next_pair_rx/$ctr = $2;''/eo));
14498    $val = &get_counter_value($ctr);
14499    if ($val) { $val.$_ }
14500    else { join(''," 0",$_) }
14501				   }
14502
14503sub do_cmd_boolean {
14504    local($_) = @_;
14505    local($bool,$val);
14506    $bool = &missing_braces
14507	unless ((s/$next_pair_pr_rx/$bool = $2;''/eo)
14508	      ||(s/$next_pair_rx/$bool = $2;''/eo));
14509    $val = &get_boolean_value($bool);
14510    if ($val) { $val.$_ }
14511    else { "0".$_ }
14512				   }
14513
14514sub get_counter_value {
14515    local($ctr) = @_;
14516    local($val,$index);
14517    $ctr = 'eqn_number' if ($ctr eq "equation");
14518    $index = $section_commands{$ctr};
14519
14520    if (defined $global{$ctr}) { $val= $global{$ctr}; }
14521    elsif (($SEGMENT)&&($index)) {
14522	$val = $segment_sec_id[$index]
14523#    if ($index) {
14524#	if ($SEGMENT) { $val = $segment_sec_id[$index] }
14525#	else { $val = $curr_sec_id[$index] }
14526    } else {
14527	&write_warnings ("\ncounter $ctr not defined");
14528	$val= 0;
14529    }
14530    print "\nVAL:$ctr: $val " if ($VERBOSITY > 3);
14531    $val;
14532				   }
14533
14534sub get_boolean_value {
14535    local($bool) = @_;
14536    local($val,$index);
14537    if (defined $global{$bool}) { $val= $global{$bool} }
14538    else {
14539	&write_warnings ("boolean $bool not defined\n");
14540	$val="0";
14541    }
14542    print "\nBOOL:$bool: $val " if ($VERBOSITY > 3);
14543    $val;
14544				   }
14545
14546sub do_cmd_addtocounter {
14547    local($_) = @_;
14548    local($ctr,$num,$index);
14549    $ctr = &missing_braces
14550	unless ((s/$next_pair_rx/$ctr = $2;''/eo)
14551	      ||(s/$next_pair_pr_rx/$ctr = $2;''/eo));
14552    $num = &missing_braces
14553	unless ((s/$next_pair_rx/$num = $2;''/eo)
14554	      ||(s/$next_pair_pr_rx/$num = $2;''/eo));
14555
14556    $num = &translate_commands($num) if ($num =~ /\\/);
14557    if ($num !~ /^\s*(\+|-)?\d+\s*$/) {
14558        print STDERR "\n*** cannot set counter $ctr to $num ***\n";
14559        return($_);
14560    }
14561
14562    $latex_body .= &revert_to_raw_tex("\\addtocounter{$ctr}{$num}\n");
14563    print "PCT: do_cmd_addtocounter: index: $index\n" if ($VERBOSITY > 5) ;
14564    print "PCT: do_cmd_addtocounter: SEGMENT: $SEGMENT\n" if ($VERBOSITY > 5) ;
14565    print "PCT: do_cmd_addtocounter: section_commands: $section_commands\n" if ($VERBOSITY > 5) ;
14566    print "PCT: do_cmd_addtocounter: ctr: $ctr --- num: $num\n" if ($VERBOSITY > 5) ;
14567    print join('',"PCT: do_cmd_addtocounter: global:",$global{$ctr},"\n") if ($VERBOSITY > 5) ;
14568    $index = $section_commands{$ctr};
14569
14570    if (defined $global{$ctr}) {
14571	$global{$ctr} += $num }
14572    elsif ($index) {
14573	if ($SEGMENT) {
14574	    $segment_sec_id[$index] += $num
14575	}
14576	else {
14577	    $curr_sec_id[$index] += $num
14578	}
14579	$global{$ctr} += $num;
14580    }
14581    elsif ($ctr eq "equation") {
14582	$global{'eqn_number'} += $num
14583    }
14584    else {
14585	$global{$ctr} += $num
14586    }
14587    print "\nADD:$ctr:+$num= ". $global{$ctr}." " if ($VERBOSITY > 3);
14588    $_;
14589				   }
14590
14591sub do_cmd_setcounter {
14592    local($_) = @_;
14593    local($ctr,$num,$index,$sctr);
14594    $ctr = &missing_braces
14595	unless ((s/$next_pair_rx/$ctr = $2;''/eo)
14596	      ||(s/$next_pair_pr_rx/$ctr = $2;''/eo));
14597    $num = &missing_braces
14598	unless ((s/$next_pair_rx/$num = $2;''/eo)
14599	      ||(s/$next_pair_pr_rx/$num = $2;''/eo));
14600
14601    $num = &translate_commands($num) if ($num =~ /\\/);
14602    if ($num !~ /^\s*(\+|-)?\d+\s*$/) {
14603	print STDERR "\n*** cannot set counter $ctr to $num ***\n";
14604	return($_);
14605    }
14606    if ($ctr =~ /^l/) {
14607	$sctr = $';
14608	$ctr = $sctr if $section_commands{$sctr};
14609    }
14610    if (! $AUX_FILE && !($ctr =~ /page/ )) {
14611	$latex_body .= &revert_to_raw_tex("\\setcounter{$ctr}{$num}\n");
14612	$index = $section_commands{$ctr};
14613	if ($index) {
14614	    if ($curr_sec_id[$index] <= $num ) {
14615		$curr_sec_id[$index] = $num
14616	    } else {
14617		print "\nignoring \\setcounter{$ctr}{$num} currently at ",$curr_sec_id[$index] ;
14618		&write_warnings(join('',"\n\\setcounter{$ctr}{$num} ignored,"
14619			," cannot reduce from ",$curr_sec_id[$index]));
14620	    }
14621	    $global{$ctr} = $num;
14622	} elsif ($ctr eq "equation") {$global{'eqn_number'} = $num }
14623	else { $global{$ctr} = $num };
14624    }
14625    print "\nSET:$ctr: = $num" if ($VERBOSITY > 3);
14626#    &reset_dependents($ctr) if ($dependent{$ctr});
14627    $_;
14628}
14629
14630sub do_cmd_setlength {
14631    local($_) = @_;
14632    local($dimen,$value,$index,$sctr);
14633    $dimen = &missing_braces
14634	unless ((s/$next_pair_rx/$dimen = $2;''/eo)
14635	      ||(s/$next_pair_pr_rx/$dimen = $2;''/eo));
14636    $value = &missing_braces
14637	unless ((s/$next_pair_rx/$value = $2;''/eo)
14638	      ||(s/$next_pair_pr_rx/$value = $2;''/eo));
14639
14640    # recognise specific length-parameters
14641    if ($dimen =~ /captionwidth/) {
14642	local($pxs,$len) = &convert_length($value, $MATH_SCALE_FACTOR);
14643	$cap_width = $pxs if ($pxs &&($dimen =~ /captionwidth/));
14644    }
14645    if ((! $AUX_FILE)&&(! $PREAMBLE)) {
14646	$latex_body .= &revert_to_raw_tex("\\setlength{$dimen}{$value}\n");
14647	print "\nSETLENGTH:$dimen = $value" if ($VERBOSITY > 3);
14648    }
14649    $_;
14650}
14651
14652				     sub do_cmd_setboolean {
14653    local($_) = @_;
14654    local($bool,$val);
14655    $bool = &missing_braces
14656	unless ((s/$next_pair_rx/$bool = $2;''/eo)
14657	      ||(s/$next_pair_pr_rx/$bool = $2;''/eo));
14658    $val = &missing_braces
14659	unless ((s/$next_pair_rx/$val = $2;''/eo)
14660	      ||(s/$next_pair_pr_rx/$val = $2;''/eo));
14661    if (! $AUX_FILE) {
14662	$latex_body .= &revert_to_raw_tex("\\setboolean{$bool}{$val}\n");
14663	$global{"if$bool"} = (($val = ~/true/) ? 1 : 0);
14664	print "\nSETBOOL:$bool = $val" if ($VERBOSITY > 3);
14665    }
14666    $_;
14667}
14668
14669sub do_cmd_endsegment {
14670    local($_) = @_;
14671    local($ctr,$dum) = &get_next_optional_argument;
14672    local($index,$steps) = ('',1);
14673#    $steps = &missing_braces unless (
14674#	(s/$next_pair_pr_rx/$steps = $2;''/e)
14675#	||(s/$next_pair_rx/$steps = $2;''/e));
14676    $index = $section_commands{$ctr} if $ctr;
14677#    if ($index) { $curr_sec_id[$index] += $steps }
14678#    if ($index) { ($after_segment,$after_seg_num) = ($index,$steps) }
14679    if ($index) { ($after_segment,$after_seg_num) = ($index,1) }
14680    $_;
14681}
14682
14683sub do_cmd_stepcounter {
14684    local($_) = @_;
14685    local($ctr,$index);
14686    $ctr = &missing_braces
14687	unless ((s/$next_pair_rx/$ctr = $2;''/eo)
14688	      ||(s/$next_pair_pr_rx/$ctr = $2;''/eo));
14689    if (! $AUX_FILE) {
14690	$latex_body .= &revert_to_raw_tex("\\stepcounter{$ctr}\n");
14691	$index = $section_commands{$ctr};
14692	if ($index) {
14693#	    if ($SEGMENT) { $segment_sec_id[$index] += 1 }
14694#	    else { $curr_sec_id[$index] += 1 }
14695	    $global{$ctr} += 1;
14696	} elsif ($ctr eq "equation") { $global{'eqn_number'} += 1 }
14697	else { $global{$ctr} += 1 };
14698    }
14699    print "\nSTP:$ctr:+1" if ($VERBOSITY > 3);
14700    &reset_dependents($ctr) if ($dependent{$ctr});
14701    $_;
14702}
14703
14704#RRM:   dependent counters are stored as a comma-separated list
14705#       in the %dependent hash.
14706sub reset_dependents {
14707    local($ctr) = @_;
14708    local($dep,$subdep,%dependents);
14709    @dependents = (split($delim, $dependent{$ctr}));
14710    print "\n" if (($VERBOSITY > 3)&&(@dependents));
14711    while (@dependents) {
14712	$dep = pop(@dependents);
14713	print "RESET $dep to 0\n" if ($VERBOSITY > 3);
14714	if ($global{$dep}) { $global{$dep} = 0 }
14715	elsif ($dep =~ /equation/) { $global{'eqn_number'} = 0 }
14716	if ($dependent{$dep}) {
14717	    push(@dependents,split($delim,$dependent{$dep}));
14718	}
14719    }
14720}
14721
14722sub do_cmd_numberwithin {
14723    local($_) = @_;
14724    local($ctr,$within);
14725    $ctr = &missing_braces
14726	unless ((s/$next_pair_rx/$ctr = $2;''/eo)
14727	      ||(s/$next_pair_pr_rx/$ctr = $2;''/eo));
14728    $within = &missing_braces
14729	unless ((s/$next_pair_rx/$within = $2;''/eo)
14730	      ||(s/$next_pair_pr_rx/$within = $2;''/eo));
14731
14732    # record the counter dependency
14733    &addto_dependents($within,$ctr) if ($within);
14734    local($newsub) = "sub do_cmd_the$ctr {"
14735	. "\$global{'max_id'}++;\n"
14736#        . "local(\$super)=\&do_cmd_the$within();\n"
14737	. "local(\$super)=\&translate_commands('\\the$within');\n"
14738	. "\$super .= '.' unless (\$super =~/\\.\$/);\n"
14739	. "\$super .\&do_cmd_value('<<'.\$global{'max_id'}.'>>"
14740	. $ctr . "<<'.\$global{'max_id'}.'>>')}\n";
14741    eval $newsub;
14742    print " *** sub do_cmd_the$ctr unchanged *** $@ " if ($@);
14743    $_;
14744}
14745
14746sub do_cmd_refstepcounter {
14747    local($_) = @_;
14748    local($ctr);
14749    $ctr = &missing_braces
14750	unless ((s/$next_pair_rx/$ctr = $2;''/eo)
14751	      ||(s/$next_pair_pr_rx/$ctr = $2;''/eo));
14752    if (! $AUX_FILE) {
14753	$latex_body .= &revert_to_raw_tex("\\refstepcounter{$ctr}\n");
14754	$index = $section_commands{$ctr};
14755	if (defined $global{$ctr}) { $global{$ctr} += 1 }
14756	elsif ($index) {
14757	    if ($SEGMENT) { $segment_sec_id[$index] += 1 }
14758	    else { $curr_sec_id[$index] += 1 }
14759	} elsif ($ctr eq "equation") { $global{'eqn_number'} += 1 }
14760	else { $global{$ctr} += 1 };
14761    }
14762    print "\nSTP: $ctr : +1" if ($VERBOSITY > 3);
14763    &reset_dependents($ctr) if ($dependent{$ctr});
14764    $_;
14765}
14766
14767sub read_counter_value {
14768    local($_) = @_;
14769    local($ctr,$br_id,$val);
14770    $ctr = &missing_braces
14771        unless ((s/$next_pair_pr_rx/$br_id = $1; $ctr = $2;''/eo)
14772              ||(s/$next_pair_rx/$br_id = $1; $ctr = $2;''/eo));
14773    $val = &get_counter_value($ctr);
14774    ($ctr, $val, $br_id, $_)
14775}
14776
14777sub styled_number_text {
14778    local($num_style, $val, $txtID) = @_;
14779    if ($USING_STYLES) {
14780        $txt_style{$num_style} = " " unless ($txt_style{$num_style});
14781        join('',"<SPAN CLASS=\"$num_style\">", $val, "</SPAN>", $_);
14782    } else { $val.$_ }
14783}
14784
14785sub do_cmd_arabic {
14786    local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14787    $val = ($val ? &farabic($val) : "0");
14788    &styled_number_text('arabic', $val, $id);
14789}
14790
14791sub do_cmd_roman {
14792    local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14793    if ($val < 0 ) { $val = join('',"-",&froman(-$val)); }
14794    elsif ($val) { $val = &froman($val) }
14795    else { $val = "0"; }
14796    &styled_number_text('roman', $val, $id);
14797}
14798
14799sub do_cmd_Roman {
14800    local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14801    if ($val < 0 ) { $val = join('',"-",&fRoman(-$val)); }
14802    elsif ($val) { $val = &fRoman($val) }
14803    else { $val = "0"; }
14804    &styled_number_text('Roman', $val, $id);
14805}
14806
14807sub do_cmd_alph {
14808    local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14809    if ($val < 0 ) { $val = join('',"-",&falph(-$val)); }
14810    elsif ($val) { $val = &falph($val) }
14811    else { $val = "0"; }
14812    &styled_number_text('alph', $val, $id);
14813}
14814
14815sub do_cmd_Alph {
14816    local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14817    if ($val < 0 ) { $val = join('',"-",&fAlph(-$val)); }
14818    elsif ($val) { $val = &fAlph($val) }
14819    else { $val = "0"; }
14820    &styled_number_text('Alph', $val, $id);
14821}
14822
14823
14824sub do_cmd_fnsymbol {
14825    local($ctr, $val, $id, $_) = &read_counter_value($_[0]);
14826    $val = &process_in_latex_helper($ctr, $val, "fnsymbol{$ctr}");
14827    &styled_number_text('Alph', $val, $id);
14828}
14829
14830
14831
14832# This is a general command for getting counter values;
14833# e.g. for section-numbers.
14834
14835sub do_cmd_thecounter {
14836    local($_) = @_;
14837    # Uses $counter bound by the caller
14838    local($val) = &get_counter_value($counter);
14839    $val = &process_in_latex_helper($counter,$val,"the$counter");
14840    &styled_number_text($counter, $val, '');
14841#   join('',&process_in_latex_helper($counter,$val,"the$counter"),$_[0]);
14842}
14843
14844
14845################# Special Naming Macros ##################################
14846
14847sub do_cmd_LaTeX {
14848    local($_) = @_;
14849    if ($USING_STYLES) {
14850	$env_style{'LaTeX'} = ' ' unless ($env_style{'LaTeX'});
14851	$env_style{'logo-LaTeX'} = ' ' unless ($env_style{'logo-LaTeX'});
14852	join('',"<SPAN CLASS=\"logo,LaTeX\">",$Laname, $TeXname,"</SPAN>",$_);
14853    } else { join('',$Laname, $TeXname, $_); }
14854}
14855
14856sub do_cmd_LaTeXe {
14857    local($_) = @_;
14858    if ($USING_STYLES) {
14859	$env_style{'LaTeX2e'} = ' ' unless ($env_style{'LaTeX2e'});
14860	$env_style{'logo-LaTeX2e'} = ' ' unless ($env_style{'logo-LaTeX2e'});
14861	join('',"<SPAN CLASS=\"logo,LaTeX2e\">"
14862		,$Laname, $TeXname,'2<SUB>e</SUB>',"</SPAN>",$_);
14863    } else { join('',$Laname,$TeXname
14864		,(($HTML_VERSION >= 3.0)? '2<SUB>e</SUB>':'2e'),$_);
14865    }
14866}
14867
14868sub do_cmd_latextohtml {
14869    local($_) = @_;
14870    if ($USING_STYLES) {
14871	$env_style{'LaTeX2HTML'} = ' ' unless ($env_style{'LaTeX2HTML'});
14872	$env_style{'logo-LaTeX2HTML'} = ' ' unless ($env_style{'logo-LaTeX2HTML'});
14873	join('',"<SPAN CLASS=\"logo,LaTeX2HTML\">"
14874		,$Laname, $TeXname,"2<TT>HTML</TT>","</SPAN>",$_);
14875    } else { join('',$Laname,$TeXname,"2<TT>HTML</TT>",$_);}
14876}
14877
14878sub do_cmd_TeX {
14879    local($_) = @_;
14880    if ($USING_STYLES) {
14881	$env_style{'logo-TeX'} = ' ' unless ($env_style{'logo-TeX'});
14882	join('',"<SPAN CLASS=\"logo-TeX\">",$TeXname,"</SPAN>",$_);
14883    } else { join('',$TeXname, $_);}
14884}
14885
14886sub do_cmd_MF {
14887    local($_) = @_;
14888    if ($USING_STYLES) {
14889	$env_style{'logo-Metafont'} = ' ' unless ($env_style{'logo-Metafont'});
14890	join('',"<SPAN CLASS=\"logo-Metafont\">",$MFname,"</SPAN>",$_);
14891    } else { join('', $MFname, $_);}
14892}
14893
14894sub do_cmd_Xy {
14895    local($_) = @_;
14896    if ($USING_STYLES) {
14897	$env_style{'logo-Xy-pic'} = ' ' unless ($env_style{'logo-Xy-pic'});
14898	join('',"<SPAN CLASS=\"logo-Xy-pic\">",$Xyname,"</SPAN>",$_);
14899    } else { join('',$Xyname, $_);}
14900}
14901
14902sub do_cmd_AmS {
14903    local($_) = @_;
14904    if ($USING_STYLES) {
14905	$env_style{'logo-AMS'} = ' ' unless ($env_style{'logo-AMS'});
14906	join('',"<SPAN CLASS=\"logo-AMS\">",$AmSname,"</SPAN>",$_);
14907    } else { join('',$AmSname, $_);}
14908}
14909
14910sub do_cmd_AmSTeX {
14911    local($_) = @_;
14912    if ($USING_STYLES) {
14913	$env_style{'logo-AMS'} = ' ' unless ($env_style{'logo-AMS'});
14914	join('',"<SPAN CLASS=\"logo-AMS\">",$AmSname,"-$TeXname","</SPAN>",$_);
14915    } else { join('',$AmSname, "-", $TeXname, $_);}
14916}
14917
14918sub do_cmd_char {
14919    local($_) = @_;
14920# some special characters are already turned into l2h internal
14921# representation.
14922# Get its represention from the table and use it like as regexp form.
14923    local($spmquot) = &escape_rx_chars($html_specials{'"'});
14924# Get all internal special char representations as implied during
14925# preprocessing.
14926    local($spmrx) = join("\000",values %html_specials);
14927# escape regexp special chars (not really necessary yet, but why not)
14928    $spmrx = &escape_rx_chars($spmrx); #~ s:([\\(){}[\]\^\$*+?.|]):\\$1:g;
14929    $spmrx =~ s/\000/|/g;
14930    $spmrx = "(.)" unless $spmrx =~ s/(.+)/($1|.)/;
14931
14932    s/^[ \t]*(\d{1,3})[ \t]*/&#$1;/ &&
14933	return($_);
14934
14935    s/^[ \t]*\'(\d{1,3})[ \t]*/"&#".oct($1).";"/e &&
14936	return($_);
14937
14938    s/^[ \t]*$spmquot(\d{1,2})[ \t]*/"&#".hex($1).";"/e &&
14939	return($_);
14940
14941# This is a kludge to work together with german.perl. Brrr.
14942    s/^[ \t]*\'\'(\d{1,2})[ \t]*/"&#".hex($1).";"/e &&
14943	return($_);
14944# If l2h's special char marker represents more than one character,
14945# it's already in the &#xxx; form. Else convert the single character
14946# into &#xxx; with the ord() command.
14947    s/^[ \t]*\`\\?$spmrx[ \t]*/
14948	(length($html_specials_inv{$1}) > 1 ?
14949	 $html_specials_inv{$1} : "&#".ord($html_specials_inv{$1}||$1).";")/e &&
14950	     return($_);
14951    &write_warnings(join('',
14952			 "Could not find character number in \\char",
14953			 (/\n/ ? $` : $_), " etc.\n"));
14954    $_;
14955}
14956
14957
14958sub do_cmd_symbol {
14959    local($_) = @_;
14960    local($char);
14961    $char = &missing_braces
14962	unless ((s/$next_pair_pr_rx/$char = $2;''/eo)
14963		||(s/$next_pair_rx/$char = $2;''/eo));
14964    join('',&do_cmd_char($char),$_);
14965}
14966
14967################# Accent and Special Symbols ##################################
14968
14969# Generate code for the accents handling commands that are never
14970# applied to i or j.
14971# MEH: Now all accents are safe for dotless i or j
14972# MEH: Math accents supported as well
14973sub generate_accent_commands {
14974    local($accent,$accent_cmd);
14975    local(%accents) = ("c", "cedil", "pc", "cedil", "d", "bdot", "b", "b",
14976		       "tilde", "tilde", "dot", "dot", "bar", "macr",
14977		       "hat", "circ", "u", "breve", "v", "caron",
14978		       "H", "dblac", "t", "t", "grave", "grave",
14979		       "acute", "acute", "ddot", "uml", "check", "caron",
14980		       "breve", "breve", "vec", "vec",
14981		       "k", "ogon", "r", "ring");
14982    foreach $accent (keys(%accents))  {
14983	$accent_cmd = "sub do_cmd_$accent {" . 'local($_) = @_;'  .
14984	    "&accent_safe_for_ij('$accents{$accent}','$accent');" . '$_}';
14985	eval $accent_cmd;
14986	$accent_cmd = "do_cmd_$accent";
14987	print STDERR "\n*** sub do_cmd_$accent failed:\nPERL: $@\n" if ($@);
14988    }
14989}
14990
14991# These handle accents, taking care of the dotless i's and j's that
14992# may follow (even though accented j's are not part of any alphabet
14993# that I know).
14994#
14995# Note that many forms of accents over dotless i's and j's are
14996# handled:
14997#   "\^\i rest"
14998#   "\^\i
14999#    rest"
15000#   "\^{\i}rest"
15001#   "\^\i{}rest"
15002# They all produce "&#238;rest".
15003# MEH: now also handles
15004#   "\^{}rest"
15005#   "\^,rest"
15006# and many more
15007
15008sub accent_safe_for_ij {
15009    local($type,$acc_cmd) = @_;
15010    local($arg, $first_char,$ij_cmd);
15011    #print STDOUT "\nACCENT: $type <$_>\n" ;
15012    s/^[ \t]*\n?[ \t]*(\S)/$1/;	# Remove whitespace
15013    if (s/^\\([ij])([^a-zA-Z]|$)/$2/) {
15014	# Accent of this form: "\^\i rest" or "\^\i{}rest"
15015	($arg) =  $1; $ij_cmd = "\\$1";
15016	s/^[ \t]+//o;		# Get rid of whitespaces after \i
15017	if (substr($_, 0, 2) =~ /[\n\r][^\n\r]/) {
15018	    $_ = substr($_, 1); # Get rid of 1 newline after \i
15019	}
15020    } else {
15021	# Accent of this form: "\^{\i}rest" or not an accent on i nor j
15022	($arg) =  &get_next_pair_or_char_pr;
15023    }
15024    $arg =~ s/([^\s\\<])/$first_char = $1; ''/eo;
15025#   print STDOUT "\nACCENT1 type:$type arg:|${arg}| first_char: |$first_char| $ij_cmd
15026#	, $ACCENT_IMAGES\n";
15027
15028    local($aafter) = $_;
15029    local($iso) = &iso_map($first_char,$type);
15030    if ($iso) { $_ = join('', $iso, $arg, $aafter) }
15031    elsif ((!($ACCENT_IMAGES))&&(!($ij_cmd))) {
15032	local($err_string) =
15033	    "\nNo available accent for $first_char$type , using just \"$first_char$arg\"";
15034	print $err_string if ($DEBUG||$VERBOSITY > 1);
15035	&write_warnings("\n ...set \$ACCENT_IMAGES  to get an image ");
15036	$_ = join('', $first_char, $arg, $aafter) }
15037    else {
15038	print ", making image of accent: $first_char$type " if ($VERBOSITY > 1);
15039	$_ = join('', &mbox_accent($acc_cmd, $first_char, $ij_cmd) , $arg, $aafter)
15040    }
15041}
15042
15043sub mbox_accent {
15044    local($type, $char, $ij_cmd) = @_;
15045    if (length($type) > 1 ) {
15046	if ($text_accent{$type}) {
15047	    $type = $text_accent{$type};
15048	} elsif ($type =~ /^(math)?accent/) {
15049	} else {
15050	    print "\n unrecognised accent $type for `$char' ";
15051	    return $char;
15052	}
15053    }
15054    local(@styles);
15055    local($cmd,$style,$bstyle,$estyle) = ('','','','');
15056    local(@styles) = split(',',$ACCENT_IMAGES);
15057    foreach $style (@styles) {
15058	$style =~ s/(^\s*\\|\s*)//g;
15059	$cmd = "do_cmd_$style";
15060	if (defined &$cmd) {
15061	    $bstyle .= "\\$style\{" ;
15062	    $estyle .= "\}";
15063	} else {
15064	    &write_warnings("\nunrecognized style \\$style for accented characters");
15065	}
15066    }
15067    if (!($bstyle)) {
15068	$bstyle = "\{";
15069	$estyle = "\}";
15070    } elsif ($bstyle =~ /textit|itshape/) {
15071	$bstyle = '\raise.5pt\hbox{' . $bstyle ;
15072	$estyle .= "\}";
15073    }
15074    $char = $ij_cmd if ($ij_cmd);
15075    print STDOUT "\nACCENT: $type, $char" if ($VERBOSITY > 2);
15076    local($afterkern); # serifs extend too far on some letters...
15077    $afterkern = "\\kern.05em" if (($char =~ /m|n/)||($type=~/[Hv]/));
15078    # ...or the accent is wider than the letter, so pad it out a bit
15079    $afterkern = "\\kern.15em" if ($char =~ /i|l/); #||($type=~/v/));
15080
15081    &process_undefined_environment("tex2html_accent_inline"
15082        , ++$global{'max_id'}, "${bstyle}\\${type}\{$char\\/\}$estyle$afterkern");
15083}
15084
15085# MEH: Actually tries to find a dotless i or j
15086sub do_cmd_i { join('',&iso_map('i', 'nodot') || 'i', $_[0]) }
15087sub do_cmd_j { join('',&iso_map('j', 'nodot') || 'j', $_[0]) }
15088
15089sub do_cmd_accent {
15090    local($_) = @_;
15091    local($number);
15092    if (s/\s*(\d+)\s*//o) {$number = $1}
15093    elsif (s/\s*&SMPquot;(\d)(\d)\s*//o) { $number = $1*16 + $2 }
15094    elsif (s/\s*\'(\d)(\d)(\d)\s*//o) { $number = $1*64 + $2*8 + $3 }
15095    else { s/\s*(\W\w+)([\s\W])/$2/o;  $number = $1 }
15096    local($type) = $accent_type{uc($number)};
15097    #print STDOUT "\ndo_cmd_accent: $number ($type) |$_|\n";
15098    if (! $type) {
15099	&write_warnings("Accent number $number is unknown.\n");
15100	return $_;
15101    }
15102    &accent_safe_for_ij($type , 'accent$number' );
15103    $_;
15104}
15105
15106sub do_cmd_ae { join('', &iso_map("ae", "lig"), $_[0]);}
15107sub do_cmd_AE { join('', &iso_map("AE", "lig"), $_[0]);}
15108sub do_cmd_aa { join('', &iso_map("a", "ring"), $_[0]);}
15109sub do_cmd_AA { join('', &iso_map("A", "ring"), $_[0]);}
15110sub do_cmd_o { join('', &iso_map("o", "slash"), $_[0]);}
15111sub do_cmd_O { join('', &iso_map("O", "slash"), $_[0]);}
15112sub do_cmd_ss { join('', &iso_map("sz", "lig"), $_[0]);}
15113sub do_cmd_DH { join('', &iso_map("ETH", ""), $_[0]);}
15114sub do_cmd_dh { join('', &iso_map("eth", ""), $_[0]);}
15115sub do_cmd_TH { join('', &iso_map("THORN", ""), $_[0]);}
15116sub do_cmd_th { join('', &iso_map("thorn", ""), $_[0]);}
15117
15118sub do_cmd_pounds { join('', &iso_map("pounds", ""), $_[0]);}
15119sub do_cmd_S { join('', &iso_map("S", ""), $_[0]);}
15120sub do_cmd_copyright { join('', &iso_map("copyright", ""), $_[0]);}
15121sub do_cmd_P { join('', &iso_map("P", ""), $_[0]);}
15122
15123
15124sub brackets { ($OP, $CP);}
15125
15126sub get_date {
15127    local($format,$order) = @_;
15128    local(@lt) = localtime;
15129    local($d,$m,$y) = @lt[3,4,5];
15130    if ($format =~ /ISO/) {
15131	sprintf("%4d-%02d-%02d", 1900+$y, $m+1, $d);
15132    } elsif ($format) {
15133	if ($order) { eval "sprintf(".$format.",".$order.")"; }
15134	else { sprintf($format, $d, $m+1, 1900+$y); }
15135    } else { sprintf("%d/%d/%d", $m+1, $d, 1900+$y); }
15136}
15137
15138sub address_data {
15139    local($user, $date, $_);
15140    local($format,$order) = @_;
15141    # Get author, (email address) and current date.
15142    ($user = L2hos->fullname()) =~ s/,.*//;
15143    ($user, &get_date($format,$order));
15144}
15145
15146
15147#################################### LaTeX2e ##################################
15148
15149sub missing_braces {
15150#    local($cmd) = @_;
15151    local($next, $revert, $thisline);
15152    local($this_cmd) = $cmd;
15153    $this_cmd =~ s/^\\// unless ($cmd eq "\\");
15154    &write_warnings("\n? brace missing for \\$this_cmd");
15155    if (/^[\s%]*([^\n]*)\n/ ) {
15156	$thisline = &revert_to_raw_tex($1)
15157    } else {
15158	$thisline = &revert_to_raw_tex($_);
15159    }
15160    print "\n\n*** no brace for \\$this_cmd , before:\n$thisline";
15161    s/^\s*//;
15162    if ($_ =~ s/$next_token_rx//) { $next = $& };
15163    $next =~ s/$comment_mark(\d+\n?)?//g;
15164#    $next = &translate_commands($next) if ($next =~ /^\\/);
15165    if ($next =~ /^\\(\W|\d|[a-zA-z]*\b)/) {
15166	$revert = $next = "\\".$1;
15167    } elsif ($next =~ /\W/) {
15168	$revert = &revert_to_raw_tex($next);
15169    } else { $revert = $next };
15170    print "\n*** using \"$revert\" as the argument instead; is this correct?  ***\n\n";
15171    $next;
15172}
15173
15174#RRM:
15175#     &styled_text_chunk  provides an interface for pieces of styled text,
15176# within a single paragraph. The visual markup can be obtained through either
15177# 1. link to a stylesheet (CSS)
15178# 2. direct markup placed into the output
15179# 3. calling another function to process the text
15180#
15181# parameters (in order):
15182#  $def_tag   : markup tag to be used, unless $USING_STYLES or no $property given,
15183#		attributes can be included, only 1st word is used for closing-tag;
15184#  $prefix    : prefix for the Unique ID identifier, defaults to 'txt'
15185#           OR  contains  CLASS= identifier  when $property is empty(see below);
15186#  $type      : general type of the style-sheet information
15187#  $class     : specific type of the style-sheet information
15188#  $property  : value to be set, applicable to the $type & $class
15189#  $alt_proc  : name of procedure to use, if $USING_STYLES == 0, and no $def_tag
15190#  $_         : current data-stream
15191#  $open_tags_R : current open-tags (not used in this procedure)
15192
15193				     sub styled_text_chunk {
15194    local($def_tag, $prefix, $type, $class, $property, $alt_proc, $_,
15195        $ot) = @_;
15196    local($open_tags_R) = defined $ot ? $ot : $open_tags_R;
15197    local($text, $env_id, $def_end);
15198    local($span_tag) = 'SPAN';
15199    print "PCT: styled_text_chunk: def_tag: $def_tag - prefix: $prefix - type: $type - class: $class - property: $property - alt_proc: $alt_proc - content: $_ - ot: $ot\n" if ($VERBOSITY > 10) ;
15200    $text = &missing_braces
15201        unless ((s/$next_pair_pr_rx/$text = $2; $env_id = $1;''/eo)
15202	    || (s/$next_pair_rx/$text = $2; $env_id = $1;''/eo));
15203    $text = &balance_inner_tags($text);
15204    print "PCT: styled_text_chunk: text: $text (balance inner tags)\n" if ($VERBOSITY > 10) ;
15205    #start from no open tags
15206    local(@save_open_tags) = ();
15207    local($open_tags_R) = [];
15208    local($result) ;
15209#    local($decl);
15210#    if ($prefix =~ /CLASS="(\w+)"/ ) {
15211#	$decl=$1;
15212#	push (@$open_tags_R, $decl);
15213#    }
15214#    push (@$open_tags_R, $color_env) if $color_env;
15215    if (!$inside_math) {
15216	$text = &translate_environments($text);
15217	$text = &translate_commands($text) if ($text =~ /\\/);
15218	$text .= &balance_tags;
15219	print "PCT: styled_text_chunk: text: $text (balance tags)\n" if ($VERBOSITY > 10) ;
15220    }
15221
15222    if (($USING_STYLES)&&($env_id =~ /^\d+$/)&&($property)) {
15223	$prefix = 'txt' unless ($prefix);
15224	$env_id = $prefix.$env_id;
15225	$styleID{$env_id} = join('',"$type", ($class ? "-$class" : '')
15226				 ,": ", $property,"; ");
15227	$result = join('',"<$span_tag ID=\"$env_id\">",$text,"<\/$span_tag>", $_) ;
15228	print "PCT: styled_text_chunk: prefix: $prefix - env_id: $env_id - return: $result\n" if ($VERBOSITY > 10) ;
15229	return $result ;
15230    }
15231
15232    if (($USING_STYLES)&&($prefix =~ /($span_tag )?CLASS=\"(\w+)\"/o)) {
15233	local($span_class) = $2;
15234	$def_tag = (($1)? $1 : $span_tag." ");
15235	$txt_style{$span_class} = "$type: $class "
15236	    unless ($txt_style{$span_class});
15237	$result = join('',"<$def_tag CLASS=\"$span_class\">", $text,"<\/$span_tag>", $_);
15238	print "PCT: styled_text_chunk: def_tag: $def_tag - return: $result\n" if ($VERBOSITY > 10) ;
15239	return $result ;
15240    }
15241
15242    if (($def_tag) && (!$USING_STYLES)) {
15243	$def_tag =~ s/^($span_tag)?CLASS=\"(\w+)\"$// ;
15244    }
15245
15246    if ($def_tag =~ /^(\w+)/) {
15247	$def_end = $1;
15248	$result = join('',"<$def_tag>",$text,"<\/$def_end>", $_) ;
15249	print "PCT: styled_text_chunk: def_end: $def_end - return: $result\n" if ($VERBOSITY > 10) ;
15250	return $result ;
15251    }
15252    print "PCT: styled_text_chunk: $text\n" if ($VERBOSITY > 10) ;
15253    $result = join('', eval ("&$alt_proc(\$text)") , $_) ;
15254    return $result if (defined "&$alt_proc");
15255
15256    &write_warnings(
15257	"\ncannot honour request for $type-$class:$property style at br$env_id");
15258    $result = join('', $text, $_);
15259    print "PCT: styled_text_chunk: NOT HONORED - return: $result\n" if ($VERBOSITY > 10) ;
15260    return $result ;
15261}
15262
15263				     sub multi_styled_text_chunk {
15264    local($def_tag, $prefix, $type, $class, $property, $_, $ot) = @_;
15265    local($open_tags_R) = defined $ot ? $ot : $open_tags_R;
15266    $prefix = 'txt' unless ($prefix);
15267    my(@def_tags) = split(',',$def_tag);
15268    my(@types) = split(',',$type);
15269    my(@classes) = split(',',$class);
15270    my(@properties) = split(',',$property);
15271    $text = &missing_braces
15272        unless ((s/$next_pair_pr_rx/$text = $2; $env_id = $1;''/eo)
15273	    || (s/$next_pair_rx/$text = $2; $env_id = $1;''/eo));
15274    if (($USING_STYLES)&&($env_id =~ /^\d+$/)&&($property)) {
15275        # $1 contains the bracket-id
15276	$env_id = $prefix.$env_id;
15277	while (@properties) {
15278	    $class = shift @classes;
15279	    $property = shift @properties;
15280	    $styleID{$env_id} .= join(''
15281		, shift @types,
15282		, ($class ? "-".$class : '')
15283		, ($property ? " : $property" : ''), " ; ");
15284	    $styleID{$env_id} .= "\n\t\t  " if (@properties);
15285	}
15286    }
15287    join('',"<SPAN ID=\"$env_id\">",$text,"<\/SPAN>", $_);
15288}
15289
15290#RRM:
15291#   This one takes care of commands with argument that really should be
15292#   environments; e.g.  \centerline, \rightline, etc.
15293#   Note that styles are inherited also from the existing @$open_tags_R.
15294#
15295				     sub styled_text_block {
15296    local($def_tag, $attrib, $value, $class, $_, $ot) = @_;
15297    local($open_tags_R) = defined $ot ? $ot : $open_tags_R;
15298    local($text, $env_id, $attribs);
15299    if ($attribs =~ /,/ ) {
15300        local(@attribs) = split(',',$attrib);
15301	local(@values) = split(',',$value);
15302	while (@attribs) {
15303            $attribs .= join('', " " , shift @attribs
15304	        ,"=\"" , shift @values, "\"") }
15305    } elsif($value) {
15306        $attribs = join(''," ",$attrib,"=\"",$value,"\"")
15307    } else { $attribs = " " . $attrib }
15308
15309    local(@save_open_tags) = @$open_tags_R;
15310    local($closures) = &close_all_tags();
15311    local($reopens)=&balance_tags();
15312    $text = &missing_braces
15313        unless ((s/$next_pair_pr_rx/$text = $2; $env_id = $1;''/eo)
15314	    || (s/$next_pair_rx/$text = $2; $env_id = $1;''/eo));
15315    if (($USING_STYLES)&&($env_id =~ /^\d+$/)) {
15316	$env_id = ++$global{'max_id'};
15317	$env_id = "par".$env_id;
15318	$styleID{$env_id} = " ";
15319	$env_style{$class} = " " if (($class)&&!($env_style{$class}));
15320	$class = " CLASS=\"$class\"" if ($class);
15321	$env_id = " ID=\"$env_id\"";
15322    } else { $class = ''; $env_id = '' };
15323
15324    $text = &translate_environments($text);
15325    $text = &translate_commands($text);
15326
15327    local($closuresA)=&close_all_tags();
15328    local($reopensA) = &balance_tags();
15329    $text =~ s/^\n?/\n/o;
15330    join('', $closures
15331        , "<$def_tag$class$env_id$attribs>"
15332        , $reopens, $text, $closuresA
15333        , "</$def_tag>\n", $reopensA,  $_);
15334				   }
15335# bold
15336sub do_cmd_textbf { &styled_text_chunk('','','','','','bbf', @_); }
15337# typewriter
15338sub do_cmd_texttt {
15339    print "PCT: do_cmd_texttt\n" if ($VERBOSITY > 10) ;
15340    &styled_text_chunk('','','','','','btt',@_);
15341}
15342# italic
15343sub do_cmd_textit { &styled_text_chunk('','','','','','bit',@_); }
15344# slanted
15345sub do_cmd_textsl { &styled_text_chunk('','','','','','bsl',@_); }
15346# slanted also ?
15347sub do_cmd_textsf { &styled_text_chunk('','','','','','bsf',@_); }
15348
15349sub lowercase_entity {
15350    local($char) = @_;
15351    local($exent);
15352    if ($exent = $low_entities{$char}) { "\&#$exent;" }
15353    elsif ($exent = $extra_small_caps{$char}) { $exent }
15354    else { "\&#$char;" }
15355}
15356
15357sub process_smallcaps {
15358    local($text) = @_;
15359    local($next, $scstr, $scbef, $special, $char);
15360    # is this enough for \sc and \scshape ?
15361    $text = &translate_environments($text);
15362
15363    # MRO: replaced $* with /m
15364    while ($text =~ /(\\[a-zA-Z]+|[&;]SPM\w+;|<[^>]+>)+/m ) {
15365	$scbef = $`; $special = $&; $text = $';
15366	while ( $scbef =~ /(&#\d+;|[a-z$sclower])+[a-z\W\d$sclower]*/m) {
15367	    $scstr .= $`; $scbef = $';
15368	    $next = $&;
15369	    $next =~ s/&#(\d+);/&lowercase_entity($1)/egm;
15370	    eval "\$next =~ $scextra" if ($scextra);
15371	    eval "\$next =~ tr/a-z$sclower/A-Z$scupper/";
15372	    $scstr .= "<SMALL>" . $next ."<\/SMALL>";
15373	}
15374	$scstr .= $scbef . $special;
15375    }
15376    if ($text) {
15377	while ( $text =~ /(&#\d+;|[a-z$sclower])+[a-z\W\d$sclower]*/m) {
15378	    $scstr .= $`; $text = $';
15379	    $next = $&;
15380	    $next =~ s/&#(\d+);/&lowercase_entity($1)/egm;
15381	    eval "\$next =~ $scextra" if ($scextra);
15382	    eval "\$next =~ tr/a-z$sclower/A-Z$scupper/";
15383	    $scstr .= "<SMALL>" . $next ."<\/SMALL>";
15384	}
15385	$scstr .= $text;
15386    }
15387    $scstr;
15388}
15389
15390# this gives a separate ID for each instance
15391#sub do_cmd_textsc { &styled_text_chunk('','','font','variant'
15392#		    ,'small-caps', 'process_smallcaps', @_); }
15393#
15394# this uses a single CLASS for all instances
15395#sub do_cmd_textsc { &styled_text_chunk('', 'CLASS="textsc"'
15396#		    ,'font-variant','small-caps','', 'process_smallcaps', @_); }
15397#
15398# ...but NS 4.03 doesn't implement  small-caps !!!
15399sub do_cmd_textsc { &styled_text_chunk('',''
15400		    ,'font-variant','small-caps','', 'process_smallcaps', @_); }
15401
15402
15403#sub do_cmd_emph { &styled_text_chunk('EM','em','font','variant','','', @_); }
15404
15405
15406# this gives a separate ID for each instance
15407#sub do_cmd_underline { &styled_text_chunk('U','','text','decoration','underline','', @_); }
15408
15409# this uses a single CLASS for all instances
15410sub do_cmd_underline { &styled_text_chunk('U','CLASS="underline"'
15411		       ,'text-decoration','underline','','', @_); }
15412sub do_cmd_underbar { &do_cmd_underline(@_) }
15413
15414
15415# this gives a separate ID for each instance
15416#sub do_cmd_strikeout { &styled_text_chunk('STRIKE',''
15417#		       ,'text','decoration','line-through','', @_); }
15418
15419# this uses a single CLASS for all instances
15420sub do_cmd_strikeout { &styled_text_chunk('STRIKE','CLASS="strikeout"',
15421		       'text-decoration','line-through','','', @_); }
15422
15423
15424sub do_cmd_uppercase {
15425    local($_) = @_;
15426    local($text,$next,$done,$special,$after);
15427    $text = &missing_braces unless (
15428	    (s/$next_pair_pr_rx/$text = $2;''/eo)
15429	    ||(s/$next_pair_rx/$text = $2;''/eo));
15430    $after = $_;
15431    while ($text =~ /(\\[a-zA-Z]+|[&;]SPM\w+;)/ ) {
15432	$next = $`;
15433	$special = $&;
15434	$text = $';
15435	$next =~ tr /a-z/A-Z/ if ($next);
15436	$done .= $next . $special;
15437    }
15438    $text =~ tr /a-z/A-Z/ if ($text);
15439    $done .= $text;
15440    $done = &convert_iso_latin_chars($done) if ($done);
15441    join('',$done,$after);
15442}
15443
15444sub do_cmd_lowercase {
15445    local($_) = @_;
15446    local($text,$next,$done,$special,$after);
15447    $text = &missing_braces
15448        unless ((s/$next_pair_pr_rx/$text = $2;''/seo)
15449	    || (s/$next_pair_rx/$text = $2;''/seo));
15450    $after = $_;
15451    while ($text =~ /(\\[a-zA-Z]+|[&;]SPM\w+;)/ ) {
15452	$next = $`;
15453	$special = $&;
15454	$text = $';
15455	$next =~ tr /A-Z/a-z/ if ($next);
15456	$done .= $next . $special;
15457    }
15458    $text =~ tr /A-Z/a-z/ if ($text);
15459    $done .= $text;
15460    $done = &convert_iso_latin_chars($done) if ($done);
15461    join('',$done,$after);
15462}
15463
15464sub do_cmd_MakeUppercase { &do_cmd_uppercase(@_) }
15465sub do_cmd_MakeLowercase { &do_cmd_lowercase(@_) }
15466
15467
15468
15469sub do_cmd_ensuremath {
15470    local($_) = @_;
15471    local ($id, $value);
15472    $value = &missing_braces unless (
15473	(s/$next_pair_pr_rx/$value=$2;''/eo)
15474	||(s/$next_pair_rx/$value=$2;''/eo));
15475    join('', &simple_math_env($value), $');
15476}
15477
15478#
15479#  This is mainly for \special{header=PostScript_Prologue},
15480#	and \graphicspath{path} which occur OUTSIDE of an environment
15481#	passed to TeX.  \special's INSIDE such environments are, of
15482#	course, left alone.
15483
15484sub do_cmd_special {
15485    local($_) = @_;
15486    local ($id, $value);
15487    $value = &missing_braces unless (
15488	(s/$next_pair_pr_rx/$value=$2;''/eo)
15489	||(s/$next_pair_rx/$value=$2;''/eo));
15490    local($special_cmd) = &revert_to_raw_tex($value);
15491    &add_to_preamble($cmd,"\\$cmd\{$special_cmd\}");
15492    $_;
15493}
15494
15495
15496########################## Input and Include commands #########################
15497
15498sub do_cmd_input {
15499    local($_) = @_;
15500    local($file,$output);
15501    (s/\s*(.*)\s*\n/$file =$1;''/s) unless (
15502	(s/$next_pair_pr_rx/$file=$2;''/eo)
15503	||(s/$next_pair_rx/$file=$2;''/eo));
15504    local($after) = $_;
15505    $file = &revert_to_raw_tex("\\input{$file}\n") if $file;
15506    if ($PREAMBLE) { &add_to_preamble('include',$file)}
15507    elsif (!($file=~/^\s*$/)) {
15508	$output = &process_undefined_environment('center'
15509		, ++$global{'max_id'},"\\vbox{$file}");
15510    }
15511    $output.$after;
15512}
15513
15514sub do_cmd_include {
15515    local($_) = @_;
15516    local($file,$output);
15517    $file = &missing_braces unless (
15518	(s/$next_pair_pr_rx/$file=$2;''/eo)
15519	||(s/$next_pair_rx/$file=$2;''/eo));
15520    local($after) = $_;
15521    $file = &revert_to_raw_tex("\\include{$file}\n") if $file;
15522    if ($PREAMBLE) { &add_to_preamble('include',$file)}
15523    else {
15524	$output = &process_undefined_environment('figure'
15525		, ++$global{'max_id'},"\\vbox{$file}");
15526    }
15527    $output.$after;
15528}
15529
15530########################## Messages #########################
15531
15532sub do_cmd_message {
15533    local($_) = @_;
15534    local($message);
15535    $message = &missing_braces unless (
15536	(s/$next_pair_pr_rx/$message=$2;''/eo)
15537	||(s/$next_pair_rx/$message=$2;''/eo));
15538    local($after) = $_;
15539    $message = &translate_commands($message);
15540    $message =~ s/$comment_mark(\d+)//og;
15541    print STDOUT "\n*** $message ***\n";
15542    $after;
15543}
15544
15545sub do_cmd_typeout {
15546    print STDOUT "\n";
15547    local($_) = &do_cmd_message(@_);
15548    print STDOUT "\n";
15549    $_;
15550}
15551
15552sub do_cmd_expandafter {
15553    local($_) = @_;
15554    print "\nEXPANDAFTER: " if ($VERBOSITY >3);
15555    return($_) unless (s/^\s*(\\\w+)\s*\\//o);
15556    print " delaying $1 " if ($VERBOSITY >3);
15557    local($delay,$cmd) = ($1,'');
15558    s/^(\w+|\W)/$cmd=$1;''/eo;
15559    local($nextcmd) = "do_cmd_$cmd";
15560    if (defined &$nextcmd) { $_ = &$nextcmd($_) }
15561    elsif ($new_command{$cmd}) {
15562        local($argn, $body, $opt) = split(/:!:/, $new_command{$cmd});
15563	do { ### local($_) = $body;
15564	    &make_unique($body);
15565	} if ($body =~ /$O/);
15566	if ($argn) {
15567	    do {
15568		local($before) = '';
15569		local($after) = "\\$cmd ".$_;
15570		$after = &substitute_newcmd;   # may change $after
15571                $after =~ s/\\\@#\@\@/\\/o unless ($after);
15572            };
15573	} else { $_ = $body . $_; }
15574    } else { print "\nUNKNOWN COMMAND: $cmd "; }
15575
15576    # now put the delayed function back for processing
15577    join('',$delay, " ", $_);
15578}
15579
15580sub do_cmd_tracingall {
15581    print "\nTRACING:\n$ref_contents\n$after\n";
15582    $VERBOSITY = 8; ""; }
15583
15584sub do_cmd_htmltracenv { &do_cmd_htmltracing }
15585
15586sub do_cmd_htmltracing {
15587    local($_) = @_;
15588    local($value);
15589    $value = &missing_braces
15590        unless ((s/$next_pair_rx/$value = $2;''/eo)
15591	    ||(s/$next_pair_pr_rx/$value = $2;''/eo));
15592    if ($value =~ /^\s*(\d+)\s*$/) {
15593	$VERBOSITY = $1;
15594	if ($VERBOSITY) {
15595	    print "\n\n *** setting trace-level to $VERBOSITY ***\n";
15596	} else {
15597	    print "\n\n *** cancelling all tracing ***\n\n";
15598	}
15599    } else {
15600	&write_warnings("argument to \\htmltracing must be a number");
15601     }
15602    $_ ;
15603}
15604
15605
15606############################ Initialization ####################################
15607
15608sub initialise {
15609    ############################ Global variables ###############################
15610    $PREAMBLE = 2;		# 1 while translating preamble, 0 while translating body
15611    $NESTING_LEVEL = undef;	#counter for TeX group nesting level
15612    $OUT_NODE = 0;		# Used in making filenames of HTML nodes unique
15613    $eqno_prefix = '';		# default prefix on equation numbers
15614    ($O , $C, $OP, $CP) = ('<<' , '>>', '<#', '#>'); # Open/Close Markers
15615    $href_name = 0;		# Used in the HREF NAME= field
15616    $wrap_toggle = 'end';
15617    $delim = '%:%';		# Delimits items of sectioning information
15618				# stored in a string
15619
15620    $LATEX2HTML_META = '<META NAME="Generator" CONTENT="LaTeX2HTML v'.$TEX2HTMLV_SHORT.'">'
15621	. "\n<META HTTP-EQUIV=\"Content-Style-Type\" CONTENT=\"text/css\">"
15622	      unless ($LATEX2HTML_META);
15623
15624    $TeXname = (($HTML_VERSION ge "3.0")? "T<SMALL>E</SMALL>X" : "TeX");
15625    $Laname = (($HTML_VERSION ge "3.0")? "L<SUP><SMALL>A</SMALL></SUP>" : "La");
15626    $MFname = (($HTML_VERSION ge "3.0")? "M<SMALL>ETAFONT</SMALL>" : "Metafont");
15627    $Xyname = (($HTML_VERSION ge "3.0")? "X<SUB><BIG>Y</BIG></SUB>" : "Xy");
15628    $AmSname = (($HTML_VERSION ge "3.0")? "A<SUB><BIG>M</BIG></SUB>S" : "AmS");
15629
15630    $EQN_TAGS = "R" unless ($EQN_TAGS);
15631    $EQNO_START = "(";
15632    $EQNO_END   = ")";
15633
15634    $AtBeginDocument_hook  = "\$AtBeginDocument_hook\=\'\'; "
15635	unless $AtBeginDocument_hook;
15636    $cross_ref_mark = '<tex2html_cr_mark>';
15637    $external_ref_mark = '<tex2html_ext_cr_mark>';
15638    $cite_mark = '<tex2html_cite_mark>';
15639    $hash_mark = '<tex2html_hash_mark>';
15640    $protected_hash = '<tex2html_protected_hash>';
15641    $param_mark = '<tex2html_param_mark>';
15642    $bbl_mark = '<tex2html_bbl_mark>';
15643    $toc_mark = '<tex2html_toc_mark>';
15644    $lof_mark = '<tex2html_lof_mark>';
15645    $lot_mark = '<tex2html_lot_mark>';
15646    $info_page_mark = '<tex2html_info_page_mark>';
15647    $info_title_mark = '<tex2html_info_title_mark>';
15648    $init_file_mark = '<tex2html_init_file_mark>';
15649    $childlinks_on_mark = '<tex2html_childlinks_mark>';
15650    $childlinks_null_mark = '<tex2html_childlinks_null_mark>';
15651    $childlinks_mark = $childlinks_on_mark;
15652    $more_links_mark = '<tex2html_morelinks_mark>';
15653    $idx_mark = '<tex2html_idx_mark>';
15654    $verbatim_mark = '<tex2html_verbatim_mark>';
15655    $unfinished_mark = '<tex2html_unfinished_mark>';
15656    $verb_mark = '<tex2html_verb_mark>';
15657    $verbstar_mark = '<tex2html_verbstar_mark>';
15658    $image_mark = '<tex2html_image_mark>';
15659    $mydb_mark =  '<tex2html_mydb_mark>';
15660    $percent_mark = '<tex2html_percent_mark>';
15661    $ampersand_mark = '<tex2html_ampersand_mark>';
15662    $dol_mark = '<tex2html_lone_dollar>';
15663    $comment_mark = '<tex2html_comment_mark>';
15664    $caption_mark = '<tex2html_caption_mark>';
15665    $array_col_mark = '<tex2html_col_mark>';
15666    $array_row_mark = '<tex2html_row_mark>';
15667    $array_text_mark = '<tex2html_text_mark>';
15668    $array_mbox_mark = '<tex2html_mbox_mark>';
15669
15670    $bibitem_counter = 0;
15671    $undef_mark = '<tex2html_undef_mark>';
15672    $file_mark = '<tex2html_file>';
15673    $endfile_mark = '<tex2html_endfile>';
15674
15675    # This defines textual markers for all the icons
15676    # e.g. $up_visible_mark = '<tex2html_up_visible_mark>';
15677    # They will be replaced with the real icons at the very end.
15678    foreach $icon (keys %icons) {eval "\$$icon = '<tex2html_$icon>'"};
15679
15680    # Make sure $HTML_VERSION is in the right range and in the right format.
15681#    $HTML_VERSION =~ /[\d.]*/;
15682#    $HTML_VERSION = 0.0 + $&;
15683#    $HTML_VERSION = 2 if ( $HTML_VERSION < 2 );
15684#    $HTML_VERSION = 9 if ( $HTML_VERSION > 9 );
15685#    $HTML_VERSION = sprintf("%3.1f",$HTML_VERSION);
15686
15687    &banner();
15688    print "Revised and extended by:"
15689	. "\n Marcus Hennecke, Ross Moore, Herb Swan and others\n";
15690
15691    # Collect HTML options and figure out HTML version
15692    $HTML_OPTIONS = '' unless ($HTML_OPTIONS);
15693    $HTML_VERSION =~ s/^html|\s+//g;
15694    local(@HTML_VERSION) = split(/,/, $HTML_VERSION);
15695    foreach ( @HTML_VERSION ) {
15696	if (/^[\d\.]+$/) {
15697	    # Make sure $HTML_VERSION is in the right range and in the right format.
15698	    $HTML_VERSION = 0.0 + $_;
15699	    $HTML_VERSION = 2 if ( $HTML_VERSION < 2 );
15700	    $HTML_VERSION = 9 if ( $HTML_VERSION > 9 );
15701	    $HTML_VERSION = sprintf("%3.1f",$HTML_VERSION);
15702	} else {
15703	    $HTML_OPTIONS .= "$_,";
15704	}
15705    }
15706    $HTML_OPTIONS =~ s/\W$//;  # remove any trailing punctuation
15707
15708    print "...producing markup for HTML version $HTML_VERSION  ";
15709    print ($HTML_OPTIONS ? "with $HTML_OPTIONS extensions\n\n\n" : "\n\n\n");
15710
15711    # load the character defs for latin-1, but don't set the charset yet
15712    &do_require_extension('latin1');
15713    $charset = $CHARSET = $PREV_CHARSET = '';
15714
15715    if ($HTML_VERSION =~ /(2.0|3.0|3.2|4.0|4.1)/) {
15716	# Require the version specific file
15717	do { $_ = "$LATEX2HTMLVERSIONS${dd}html$1.pl";
15718	     if (!(-f $_)) {  s/(\d).(\d.pl)$/$1_$2/ };
15719	     if (!(-f $_)) {  s/(\d)_(\d.pl)$/$1-$2/ };
15720	     require $_ || die "\n*** Could not load $_ ***\n";
15721	     print "\nHTML version: loading $_\n";
15722	} unless ($HTML_VERSION =~ /2.0/);
15723	$DOCTYPE = "-//".(($HTML_VERSION eq "2.0")? "IETF" : "W3C")
15724	    . "//DTD HTML $HTML_VERSION"
15725	    .(($HTML_VERSION eq "3.2")? " Final" : "")
15726	    .(($HTML_VERSION eq "4.0")? " Transitional" : "");
15727
15728	if ($HTML_OPTIONS) {
15729	    local($ext);
15730	    local($loading_extensions) = 1;
15731	    # Require the option specific files
15732	    @HTML_VERSION = split(/,/, $HTML_OPTIONS);
15733	    foreach $ext ( @HTML_VERSION ) {
15734		&do_require_extension($ext);
15735#		do {
15736#		    print "\nLoading $LATEX2HTMLVERSIONS$dd$ext.pl";
15737#		    require "$LATEX2HTMLVERSIONS$dd$ext.pl";
15738#		} if (-f "$LATEX2HTMLVERSIONS$dd$ext.pl");
15739	    }
15740	    undef $loading_extensions;
15741	}
15742    } else {
15743	print "\n You specified an invalid version: $HTML_VERSION\n"
15744	    . "In future please request extensions by name:\n"
15745	    . "  i18n  table  math  frame  latin1  unicode  etc.\n";
15746
15747    # Require all necessary version specific files
15748	foreach ( sort <$LATEX2HTMLVERSIONS${dd}html[1-9].[0-9].pl> ) {
15749	    last if ( $_ gt "$LATEX2HTMLVERSIONS${dd}html$HTML_VERSION.pl" );
15750	    do { print "\nloading $_" if ($DEBUG);
15751		 require $_; } unless (
15752		($NO_SIMPLE_MATH)&&($_ eq "$LATEX2HTMLVERSIONS${dd}html3.1.pl"));
15753	};
15754	$STRICT_HTML = 0;
15755    }
15756
15757    # packages automatically implemented, or clearly irrelevant
15758    %styles_loaded =
15759     ( 'theorem' , 1 , 'enumerate', 1 , 'a4paper' , 1 , 'b5paper' , 1
15760     , '10pt' , 1 , '11pt' , 1 , '12pt' , 1
15761     , %styles_loaded );
15762
15763
15764    %declarations =
15765    ('em' , '<EM></EM>',
15766     'it' , '<I></I>',
15767     'bf' , '<SPAN class="bbf"></SPAN>',
15768     'tt' , '<SPAN class="btt"></SPAN>',
15769     'sl' , '<I></I>',		# Oops!
15770     'sf' , '<I></I>',		# Oops!
15771     'rm' ,  '<></>',
15772     'rmfamily'   ,'<></>',     # see $fontchange_rx
15773     'normalfont' ,'<></>',     # see $fontweight_rx and $fontchange_rx
15774     'mdseries'   ,'<></>',     # see $fontweight_rx
15775     'upshape'    ,'<></>',     # see $fontchange_rx
15776     'itshape' ,  '<I></I>',
15777     'bfseries' , '<B></B>',
15778     'ttfamily' , '<TT></TT>',
15779     'slshape' ,  '<I></I>',	# Oops!
15780     'sffamily' , '<I></I>',	# Oops!
15781##     'scshape' ,  '<I></I>',	# Oops!
15782#     'boldmath' , '<B></B>',
15783#     'quote', '<BLOCKQUOTE></BLOCKQUOTE>',
15784#     'quotation', '<BLOCKQUOTE></BLOCKQUOTE>',
15785     %declarations	# Just in case someone extends it in the init file
15786     );
15787
15788
15789%declarations = (
15790     'tiny', '<FONT SIZE="-2"></FONT>',
15791     'Tiny', '<FONT SIZE="-2"></FONT>',
15792     'scriptsize', '<FONT SIZE="-2"></FONT>',
15793     'small', '<FONT SIZE="-1"></FONT>',
15794     'Small', '<FONT SIZE="-1"></FONT>',
15795     'SMALL', '<FONT SIZE="-1"></FONT>',
15796     'smaller', '<SMALL></SMALL>',
15797     'footnotesize', '<FONT SIZE="-1"></FONT>',
15798     'larger', '<BIG></BIG>',
15799     'large', '<FONT SIZE="+1"></FONT>',
15800     'Large', '<FONT SIZE="+2"></FONT>',
15801     'LARGE', '<FONT SIZE="+2"></FONT>',
15802     'huge', '<FONT SIZE="+3"></FONT>',
15803     'Huge', '<FONT SIZE="+4"></FONT>',
15804#     'centering', '<DIV ALIGN="CENTER"></DIV>',
15805#     'center', '<DIV ALIGN="CENTER"></DIV>',
15806#     'flushleft', '<DIV ALIGN="LEFT"></DIV>',
15807#     'raggedright', '<DIV ALIGN="LEFT"></DIV>',
15808#     'flushright', '<DIV ALIGN="RIGHT"></DIV>',
15809#     'raggedleft', '<DIV ALIGN="RIGHT"></DIV>',
15810     %declarations
15811    ) if ($HTML_VERSION > 2.0 );
15812
15813#  no alignment in HTML 2.0
15814#%declarations = (
15815#     'centering', '<P ALIGN="CENTER"></P>',
15816#     'center', '<P ALIGN="CENTER"></P>',
15817#     'flushleft', '<P ALIGN="LEFT"></P>',
15818#     'raggedright', '<P ALIGN="LEFT"></P>',
15819#     'flushright', '<P ALIGN="RIGHT"></P>',
15820#     'raggedleft', '<P ALIGN="RIGHT"></P>',
15821
15822%declarations = (
15823#     'centering', '<P></P>',
15824     'center', '<P></P>',
15825     'flushleft', '<P></P>',
15826     'raggedright', '<P></P>',
15827     'flushright', '<P></P>',
15828     'raggedleft', '<P></P>',
15829     'quote', '<BLOCKQUOTE></BLOCKQUOTE>',
15830     'quotation', '<BLOCKQUOTE></BLOCKQUOTE>',
15831     'verse', '<BLOCKQUOTE></BLOCKQUOTE>',
15832     'preform', '<PRE></PRE>',
15833     'unord', '<UL></UL>',
15834     'ord', '<OL></OL>',
15835     'desc', '<DL></DL>',
15836     'list', '',
15837     'par', '<P></P>'
15838    ) if ($HTML_VERSION == 2.0 );
15839
15840    &generate_declaration_subs;	# Generate code to handle declarations
15841
15842    # ...but these block-level divisions must be handled differently...
15843%declarations = (
15844     'quote', '<BLOCKQUOTE></BLOCKQUOTE>',
15845     'quotation', '<BLOCKQUOTE></BLOCKQUOTE>',
15846     'verse', '<BLOCKQUOTE></BLOCKQUOTE>',
15847     'preform', '<PRE></PRE>',
15848     'unord', '<UL></UL>',
15849     'ord', '<OL></OL>',
15850     'desc', '<DL></DL>',
15851#     'list', '<DIV></DIV>',
15852     'par', '<P></P>',
15853     'samepage', '',
15854#     'centering', '<DIV ALIGN="CENTER"></DIV>',
15855     'center', '<DIV ALIGN="CENTER"></DIV>',
15856     'flushleft', '<DIV ALIGN="LEFT"></DIV>',
15857     'raggedright', '<DIV ALIGN="LEFT"></DIV>',
15858     'flushright', '<DIV ALIGN="RIGHT"></DIV>',
15859     'raggedleft', '<DIV ALIGN="RIGHT"></DIV>',
15860     %declarations
15861    ) if ($HTML_VERSION > 2.0 );
15862
15863
15864    %section_commands =
15865	('partstar' , '1' , 'chapterstar', '2', 'sectionstar', '3'
15866	, 'subsectionstar', '4', 'subsubsectionstar', '5', 'paragraphstar'
15867	, '6', 'subparagraphstar', '7'
15868	, 'part' , '1' , 'chapter', '2', 'section', '3','subsection', '4'
15869	, 'subsubsection', '5', 'paragraph', '6', 'subparagraph', '7'
15870	, 'slidehead', '3', %section_commands);
15871    # The tableofcontents, listoffigures, listoftables, bibliography and
15872    # textohtmlindex are set after determining what is the outermost level
15873    # in sub set_depth_levels. Appendix is implemented as a command.
15874
15875    %standard_section_headings =
15876	('part' , 'H1' , 'chapter' , 'H1', 'section', 'H2', 'subsection', 'H3'
15877	, 'subsubsection', 'H4', 'paragraph', 'H5', 'subparagraph', 'H6'
15878	, %standard_section_headings );
15879
15880    # Generates code to handle sectioning commands
15881    # for those sections which take an argument.
15882    &generate_sectioning_subs;
15883
15884    %section_headings =
15885	('partstar' , 'H1' , 'chapterstar' , 'H1', 'sectionstar', 'H2'
15886	, 'subsectionstar', 'H3', 'subsubsectionstar', 'H4', 'paragraphstar'
15887	, 'H5', 'subparagraphstar', 'H6', %section_headings);
15888
15889    # These need their own custom code but are treated as sectioning commands
15890    %section_headings =
15891	('tableofcontents', 'H2', 'listoffigures', 'H2', 'listoftables', 'H2'
15892	, 'bibliography', 'H2', 'textohtmlindex', 'H2'
15893	, %standard_section_headings
15894	, %section_headings);
15895
15896    &generate_accent_commands;	# Code to handle accent commands
15897
15898    # These are replaced as soon as the text is read in.
15899    %html_specials = (  '<', ';SPMlt;'
15900		,  '>', ';SPMgt;'
15901		,  '&', ';SPMamp;'
15902#		,  '``', '\lq\lq '  # probably not a good idea
15903#		,  "''", '\rq\rq ',  # probably not a good idea
15904		,  '"', ';SPMquot;'
15905		);
15906
15907    %html_specials = ( %html_specials
15908		, '``', ';SPMldquo;', "''", ';SPMrdquo;'
15909		) if ($HTML_VERSION >= 5 );
15910
15911    # This mapping is needed in sub revert_to_raw_tex
15912    # before passing stuff to latex for processing.
15913    %html_specials_inv = (
15914    		 ';SPMlt;' ,'<'
15915		, ';SPMgt;','>'
15916		, ';SPMamp;','&'
15917		, ';SPMquot;','"'
15918		, ';SPMldquo;','``'
15919		, ';SPMrdquo;',"''"
15920		, ';SPMdollar;', '$'	# for alltt
15921		, ';SPMpct;', '%'
15922		, ';SPMtilde;', '&#126;'
15923		);
15924
15925    # normalsize vertical dimension factors for 12pt (1.0 <=> <BR>)
15926    %vspace_12pt = ('ex', 1.0, 'em', 1.0, 'pt', 0.1, 'pc', 1.0,
15927	'in', 6.0, 'bp', 0.1, 'cm', 2.3, 'mm', 0.2, 'dd', 0.1,
15928	'cc', 1.0, 'sp', 0.0);
15929
15930    # For some commands such as \\, \, etc it is not possible to define
15931    # perl subroutines because perl does not allow some non-ascii characters
15932    # in subroutine names. So we define a table and a subroutine to relate
15933    # such commands to ascii names.
15934    %normalize = ('\\', 'd_backslash'
15935		  , '/', 'esc_slash', "`", 'grave'
15936		  , "'", 'acute', "^", 'hat', '"', 'ddot'
15937		  , '~', 'tilde', '.', 'dot', '=', 'bar'
15938		  , '{', 'lbrace' , '}', 'rbrace', '|', 'Vert'
15939		  , '#', 'esc_hash', '$', 'esc_dollar'
15940                 );
15941
15942    %text_accent = (  'cedil','c', 'bdot','d', 'b','b' , 'tilde','~'
15943                    , 'circ' ,'^', 'hat','^', 'check','v' , 'caron','v'
15944                    , 'acute','\'' , 'grave','`' , 'dot','.' , 'breve','u'
15945                    , 'ddot','"' , 'uml','"' , 'bar','=','macr','='
15946                    , 'dblacc','H' , 't','t' , 'ogon','k' , 'ring','r'
15947                  );
15948
15949    # %languages_translations holds for each known language the
15950    # appropriate translation function. The function is called in
15951    # slurp_input.
15952    # The translation functions subtitute LaTeX macros
15953    # with ISO-LATIN-1 character references
15954    %language_translations = (
15955	   'english',	'english_translation'
15956	 , 'USenglish',	'english_translation'
15957	 , 'original',	'english_translation'
15958	 , 'german',	'german_translation'
15959	 , 'austrian',	'german_translation'
15960	 , 'finnish',	'finnish_translation'
15961	 , 'french',	'french_translation'
15962	 , 'spanish',	'spanish_translation'
15963	 , 'swedish',	'swedish_translation'
15964	 , 'turkish',	'turkish_translation'
15965	);
15966
15967# Reiner:
15968#    $standard_label_rx =
15969#	"\\s*[[]\\s*(((\$any_next_pair_rx4)|([[][^]]*[]])|[^]])*)[]]";
15970#    $enum_label_rx = "^((({[^{}]*})|([^{}]))*)([aAiI1])(.*)";
15971#    $enum_level = 0;	# level for enumerate (1-4, i-iv)
15972    %enum = (
15973		'enumi',	0,			# counter for level 1
15974		'enumii',	0,			# counter for level 2
15975		'enumiii',	0,
15976		'enumiv',	0,
15977		'theenumi',	"&arabic('enumi')",	# eval($enum{"theenumi"})
15978		'theenumii',	"&alph('enumii')",
15979		'theenumiii',	"&roman('enumiii')",
15980		'theenumiv',	"&Alph('enumiv')",
15981			# e.g. eval("$enum{'labelenumi'}")
15982		'labelenumi',	'eval($enum{"theenumi"}) . "."',
15983		'labelenumii',	'"(" . eval($enum{"theenumii"}) . ")"',
15984		'labelenumiii',	'eval($enum{"theenumiii"}) . "."',
15985		'labelenumiv',	'eval($enum{"theenumiv"}) . "."'
15986		);
15987
15988    %RomanI = ( '1',"I",'2',"II",'3',"III",'4',"IV"
15989		    ,'5',"V",'6',"VI",'7',"VII", '8',"VIII",'9',"IX");
15990    %RomanX = ( '1',"X",'2',"XX",'3',"XXX",'4',"XL"
15991		    ,'5',"L",'6',"LX",'7',"LXX", '8',"LXXX",'9',"XC");
15992    %RomanC = ( '1',"C",'2',"CC",'3',"CCC",'4',"CD"
15993		    ,'5',"D",'6',"DC",'7',"DCC", '8',"DCCC",'9',"CM");
15994    %RomanM = ( '1',"M",'2',"MM",'3',"MMM",'4',"MH"
15995		    ,'5',"H",'6',"HM",'7',"HMM",'8',"HMMM");
15996
15997    %enum_label_funcs = (
15998	"a", "alph", "A", "Alph", "i", "roman", "I", "Roman", "1", "arabic" );
15999
16000sub farabic{
16001    local($_)=@_;
16002    $_;
16003}
16004sub arabic{
16005    local($_)=@_;
16006    eval($enum{$_});
16007}
16008
16009sub falph{
16010    local($num)=@_;
16011#    chr($num+64);
16012    substr(" abcdefghijklmnopqrstuvwxyz",$num,1)
16013}
16014sub alph{
16015    local($num)=@_;
16016    &falph(eval($enum{$num}));
16017}
16018sub fAlph{
16019    local($num)=@_;
16020#    chr($num+32);
16021    substr(" ABCDEFGHIJKLMNOPQRSTUVWXYZ",$num,1)
16022}
16023sub Alph{
16024    local($num)=@_;
16025    &falph(eval($enum{$num}));
16026}
16027
16028sub Roman{
16029    local($num)=@_;
16030    &fRoman(eval($enum{$num}));
16031}
16032sub fRoman{
16033    local($num)=@_;
16034    local($RmI)= $num%10; ($RmI) = (($RmI) ? $RomanI{"$RmI"} : '' );
16035    $num = $num/10; local($RmX)= $num%10; ($RmX) = (($RmX) ? $RomanX{"$RmX"} : '' );
16036    $num = $num/10; local($RmC)= $num%10; ($RmC) = (($RmC) ? $RomanC{"$RmC"} : '' );
16037    $num = $num/10; local($RmM)= $num%10; ($RmM) = (($RmM) ? $RomanM{"$RmM"} : '' );
16038    "$RmM" . "$RmC" . "$RmX" . "$RmI";
16039}
16040sub froman{
16041    local($_)=@_;
16042    $_ = &fRoman($_);
16043    $_ =~ tr/A-Z/a-z/;
16044    $_;
16045}
16046sub roman{
16047    local($num)=@_;
16048    &froman(eval($enum{$num}));
16049}
16050
16051
16052    %unitscale = ("in",72,"pt",72.27/72,"pc",12,"mm",72/25.4,"cm",72/2.54
16053		  ,"\\hsize",100,"\\vsize",100
16054		  ,"\\textwidth",100,"\\textheight",100
16055		  ,"\\pagewidth",100,"\\linewidth",100
16056		  );
16057    %units = ("in","in","pt","pt","pc","pi","mm","mm","cm","cm"
16058	      ,"\\hsize","%","\\vsize","%","\\textwidth","%","\\textheight","%");
16059
16060sub convert_length { # clean
16061    my ($this,$scale) = @_;
16062    $scale = 1 unless $scale;
16063    my ($pxs,$len,$full);
16064    if ( $this =~ /([\d.]*)\s*(in|pt|pc|mm|cm|\\[hv]size|\\\w+(width|height))?/ ) {
16065	$len = ($1 ? $1 : 1); $full = $2;
16066	if ($full &&($full =~ /\\([hv]size|\w+(width|height))/)) { $scale = 1;};
16067	$pxs = (($full) ? int($len * $unitscale{$full}*$scale + 0.5)
16068		 : int($len*$scale + .5) );
16069	if ( $full =~ /\\([hv]size|\w+(width|height))/) { $pxs .= '%';};
16070    };
16071    ($pxs,$len);
16072}
16073
16074
16075
16076
16077    # Inclusion in this list will cause a command or an environment to be ignored.
16078    # This is suitable for commands without arguments and for environments.
16079    # If however a do_env|cmd_<env|cmd> exists then it will be used.
16080    %ignore = ('sloppypar', 1,  'document', 1, 'newblock', 1,
16081	       ',', 1,  '@', 1, ' ', 1,  '-', 1,
16082               'sloppy', 1,
16083	       'hyphen', 1, 'titlepage', 1, 'htmlonly', 1,
16084	       'flushleft', 1, 'flushright', 1, 'slide', 1,
16085	       'tiny', 1, 'Tiny', 1, 'scriptsize', 1, 'footnotesize', 1,
16086	       'small', 1, 'normalsize', 1, 'large', 1, 'Large', 1,
16087	       'LARGE', 1, 'huge', 1, 'Huge', 1,
16088	       %ignore);
16089
16090    # Specify commands with arguments that should be ignored.
16091    # Arbitrary code can be placed between the arguments
16092    # to be executed while processing the command.
16093    #
16094# Note that some commands MAY HAVE ARGUMENTS WHICH SHOULD BE LEFT AS TEXT
16095    # EVEN THOUGH THE COMMAND IS IGNORED (e.g. hbox, center, etc)
16096
16097&ignore_commands( <<_IGNORED_CMDS_);
16098NeedsTeXFormat # {} # []
16099ProvidesClass # {} # []
16100ProvidesFile # {} # []
16101ProvidesPackage # {} # []
16102abovedisplayskip # &ignore_numeric_argument
16103abovedisplayshortskip # &ignore_numeric_argument
16104addcontentsline # {} # {} # {}
16105addtocontents # {} # {}
16106addvspace # {} # &ignore_numeric_argument
16107and
16108and # \$_ = join(''," - ",\$_)
16109backmatter
16110baselineskip # &ignore_numeric_argument
16111belowdisplayskip # &ignore_numeric_argument
16112belowdisplayshortskip # &ignore_numeric_argument
16113bibdata
16114bibliographystyle # {}
16115bibstyle # {}
16116bigskipamount # &ignore_numeric_argument
16117smallskipamount # &ignore_numeric_argument
16118medskipamount # &ignore_numeric_argument
16119center
16120citation # {}
16121citeauthoryear
16122clearpage
16123cline # {}
16124#documentclass # [] # {}
16125#documentstyle # [] # {}
16126#end # {}
16127enlargethispage # {}
16128evensidemargin # &ignore_numeric_argument
16129filecontents
16130filbreak
16131fil
16132fill
16133flushbottom
16134fontsize # {} # {}
16135footheight # &ignore_numeric_argument
16136footskip  # &ignore_numeric_argument
16137frontmatter
16138fussy
16139global
16140goodbreak
16141hbox
16142headheight # &ignore_numeric_argument
16143headsep # &ignore_numeric_argument
16144hfil
16145hfill
16146hfuzz # &ignore_numeric_argument
16147hline
16148hspace # {} # \$_ = join(''," ",\$_)
16149hspacestar # {} # \$_ = join(''," ",\$_)
16150html
16151ifcase
16152ignorespaces
16153indent
16154itemindent # &ignore_numeric_argument
16155itemsep # &ignore_numeric_argument
16156labelsep # &ignore_numeric_argument
16157labelwidth # &ignore_numeric_argument
16158leavevmode
16159leftmargin # &ignore_numeric_argument
16160listparindent # &ignore_numeric_argument
16161lower # &ignore_numeric_argument
16162long
16163mainmatter
16164makebox # [] # []
16165makeindex
16166marginpar # {}
16167marginparsep # &ignore_numeric_argument
16168marginparwidth # &ignore_numeric_argument
16169markboth # {} # {}
16170markright # {}
16171mathord
16172mathbin
16173mathindent # &ignore_numeric_argument
16174mathrel
16175mathop
16176mathtt
16177#mdseries
16178newpage
16179#newedboolean # {}
16180#newedcommand # {} # [] # [] # {}
16181#newedcounter # {} # []
16182#newedenvironment # {} # [] # [] # {} # {}
16183#newedtheorem # {} # [] # {} # []
16184#providedcommand # {} # [] # [] # {}
16185#renewedcommand # {} # [] # [] # {}
16186#renewedenvironment # {} # [] # [] # {} # {}
16187nobreakspace # \$_ = join('',";SPMnbsp;",\$_)
16188nonbreakingspace # \$_ = join('',";SPMnbsp;",\$_)
16189noalign
16190nobreak
16191nocite # {}
16192noindent
16193nolinebreak# []
16194nopagebreak #[]
16195normalmarginpar
16196numberline
16197oddsidemargin # &ignore_numeric_argument
16198omit
16199onecolumn
16200outer
16201pagenumbering #{}
16202pagestyle # {}
16203parindent # &ignore_numeric_argument
16204parsep # &ignore_numeric_argument
16205parskip # &ignore_numeric_argument
16206partopsep # &ignore_numeric_argument
16207penalty # &ignore_numeric_argument
16208phantom # {}
16209protect
16210raggedright
16211raggedbottom
16212raise # &ignore_numeric_argument
16213raisebox # {} # [] # []
16214relax
16215reversemarginpar
16216rightmargin # &ignore_numeric_argument
16217#rmfamily
16218rule # [] # {} # {}
16219samepage
16220selectfont
16221startdocument # \$SEGMENT=1;\$SEGMENTED=1; \$_
16222strut
16223suppressfloats # []
16224textheight # &ignore_numeric_argument
16225textwidth # &ignore_numeric_argument
16226textnormal
16227#textrm
16228textup
16229theorempreskipamount # &ignore_numeric_argument
16230theorempostskipamount # &ignore_numeric_argument
16231thispagestyle # {}
16232topmargin # &ignore_numeric_argument
16233topsep # &ignore_numeric_argument
16234topskip # &ignore_numeric_argument
16235twocolumn
16236unskip
16237#upshape
16238vfil
16239vfill
16240vfilll
16241vline
16242_IGNORED_CMDS_
16243
16244    # Commands which need to be passed, ALONG WITH THEIR ARGUMENTS, to TeX.
16245    # Note that this means that the arguments should *not* be translated,
16246    # This is handled by wrapping the commands in the dummy tex2html_wrap
16247    # environment before translation begins ...
16248
16249    # Also it can be used to specify environments which may be defined
16250    # using do_env_* but whose contents will be passed to LaTeX and
16251    # therefore should not be translated.
16252    # Note that this code squeezes spaces out of the args of psfig;
16253
16254
16255    # Images are cropped to the minimum bounding-box for these...
16256
16257&process_commands_in_tex (<<_RAW_ARG_CMDS_);
16258psfig # {} # \$args =~ s/ //g;
16259usebox # {}
16260framebox # [] # [] # {}
16261_RAW_ARG_CMDS_
16262
16263    # ... but these are set in a box to measure height/depth
16264    # so that white space can be preserved in the images.
16265
16266&process_commands_inline_in_tex (<<_RAW_ARG_CMDS_);
16267#etalchar # {} \$args =~ s/(.*)/\$\^\{\$1\}\\\$/o;
16268fbox # {}
16269#frac # [] # {} # {}
16270dag
16271ddag
16272l
16273L
16274oe
16275OE
16276textexclamdown
16277textquestiondown
16278textregistered
16279textperiodcentered
16280#textcircled # {}
16281#raisebox # {} # [] # [] # {}
16282_RAW_ARG_CMDS_
16283
16284
16285
16286# These are handled by wrapping the commands in the dummy tex2html_nowrap
16287# environment before translation begins. This environment will be
16288# stripped off later, when the commands are put into  images.tex  ...
16289
16290&process_commands_nowrap_in_tex (<<_RAW_ARG_NOWRAP_CMDS_);
16291#begingroup
16292#endgroup
16293#bgroup
16294#egroup
16295errorstopmode
16296nonstopmode
16297scrollmode
16298batchmode
16299psfigurepath # {}
16300pssilent
16301psdraft
16302psfull
16303thinlines
16304thicklines
16305linethickness # {}
16306hyphenation # {}
16307hyphenchar # \\ # &get_numeric_argument
16308hyphenpenalty # &get_numeric_argument
16309#let # \\ # <<\\(\\W|\\w+)>>
16310newedboolean # {}
16311newedcommand # {} # [] # [] # {}
16312newedcounter # {} # []
16313newedenvironment # {} # [] # [] # {} # {}
16314newedtheorem # {} # [] # {} # []
16315#providedcommand # {} # [] # [] # {}
16316#renewedcommand # {} # [] # [] # {}
16317#renewedenvironment # {} # [] # [] # {} # {}
16318DeclareMathAlphabet # {} # {} # {} # {} # {}
16319SetMathAlphabet # {} # {} # {} # {} # {} # {}
16320DeclareMathSizes # {} # {} # {} # {}
16321DeclareMathVersion # {}
16322DeclareSymbolFont # {} # {} # {} # {} # {}
16323DeclareSymbolFontAlphabet # {} # {}
16324DeclareMathSymbol # {} # {} # {} # {}
16325SetSymbolFont # {} # {} # {} # {} # {} # {}
16326DeclareFontShape # {} # {} # {} # {} # {} # {}
16327DeclareFontFamily # {} # {} # {}
16328DeclareFontEncoding # {} # {} # {}
16329DeclareFontSubstitution # {} # {} # {} # {}
16330mathversion # {}
16331#newfont # {} # {}
16332#normalfont
16333#rmfamily
16334#mdseries
16335newlength # {}
16336setlength # {} # {}
16337addtolength # {} # {}
16338settowidth # {}# {}
16339settoheight # {} # {}
16340settodepth # {} # {}
16341newsavebox # {}
16342savebox # {} # [] # {}
16343sbox # {} # {}
16344setbox # {}
16345TagsOnLeft  # \$EQN_TAGS = \"L\" if \$PREAMBLE;
16346TagsOnRight # \$EQN_TAGS = \"R\" if \$PREAMBLE;
16347_RAW_ARG_NOWRAP_CMDS_
16348
16349
16350&process_commands_wrap_deferred (<<_RAW_ARG_DEFERRED_CMDS_);
16351alph # {}
16352Alph # {}
16353arabic # {}
16354author # [] # {}
16355boldmath
16356unboldmath
16357captionstar # [] # {}
16358caption # [] # {}
16359#endsegment # []
16360#segment # [] # {} # {} # {}
16361fnsymbol # {}
16362footnote # [] # {}
16363footnotemark # []
16364footnotetext # [] # {}
16365#thanks # {}
16366roman # {}
16367Roman # {}
16368#mbox # {}
16369parbox # [] # [] # [] # {} # {}
16370#selectlanguage # [] # {}
16371setcounter # {} # {}
16372addtocounter # {} # {}
16373stepcounter # {}
16374refstepcounter # {}
16375value # {}
16376par
16377hrule # &ignore_numeric_argument
16378linebreak # []
16379pagebreak # []
16380newfont # {} # {}
16381smallskip
16382medskip
16383bigskip
16384centering
16385raggedright
16386raggedleft
16387itshape
16388#textit # {}
16389upshape
16390slshape
16391#scshape
16392rmfamily
16393sffamily
16394ttfamily
16395mdseries
16396bfseries
16397#textbf # {}
16398em
16399normalfont
16400it
16401rm
16402sl
16403bf
16404tt
16405sf
16406Tiny
16407tiny
16408scriptsize
16409footnotesize
16410small
16411Small
16412SMALL
16413normalsize
16414large
16415Large
16416LARGE
16417huge
16418Huge
16419lowercase # {}
16420uppercase # {}
16421MakeLowercase # {}
16422MakeUppercase # {}
16423htmlinfo # []
16424htmlinfostar # []
16425tableofchildlinks # []
16426tableofchildlinksstar # []
16427tableofcontents
16428listoffigures
16429listoftables
16430thepart
16431thepage
16432thechapter
16433thesection
16434thesubsection
16435thesubsubsection
16436theparagraph
16437thesubparagraph
16438theequation
16439htmltracenv # {}
16440HTMLsetenv # [] # {} # {}
16441#newedboolean # {}
16442#newedcounter # {} # []
16443#newedcommand # {} # [] # [] # {}
16444#newedtheorem # {} # [] # {} # []
16445#newedenvironment # {} # [] # [] # {} # {}
16446providedcommand # {} # [] # [] # {}
16447renewedcommand # {} # [] # [] # {}
16448renewedenvironment # {} # [] # [] # {} # {}
16449url # {}
16450htmlurl # {}
16451latextohtml
16452TeX
16453LaTeX
16454LaTeXe
16455LaTeXiii
16456Xy
16457MF
16458AmS
16459AmSTeX
16460textcircled # {}
16461_RAW_ARG_DEFERRED_CMDS_
16462
16463
16464#rrm
16465# implement the XBit-Hack for Apache servers, to handle
16466# Server-Side Includes (SSIs) with .html filename extension
16467#
16468sub check_htaccess {
16469    my $access_file = '.htaccess';
16470    my $has_access = '';
16471    local $_;
16472    print "\nChecking for .htaccess  file";
16473    if (-f $access_file) {
16474	print STDOUT " ... found";
16475	open(HTACCESS, "<$access_file");
16476	while (<HTACCESS>) {
16477	    if (/^\s*XBitHack\s*on\s*$/) {
16478		print STDOUT " with XBitHack on";
16479		$has_access =1; last;
16480	    };
16481	}
16482	print STDOUT "\n";
16483	close HTACCESS;
16484	return() if $has_access;
16485	open (HTACCESS, ">>$access_file");
16486	&write_warnings("appended to .htaccess in $DESTDIR");
16487    } else {
16488	open (HTACCESS, ">$access_file");
16489	chmod 0644, $access_file;
16490	&write_warnings("created .htaccess file in $DESTDIR");
16491    }
16492    print HTACCESS "\nXBitHack on\n";
16493    close HTACCESS;
16494}
16495
16496# This maps the HTML mnemonic names for the ISO-LATIN-1 character references
16497# to their numeric values. When converting latex specials characters to
16498# ISO-LATIN-1 equivalents I use the numeric values because this makes any
16499# conversion back to latex (using revert_raw_tex) more reliable (in case
16500# the text contains "&mnemonic_name"). Errors may occur if an environment
16501# passed to latex (e.g. a table) contains the numeric values of character
16502# references.
16503
16504# RRM: removed this portion; load from  latin1.pl instead
16505#&do_require_extension('latin1');
16506
16507sub make_isolatin1_rx {
16508    local($list) = &escape_rx_chars(join($CD,(values %iso_8859_1_character_map_inv)));
16509    $list =~ s/$CD/|/g;
16510    $isolatin1_rx = "($list)";
16511}
16512
16513
16514    ################### Frequently used regular expressions ###################
16515    # $1 : preamble
16516
16517    $preamble_rx = "(^[\\s\\S]*)(\\\\begin\\s*$O\\d+$C\\s*document\\s*$O\\d+$C|\\\\startdocument)";
16518
16519    # \d (number) should sometimes also be a delimiter but this causes
16520    # problems with command names  that are allowed to contain numbers (eg tex2html)
16521    # \d is a delimiter with commands which take numeric arguments?
16522    # JCL: I can't see that. \tex2html is also no valid LaTeX (or TeX).
16523    # It is parsed \tex 2html, and \tex may take 2html as argument, but this
16524    # is invalid LaTeX. \d must be treated as delimiter.
16525
16526# JCL(jcl-del) - Characters to be treated as letters, everything else
16527# is a delimiter.
16528    # internal LaTeX command separator, shouldn't be equal to $;
16529    $CD = "\001";
16530    &make_cmd_spc_rx; # determines space to follow a letter command
16531#old    $delimiters = '\'\\s[\\]\\\\<>(=).,#;:~\/!-';
16532    $letters = 'a-zA-Z';
16533    $delimiter_rx = "([^$letters])";
16534#
16535
16536    # liberalized environment names (white space, optional arg, interpunctuation signs etc.)
16537    # $1 : br_id, $2 : <environment>
16538    $begin_env_rx="(\\\\protect)?\\\\begin\\s*(\\[([^\\]]*)])?$O(\\d+)$C\\s*([^'[\\]\\\\#~]+)\\s*$O\\4$C";
16539    $begin_env_pr_rx="(\\\\protect)?\\\\begin\\s*(\\[([^\\]]*)])?$OP(\\d+)$CP\\s*([^'[\\]\\\\#~]+)\\s*$OP\\4$CP";
16540
16541    $mbox_rx = "\\\\mbox\\s*";
16542
16543    $match_br_rx = "\\s*$O\\d+$C\\s*";
16544
16545    $opt_arg_rx = "\\s*\\[([^\\]]*)\\]\\s*";	# Cannot handle nested []s!
16546    $optional_arg_rx = "^\\s*\\[([^]]*)\\]";	# Cannot handle nested []s!
16547
16548    $block_close_rx = "^<\\/(DIV|P|BLOCKQUOTE)>\$";
16549    $all_close_rx = "^<\\/(BODY|PRE|OL|UL|DL|FORM|ADDRESS)>\$";
16550
16551    # Matches a pair of matching brackets
16552    # $1 : br_id
16553    # $2 : contents
16554    $next_pair_rx = "^[\\s%]*$O(\\d+)$C([\\s\\S]*)$O\\1$C($comment_mark\\d*\\n?)?";
16555
16556    # will comments be a problem after these ???
16557    $any_next_pair_rx = "$O(\\d+)$C([\\s\\S]*)$O\\1$C";
16558    $any_next_pair_rx4 = "$O(\\d+)$C([\\s\\S]*)$O\\4$C";
16559    $any_next_pair_pr_rx4 = "$OP(\\d+)$CP([\\s\\S]*)$OP\\4$CP";
16560    $any_next_pair_rx5 = "$O(\\d+)$C([\\s\\S]*)$O\\5$C";
16561    $any_next_pair_rx6 = "$O(\\d+)$C([\\s\\S]*)$O\\6$C";
16562
16563    # used for labels in {enumerate} environments
16564    $standard_label_rx =
16565	"\\s*[[]\\s*((($any_next_pair_rx4)|([[][^]]*[]])|[^]])*)[]]";
16566    $enum_label_rx = "^(((\{[^{}]*\})|([^{}]))*)([aAiI1])(.*)";
16567    $enum_level = 0;	# level for enumerate (1-4, i-iv)
16568
16569
16570    # Matches the \ensuremath command
16571    $enspair = "\\\\ensuremath\\s*" . $any_next_pair_rx;
16572#    $enspair = "\\\\ensuremath\\s*$O(\\d+)$C([\\s\\S]*[\\\\\$&]+[\\s\\S]*)$O\\1$C";
16573
16574    # Matches math comments, from  math.pl
16575    $math_verbatim_rx = "$verbatim_mark#math(\\d+)#";
16576    $mathend_verbatim_rx = "$verbatim_mark#mathend([^#]*)#";
16577
16578    # Matches math array environments
16579    $array_env_rx = "array|cases|\\w*matrix";
16580
16581    # initially empty; has a value in HTML 3.2 and 4.0
16582    $math_class = '' unless ($math_class);
16583    $eqno_class = '' unless ($eqno_class);
16584
16585    # Matches to end-of-line and subsequent spaces
16586    $EOL = "[ \\t]*\\n?";
16587
16588    # Matches wrapped \par command
16589    $par_rx = "\\n?\\\\begin(($O|$OP)\\d+($C|$CP))tex2html_deferred\\1\\\\par\\s\*"
16590        . "\\\\end(($O|$OP)\\d+($C|$CP))tex2html_deferred\\4\\n?";
16591
16592    # $1 : br_id
16593    $begin_cmd_rx = "$O(\\d+)$C";
16594
16595    # $1 : image filename prefix
16596    $img_rx = "(\\w*T?img\\d+)";
16597
16598    # $1 : largest argument number
16599    $tex_def_arg_rx = "^[#0-9]*#([0-9])($O|$OP)";
16600
16601    #   only some non-alphanumerics are allowed in labels,  Why?
16602    $label_rx = "[^\\w\.\\\-\\\+\\\:]";
16603
16604#JCL(jcl-del) - new face, see also &do_cmd_makeatletter et.al.
16605#    $cmd_delims = q|-#,.~/\'`^"=\$%&_{}@|; # Commands which are also delimiters!
16606#    $single_cmd_atletter_rx = "\\\\([a-zA-Z\\\@]+\\*?|[$cmd_delims]|\\\\)";
16607#    $single_cmd_atother_rx = "\\\\([a-zA-Z]+\\*?|[$cmd_delims]|\\\\)";
16608    # $1 : declaration or command or newline (\\)
16609    &make_single_cmd_rx;
16610#
16611
16612    # $1 : description in a list environment
16613    $item_description_rx =
16614#	"\\\\item\\s*[[]\\s*((($any_next_pair_rx4)|([[][^]]*[]])|[^]])*)[]]";
16615	"\\\\item\\s*[[]\\s*((($any_next_pair_pr_rx4)|([[][^]]*[]])|[^]])*)[]]";
16616
16617    $fontchange_rx = 'rm|em|it|sl|sf|tt|sc|upshape|normalfont';
16618    $fontweight_rx = 'bf|mdseries|normalfont';
16619    $colorchange_rx = "(text)?color\\s*(\#\\w{6})?";
16620    $sizechange_rx = 'tiny|Tiny|scriptsize|footnotesize|small|Small|SMALL' .
16621	'|normalsize|large|Large|LARGE|huge|Huge';
16622
16623#    $image_switch_rx = "makeimage";
16624    $image_switch_rx = "makeimage|scshape|sc";
16625    $env_switch_rx = "writetolatex";
16626    $raw_arg_cmds{'font'} = 1;
16627
16628    # Matches the \caption command
16629    # $1 : br_id
16630    # $2 : contents
16631     $caption_suffixes = "lof|lot";
16632#    $caption_rx = "\\\\caption\\s*([[]\\s*((($any_next_pair_rx5)|([[][^]]*[]])|[^]])*)[]])?$O(\\d+)$C([\\s\\S]*)$O\\8$C$EOL";
16633
16634    $caption_rx = "\\\\(top|bottom|table)?caption\\s*\\\*?\\s*([[]\\s*((($any_next_pair_rx6)|([[][^]]*[]])|[^]])*)[]])?$O(\\d+)$C([\\s\\S]*)$O\\9$C$EOL";
16635    $caption_width_rx = "\\\\setlength\\s*(($O|$OP)\\d+($C|$CP))\\\\captionwidth\\1\\s*(($O|$OP)\\d+($C|$CP))([^>]*)\\4";
16636
16637    # Matches the \htmlimage command
16638    # $1 : br_id
16639    # $2 : contents
16640    $htmlimage_rx = "\\\\htmlimage\\s*$O(\\d+)$C([\\s\\S]*)$O\\1$C$EOL";
16641    $htmlimage_pr_rx = "\\\\htmlimage\\s*$OP(\\d+)$CP([\\s\\S]*)$OP\\1$CP$EOL";
16642
16643    # Matches the \htmlborder command
16644    # $1 : optional argument...
16645    # $2 : ...contents  i.e. extra attributes
16646    # $3 : br_id
16647    # $4 : contents i.e. width
16648    $htmlborder_rx = "\\\\htmlborder\\s*(\\[([^]]*)\\])?\\s*$O(\\d+)$C(\\d*)$O\\3$C$EOL";
16649    $htmlborder_pr_rx = "\\\\htmlborder\\s*(\\[([^]]*)\\])?\\s*$OP(\\d+)$CP(\\d*)$OP\\3$CP$EOL";
16650
16651    # Matches a pair of matching brackets
16652    # USING PROCESSED DELIMITERS;
16653    # (the delimiters are processed during command translation)
16654    # $1 : br_id
16655    # $2 : contents
16656#    $next_pair_pr_rx = "^[\\s%]*$OP(\\d+)$CP([\\s\\S]*)$OP\\1$CP";
16657    $next_pair_pr_rx = "^[\\s%]*$OP(\\d+)$CP([\\s\\S]*)$OP\\1$CP($comment_mark\\d*\\n?)?";
16658    $any_next_pair_pr_rx = "$OP(\\d+)$CP([\\s\\S]*)$OP\\1$CP($comment_mark\\d*\\n?)?";
16659    $next_token_rx = "^[\\s%]*(\\\\[A-Za-z]+|\\\\[^a-zA-Z]|.)";
16660
16661    $HTTP_start = 'http:';
16662
16663    # This will be used to recognise escaped special characters as such
16664    # and not as commands
16665    $latex_specials_rx = '[\$]|&|%|#|{|}|_';
16666    $html_escape_chars = '<>&';
16667
16668    # This is used in sub revert_to_raw_tex before handing text to be processed
16669    # by latex.
16670    $html_specials_inv_rx = join("|", keys %html_specials_inv);
16671
16672    # These are used for direct replacements in/from  ALT=... strings
16673    %html_special_entities = ('<','lt','>','gt','"','quot','&','amp');
16674    %html_spec_entities_inv = ('lt','<','gt','>','quot','"','amp','&');
16675
16676    # This is also used in sub revert_to_raw_tex
16677    $character_entity_rx = '(&#(\d+);)';
16678    $named_entity_rx = '&(\w+);';
16679
16680    #commands for altering theorem-styles
16681    $theorem_cmd_rx = 'theorem(style|(header|body)font)';
16682
16683
16684    # Matches a \begin or \end {tex2html_wrap}. Also used by revert_to_raw_tex
16685    $tex2html_wrap_rx = '\\\\(begin|end)\\s*\{\\s*(tex2html_(wrap|nowrap|deferred|nomath|preform|\\w*_inline)[_a-z]*|makeimage)\\s*\}'."($EOL)";
16686    $tex2html_deferred_rx  = '\\\\(begin|end)(<<\\d+>>)tex2html_deferred\\2';
16687    $tex2html_deferred_rx2 = '\\\\(begin|end)(<<\\d+>>)tex2html_deferred\\4';
16688    $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";
16689
16690    # The first empty parenthese pair is for non-letter commands.
16691    # $2: meta command, $4: delimiter (may be empty)  ignore the *-version distinction
16692#    $meta_cmd_rx = "()\\\\(providecommand|renewcommand|renewenvironment|newcommand|newenvironment|newtheorem|newcounter|newboolean|newif|let)(([^$letters$cmd_spc])|$cmd_spcs_rx)";
16693    $meta_cmd_rx = "()\\\\(providecommand|renewcommand|renewenvironment|newcommand|newenvironment|newtheorem|newcounter|newboolean|newif|DeclareRobustCommand|DeclareMathOperator\\*?)\\\*?(([^$letters$cmd_spc])|$cmd_spcs_rx)";
16694
16695    &make_counters_rx;
16696
16697    # Matches a label command and its argument
16698    $labels_rx = "\\\\label\\s*$O(\\d+)$C([\\s\\S]*)$O\\1$C$EOL";
16699    $labels_rx8 = "\\\\label\\s*$O(\\d+)$C([\\s\\S]*)$O\\8$C$EOL";
16700
16701    # Matches environments that should not be touched during the translation
16702#   $verbatim_env_rx = "\\s*{(verbatim|rawhtml|LVerbatim)[*]?}";
16703    $verbatim_env_rx = "\\s*(\\w*[Vv]erbatim|rawhtml|imagesonly|tex2html_code)[*]?";
16704    $image_env_rx = "\\s*(picture|xy|diagram)[*]?";
16705    $keepcomments_rx = "\\s*(picture|makeimage|xy|diagram)[*]?";
16706
16707    # names of different math environment types
16708    $display_env_rx = "displaymath|makeimage|eqnarray|equation";
16709    $inline_env_rx = "inline|indisplay|entity|xy|diagram";
16710    $sub_array_env_rx = "array|(small|\\w)\?matrix|tabular|cases";
16711
16712    # Matches environments needing pre-processing for images
16713    $pre_processor_env_rx = "\\\\(begin|end)\\s*(($O|$OP|\{)\\d+($C|$CP|\}))pre_(\\w+)\\2";
16714
16715    # Matches icon markers
16716    $icon_mark_rx = "<tex2html_(" . join("|", keys %icons) . ")>";
16717
16718    $start_time = time;
16719    print STDOUT join(" ", "Starting at", $start_time, "seconds\n")
16720        if ($TIMING||$DEBUG||($VERBOSITY>2));
16721$bbalise_rx = join('',$OP,'(\\d+)',$CP) ;
16722$bdeferred_rx = join('',$bbalise_rx,'tex2html_deferred') ;
16723
16724}	# end of &initialise
16725
16726# Frequently used regular expressions with arguments
16727sub make_end_env_rx {
16728    local($env) = @_;
16729    $env = &escape_rx_chars($env);
16730    "\\\\end\\s*$O(\\d+)$C\\s*$env\\s*$O\\1$C".$EOL;
16731}
16732
16733sub make_begin_end_env_rx {
16734    local($env) = @_;
16735    $env = &escape_rx_chars($env);
16736    "\\\\(begin|end)\\s*$O(\\d+)$C\\s*$env\\s*$O\\3$C(\\s*\$)?";
16737}
16738
16739sub make_end_cmd_rx {
16740    local($br_id) = @_;
16741    "$O$br_id$C";
16742}
16743
16744#JCL(jcl-del) - see also &tokenize.
16745# Arrange commands into a regexp for tokenisation.
16746# Any letter command will gobble spaces, but avoids to match
16747# on ensuing letters (\foo won't match on \foox).
16748# Any non-letter command retains spaces and matches always
16749# by itself (\| matches \|... regardless of ...).
16750#
16751# This all is a huge kludge. The commands names should stay fix,
16752# regardless of changing catcodes. If we have \makeatletter,
16753# and LaTeX2HTML marks \@foo, then \@foo will be expanded
16754# properly before \makeatother, but does weird things on \@foo
16755# after \makeatother (\@foo in LaTeX is then \@ and foo, which
16756# isn't recognized as such).
16757# The reason is that the text to match the command \@foo
16758# in LaTeX mustn't be \@foo at all, because any text in LaTeX
16759# is also attributed with the category codes.
16760#
16761# But at least we have proper parsing of letter and non-letter
16762# commands as long as catcoding won't upset LaTeX2HTML too much.
16763#
16764sub make_new_cmd_rx {
16765    return("") if $#_ < 0; # empty regexp if list is empty!
16766
16767    # We have a subtle treatment of ambivalent commands like
16768    # \@foo in situations depicted above!
16769    # Get every command that contains no letters ...
16770    local($nonlettercmds) =
16771	&escape_rx_chars(join($CD, grep(!/[$letters]/,@_)));
16772    # and every command that contains a letter
16773    local($lettercmds) =
16774	&escape_rx_chars(join($CD, grep(/[$letters]/,@_)));
16775
16776    if (%renew_command) {
16777	local($renew);
16778	foreach $renew (keys %renew_command) {
16779	    $lettercmds =~ s/(^|$CD)$renew//; }
16780        $lettercmds =~ s/^$CD$//;
16781    }
16782
16783    # replace the temporary $CD delimiter (this enables eg. \| command)
16784    $nonlettercmds =~ s/$CD/|/g;
16785    $lettercmds =~ s/$CD/|/g;
16786
16787    # In case we have no non-letter commands, insert empty parentheses
16788    # to align match strings.
16789    #
16790    $nonlettercmds =~ s/^\||\|$//g;
16791    $lettercmds =~ s/^\||\|$//g;
16792    local($rx) = (length($nonlettercmds) ? "\\\\($nonlettercmds)" : "");
16793    if (length($lettercmds)) {
16794	$rx .= ( length($rx) ? "|" : "()" );
16795	$rx .= "\\\\($lettercmds)(([^$letters$cmd_spc])|$cmd_spcs_rx|\$)";
16796    }
16797    # $1: non-letter cmd, $2: letter cmd, $4: delimiter
16798    # Eg. \\(\@|...|\+)|\\(abc|...|xyz)(([^a-zA-Z \t])|[ \t]+)
16799    # $1 and $2 are guaranteed to alternate, $4 may be empty.
16800    $rx;
16801}
16802
16803# Build a simple regexp to use after tokenisation for
16804# faster translation.
16805sub make_new_cmd_no_delim_rx {
16806    return("") if $#_ < 0; # empty regexp if list is empty!
16807    # Get every command that contains no letters ...
16808    local($_) = &escape_rx_chars(join($CD, @_));
16809    s/$CD/|/g;
16810
16811    join('',"\\\\(",$_,")");
16812}
16813
16814
16815#JCL(jcl-del) - new face: w/o arg (was 'begin' only), escapes env names
16816sub make_new_env_rx {
16817    local($envs) = &escape_rx_chars(join($CD, keys %new_environment));
16818    $envs =~ s/$CD/|/g;
16819    length($envs) ? "\\\\begin\\s*$O(\\d+)$C\\s*($envs)\\s*$O\\1$C\\s*" : "";
16820}
16821
16822sub make_new_end_env_rx {
16823    local($envs) = &escape_rx_chars(join($CD, keys %new_environment));
16824    $envs =~ s/$CD/|/g;
16825    length($envs) ? "\\\\end\\s*$O(\\d+)$C\\s*($envs)\\s*$O\\1$C\\s*" : "";
16826}
16827
16828#JCL(jcl-del) - $delimiter_rx -> ^$letters
16829# don't care for $cmd_spc_rx; space after sectioning commands
16830# is unlikely and I don't want to try too much new things
16831#
16832sub make_sections_rx {
16833    local($section_alts) = &get_current_sections;
16834    # $section_alts includes the *-forms of sectioning commands
16835    $sections_rx = "()\\\\($section_alts)(([^$letters$cmd_spc])|$cmd_spcs_rx|\$)";
16836#    $sections_rx = "()\\\\($section_alts)([^$letters])";
16837}
16838
16839sub make_order_sensitive_rx {
16840    local(@theorem_alts, $theorem_alts);
16841    @theorem_alts = ($preamble =~ /\\newtheorem\s*{([^\s}]+)}/og);
16842    $theorem_alts = join('|',@theorem_alts);
16843#
16844#  HWS: Added kludge to require counters to be more than 2 characters long
16845#	in order to be flagged as order-sensitive.  This will permit equations
16846#	with \theta to remain order-insensitive.  Also permit \alpha and
16847#	the eqnarray* environment to remain order-insensitive.
16848#
16849    $order_sensitive_rx =
16850#        "(equation|eqnarray[^*]|\\\\caption|\\\\ref|\\\\the[a-z]{2,2}[a-z]|\\\\stepcounter" .
16851        "(\\\\caption|\\\\ref|\\\\the[a-z]{2,2}[a-z]|\\\\stepcounter" .
16852        "|\\\\arabic|\\\\roman|\\\\Roman|\\\\alph[^a]|\\\\Alph|\\\\fnsymbol)";
16853    $order_sensitive_rx =~ s/\)/|$theorem_alts)/ if $theorem_alts;
16854}
16855
16856sub make_language_rx {
16857    local($language_alts) = join("|", keys %language_translations);
16858#    $setlanguage_rx = "\\\\se(lec)?tlanguage\\s*{\\\\?($language_alts)}";
16859    $setlanguage_rx = "\\\\setlanguage\\s*{\\\\?($language_alts)}";
16860    $language_rx = "\\\\($language_alts)TeX";
16861    $case_change_rx = "(\\\\(expandafter|noexpand)\s*)?\\\\((Make)?([Uu]pp|[Ll]ow)ercase)\s*";
16862}
16863
16864sub addto_languages {
16865    local($lang) = @_;
16866    local($trans) = "main'".$lang.'_translation';
16867    if (defined &$trans) {
16868	$language_translations {$lang} = $lang.'_translation';
16869    }
16870}
16871
16872# JCL(jcl-del) - new rexexp type
16873sub make_raw_arg_cmd_rx {
16874    # $1 or $2 : commands to be processed in latex (with arguments untouched)
16875    # $4 : delimiter
16876    $raw_arg_cmd_rx = &make_new_cmd_rx(keys %raw_arg_cmds);
16877    $raw_arg_cmd_rx;
16878}
16879
16880# There are probably more.
16881# Interferences not checked out yet, thus in makeat... only.
16882sub make_letter_sensitive_rx {
16883    $delimiter_rx = "([^$letters])";
16884    &make_sections_rx;
16885    &make_single_cmd_rx;
16886    &make_counters_rx;
16887}
16888
16889#JCL(jcl-del) - this could eat one optional newline, too.
16890# But this might result in large lines... anyway, it *should* be
16891# handled. A possible solution would be to convert adjacent newlines
16892# into \par's in preprocessing.
16893sub make_cmd_spc_rx {
16894    $cmd_spc = " \\t";
16895    $cmd_spc_rx = "[ \\t]*"; # zero or more
16896    $cmd_spcs_rx = "[ \\t]+"; # one or more
16897}
16898
16899sub make_single_cmd_rx {
16900    $single_cmd_rx = "\\\\([^$letters])|\\\\([$letters]+\\*?)(([^$letters$cmd_spc])|$cmd_spcs_rx|\n|\$)";
16901}
16902
16903sub make_counters_rx {
16904    # Matches counter commands - these are caught early and are appended to the
16905    # file that is passed to latex.
16906#JCL(jcl-del) - $delimiter_rx -> ^$letters
16907    $counters_rx = "()\\\\(newcounter|addtocounter|setcounter|refstepcounter|stepcounter|arabic|roman|Roman|alph|Alph|fnsymbol)(([^$letters$cmd_spc])|$cmd_spcs_rx|\$)";
16908}
16909
16910
16911# Creates an anchor for its argument and saves the information in
16912# the array %index;
16913# In the index the word will use the beginning of the title of
16914# the current section (instead of the usual pagenumber).
16915# The argument to the \index command is IGNORED (as in latex)
16916sub make_index_entry { &make_real_index_entry(@_) }
16917sub make_real_index_entry {
16918    local($br_id,$str) = @_;
16919    local($this_file) = $CURRENT_FILE;
16920    $TITLE = $saved_title if (($saved_title)&&(!($TITLE)||($TITLE eq $default_title)));
16921    # Save the reference
16922    $str = "$str###" . ++$global{'max_id'}; # Make unique
16923    $index{$str} .= &make_half_href($this_file."#$br_id");
16924    "<A NAME=\"$br_id\">$anchor_invisible_mark<\/A>";
16925}
16926
16927sub image_message { # clean
16928    print <<"EOF";
16929
16930To resolve the image conversion problems please consult
16931the "Troubleshooting" section of your local User Manual
16932or read it online at
16933   http://www-texdev.ics.mq.edu.au/l2h/docs/manual/
16934
16935EOF
16936}
16937
16938sub image_cache_message { # clean
16939   print <<"EOF";
16940
16941If you are having problems displaying the correct images with Mosaic,
16942try selecting "Flush Image Cache" from "Options" in the menu-bar
16943and then reload the HTML file.
16944EOF
16945}
16946
16947__DATA__
16948
16949# start of POD documentation
16950
16951=head1 NAME
16952
16953latex2html - Translate LaTeX files to HTML (HyperText Markup Language)
16954
16955=head1 SYNOPSIS
16956
16957B<latex2html> S<[ B<-help> | B<-h> ]> S<[ B<-version> | B<-V> ]>
16958
16959B<latex2html> S<[ B<-split> I<num> ]>
16960S<[ B<-link> I<num> ]>
16961S<[ B<-toc_depth> I<num> ]>
16962S<[ B<->(B<no>)B<toc_stars> ]>
16963S<[ B<->(B<no>)B<short_extn> ]>
16964S<[ B<-iso_language> I<lang> ]>
16965S<[ B<->(B<no>)B<validate> ]>
16966S<[ B<->(B<no>)B<latex> ]>
16967S<[ B<->(B<no>)B<djgpp> ]>
16968S<[ B<->(B<no>)B<fork> ]>
16969S<[ B<->(B<no>)B<external_images> ]>
16970S<[ B<->(B<no>)B<ascii_mode> ]>
16971S<[ B<->(B<no>)B<lcase_tags> ]>
16972S<[ B<->(B<no>)B<ps_images> ]>
16973S<[ B<-font_size> I<size> ]>
16974S<[ B<->(B<no>)B<tex_defs> ]>
16975S<[ B<->(B<no>)B<navigation> ]>
16976S<[ B<->(B<no>)B<top_navigation> ]>
16977S<[ B<->(B<no>)B<buttom_navigation> ]>
16978S<[ B<->(B<no>)B<auto_navigation> ]>
16979S<[ B<->(B<no>)B<index_in_navigation> ]>
16980S<[ B<->(B<no>)B<contents_in_navigation> ]>
16981S<[ B<->(B<no>)B<next_page_in_navigation> ]>
16982S<[ B<->(B<no>)B<previous_page_in_navigation> ]>
16983S<[ B<->(B<no>)B<footnode> ]>
16984S<[ B<->(B<no>)B<numbered_footnotes> ]>
16985S<[ B<-prefix> I<output_filename_prefix> ]>
16986S<[ B<->(B<no>)B<auto_prefix> ]>
16987S<[ B<-long_titles> I<num> ]>
16988S<[ B<->(B<no>)B<custom_titles> ]>
16989S<[ B<-title>|B<-t> I<top_page_title> ]>
16990S<[ B<->(B<no>)B<rooted> ]>
16991S<[ B<-rootdir> I<output_directory> ]>
16992S<[ B<-dir> I<output_directory> ]>
16993S<[ B<-mkdir> ]>
16994S<[ B<-address> I<author_address> | B<-noaddress> ]>
16995S<[ B<->(B<no>)B<subdir> ]>
16996S<[ B<-info> I<0> | I<1> | I<string> ]>
16997S<[ B<->(B<no>)B<auto_link> ]>
16998S<[ B<-reuse> I<num> | B<-noreuse> ]>
16999S<[ B<->(B<no>)B<antialias_text> ]>
17000S<[ B<->(B<no>)B<antialias> ]>
17001S<[ B<->(B<no>)B<transparent> ]>
17002S<[ B<->(B<no>)B<white> ]>
17003S<[ B<->(B<no>)B<discard> ]>
17004S<[ B<-image_type> I<type> ]>
17005S<[ B<->(B<no>)B<images> ]>
17006S<[ B<-accent_images> I<type> | B<-noaccent_images> ]>
17007S<[ B<-style> I<style> ]>
17008S<[ B<->(B<no>)B<parbox_images> ]>
17009S<[ B<->(B<no>)B<math> ]>
17010S<[ B<->(B<no>)B<math_parsing> ]>
17011S<[ B<->(B<no>)B<latin> ]>
17012S<[ B<->(B<no>)B<entities> ]>
17013S<[ B<->(B<no>)B<local_icons> ]>
17014S<[ B<->(B<no>)B<scalable_fonts> ]>
17015S<[ B<->(B<no>)B<images_only> ]>
17016S<[ B<->(B<no>)B<show_section_numbers> ]>
17017S<[ B<->(B<no>)B<show_init> ]>
17018S<[ B<-init_file> I<Perl_file> ]>
17019S<[ B<-up_url> I<up_URL> ]>
17020S<[ B<-up_title> I<up_title> ]>
17021S<[ B<-down_url> I<down_URL> ]>
17022S<[ B<-down_title> I<down_title> ]>
17023S<[ B<-prev_url> I<prev_URL> ]>
17024S<[ B<-prev_title> I<prev_title> ]>
17025S<[ B<-index> I<index_URL> ]>
17026S<[ B<-biblio> I<biblio_URL> ]>
17027S<[ B<-contents> I<toc_URL> ]>
17028S<[ B<-external_file> I<external_aux_file> ]>
17029S<[ B<->(B<no>)B<short_index> ]>
17030S<[ B<->(B<no>)B<unsegment> ]>
17031S<[ B<->(B<no>)B<debug> ]>
17032S<[ B<-tmp> I<path> ]>
17033S<[ B<->(B<no>)B<ldump> ]>
17034S<[ B<->(B<no>)B<timing> ]>
17035S<[ B<-verbosity> I<num> ]>
17036S<[ B<-html_version> I<num> ]>
17037S<[ B<->(B<no>)B<strict> ]>
17038I<file.tex> S<[ I<file2.tex> ... ]>
17039
17040=head1 DESCRIPTION
17041
17042I<LaTeX2HTML> is a Perl program that translates LaTeX source files into
17043HTML. For each source file given as an argument the translator will create
17044a directory containing the corresponding HTML files.
17045
17046=head1 OPTIONS
17047
17048Many options can be specified in a true/false manner. This is indicated by
17049I<(no)>, e.g. to enable passing unknown environments to LaTeX, say "-latex",
17050to disable the feature say "-nolatex" or "-no_latex" (portability mode).
17051
17052=over 4
17053
17054=item B<-help> | B<-h>
17055
17056Print this online manual and exit.
17057
17058=item B<-version> | B<-V>
17059
17060Print the LaTeX2HTML release and version information and exit.
17061
17062=item B<-split> I<num>
17063
17064Stop making separate files at this depth (say "-split 0" for one huge HTML
17065file).
17066
17067=item B<-link> I<num>
17068
17069Stop showing child nodes at this depth.
17070
17071=item B<-toc_depth> I<num>
17072
17073MISSING_DESCRIPTION
17074
17075=item B<->(B<no>)B<toc_stars>
17076
17077MISSING_DESCRIPTION
17078
17079=item B<->(B<no>)B<short_extn>
17080
17081If this is set all HTML file will have extension C<.htm> instead of
17082C<.html>. This is helpful when shipping the document to PC systems.
17083
17084=item B<-iso_language> I<lang>
17085
17086MISSING_DESCRIPTION
17087
17088=item B<->(B<no>)B<validate>
17089
17090When this is set true, the HTML validator specified in F<l2hconf.pm>
17091will run.
17092
17093=item B<->(B<no>)B<latex>
17094
17095Pass unknown environments to LaTeX. This is the default.
17096
17097=item B<->(B<no>)B<djgpp>
17098
17099Specify this switch if you are running DJGPP on DOS and need to avoid
17100running out of filehandles.
17101
17102=item B<->(B<no>)B<fork>
17103
17104Enable/disable forking. The default is reasonable for this platform.
17105
17106=item B<->(B<no>)B<external_images>
17107
17108If set, leave the images outside the document.
17109
17110=item B<->(B<no>)B<ascii_mode>
17111
17112This is different from B<-noimages>.
17113If this is set, B<LaTeX2HTML> will show textual tags rather than
17114images, both in navigation panel and text (Eg. C<[Up]> instead the up
17115icon).
17116You could use this feature to create simple text from your
17117document, eg. with 'Save as... Text' from B<Netscape> or with
17118B<lynx -dump>.
17119
17120=item B<->(B<no>)B<lcase_tags>
17121
17122writes out HTML tag names using lowercase letters, rather than uppercase.
17123
17124=item B<->(B<no>)B<ps_images>
17125
17126If set, use links to external postscript images rather than inlined bitmaps.
17127
17128=item B<-font_size> I<size>
17129
17130To set the point size of LaTeX-generated GIF files, specify the desired
17131value (i.e., C<10pt>, C<11pt>, C<12pt>, etc.).
17132The default is to use the point size of the original LaTeX document.
17133This value will be magnified by I<$FIGURE_SCALE_FACTOR> and
17134I<$MATH_SCALE_FACTOR> defined in F<l2hconf.pm>.
17135
17136=item B<->(B<no>)B<tex_defs>
17137
17138Enable interpretation of raw TeX commands (default).
17139Note: There are many variations of C<\def> that B<LaTeX2HTML> cannot process
17140correctly!
17141
17142=item B<->(B<no>)B<navigation>
17143
17144Put a navigation panel at the top of each page (default).
17145
17146=item B<->(B<no>)B<top_navigation>
17147
17148Enables navigation links at the top of each page (default).
17149
17150=item B<->(B<no>)B<buttom_navigation>
17151
17152Enables navigation links at the buttom of each page.
17153
17154=item B<->(B<no>)B<auto_navigation>
17155
17156Put navigation links at the top of each page. If the page exceeds
17157I<$WORDS_IN_PAGE> number of words then put one at the bottom of the page.
17158
17159=item B<->(B<no>)B<index_in_navigation>
17160
17161Put a link to the index page in the navigation panel.
17162
17163=item B<->(B<no>)B<contents_in_navigation>
17164
17165Put a link to the table of contents in the navigation panel.
17166
17167=item B<->(B<no>)B<next_page_in_navigation>
17168
17169Put a link to the next logical page in the navigation panel.
17170
17171=item B<->(B<no>)B<previous_page_in_navigation>
17172
17173Put a link to the previous logical page in the navigation panel.
17174
17175=item B<->(B<no>)B<footnode>
17176
17177Puts all footnotes onto a separate HTML page, called F<footnode.html>,
17178rather than at the bottom of the page where they are referenced.
17179
17180=item B<->(B<no>)B<numbered_footnotes>
17181
17182If true, you will get every footnote applied with a subsequent number, else
17183with a generic hyperlink icon.
17184
17185=item B<-prefix> I<output_filename_prefix>
17186
17187Set the output file prefix, prepended to all C<.html>, C<.gif> and C<.pl>
17188files. See also B<-auto_prefix>.
17189
17190=item B<->(B<no>)B<auto_prefix>
17191
17192Set this to automatically insert the equivalent of B<-prefix >C<basename->",
17193where "basename" is the base name of the file being translated.
17194
17195=item B<-long_titles> I<num>
17196
17197MISSING_DESCRIPTION
17198
17199=item B<->(B<no>)B<custom_titles>
17200
17201MISSING_DESCRIPTION
17202
17203=item B<-title>|B<-t> I<top_page_title>
17204
17205The title (displayed in the browser's title bar) the document shall get.
17206
17207=item B<->(B<no>)B<rooted>
17208
17209MISSING_DESCRIPTION
17210
17211=item B<-rootdir> I<output_directory>
17212
17213MISSING_DESCRIPTION
17214
17215=item B<-dir> I<output_directory>
17216
17217Put the result in this directory instead of parallel to the LaTeX file,
17218provided the directory exists, or B<-mkdir> is specified.
17219
17220=item B<-mkdir>
17221
17222Allow directory specified with B<-dir> to be created if necessary.
17223
17224=item B<-address> I<author_address> | B<-noaddress>
17225
17226Supply your own string if you don't like the default
17227"E<lt>NameE<gt> E<lt>DateE<gt>". B<-noaddress> suppresses the
17228generation of an address footer.
17229
17230=item B<->(B<no>)B<subdir>
17231
17232If set (default), B<LaTeX2HTML> creates (or reuses) another file directory.
17233When false, the generated HTML files will be placed in the current
17234directory.
17235
17236=item B<-info> I<0> | I<1> | I<string>
17237
17238=item B<-noinfo>
17239
17240If 0 is specified (or B<-noinfo> is used), do not generate an I<"About this
17241document..."> section. If 1 is specified (default), the standard info page is
17242generated. If a custom string is given, it is used as the info page.
17243
17244=item B<->(B<no>)B<auto_link>
17245
17246MISSING_DESCRIPTION
17247
17248=item B<-reuse> I<num> | B<-noreuse>
17249
17250If false, do not reuse or recycle identical images generated in previous
17251runs. If the html subdirectory already exists, start the interactive session.
17252If I<num> is nonzero, do recycle them and switch off the interactive session.
17253If 1, only recycle images generated from previous runs.
17254If 2, recycle images from the current and previous runs (default).
17255
17256=item B<->(B<no>)B<antialias_text>
17257
17258Use anti-aliasing in the generation of images of typeset material;
17259e.g. mathematics and text, e.g. in tables and {makeimage} environments.
17260
17261=item B<->(B<no>)B<antialias>
17262
17263Use anti-aliasing in the generation of images of figures. This usually
17264results in "sharper" bitmap images.
17265
17266=item B<->(B<no>)B<transparent>
17267
17268If this is set to false then any inlined images generated from "figure"
17269environments will NOT be transparent.
17270
17271=item B<->(B<no>)B<white>
17272
17273This sets the background of generated images to white for anti-aliasing.
17274
17275=item B<->(B<no>)B<discard>
17276
17277if true, the PostScript file created for each generated image
17278is discarded immediately after its image has been rendered and saved in the
17279required graphics format. This can lead to significant savings in disk-space,
17280when there are a lot of images, since otherwise these files are not discarded
17281until the end of all processing.
17282
17283=item B<-image_type> I<type>
17284
17285Specify the type of bitmap images to be generated. Depending on your setup,
17286B<LaTeX2HTML> can generate B<gif> or B<png> images. Note: Gif images have
17287certain legal restrictions, as their generation involves an algorithm
17288patented by Unisys.
17289
17290=item B<->(B<no>)B<images>
17291
17292If false, B<LaTeX2HTML> will not attempt to produce any inlined images.
17293The missing images can be generated "off-line" by restarting B<LaTeX2HTML>
17294with B<-images_only>.
17295
17296=item B<-accent_images> I<type> | B<-noaccent_images>
17297
17298MISSING_DESCRIPTION
17299
17300=item B<-style> I<style>
17301
17302MISSING_DESCRIPTION
17303
17304=item B<->(B<no>)B<parbox_images>
17305
17306MISSING_DESCRIPTION
17307
17308=item B<->(B<no>)B<math>
17309
17310By default the special MATH extensions are not used
17311since they do not conform with the HTML 3.2 standard.
17312
17313=item B<->(B<no>)B<math_parsing>
17314
17315MISSING_DESCRIPTION
17316
17317=item B<->(B<no>)B<latin>
17318
17319MISSING_DESCRIPTION
17320
17321=item B<->(B<no>)B<entities>
17322
17323MISSING_DESCRIPTION
17324
17325=item B<->(B<no>)B<local_icons>
17326
17327Set this if you want to copy the navigation icons to each document directory
17328so that the document directory is self-contained and can be dropped into
17329another server tree without further actions.
17330
17331=item B<->(B<no>)B<scalable_fonts>
17332
17333MISSING_DESCRIPTION
17334
17335=item B<->(B<no>)B<images_only>
17336
17337When true, B<LaTeX2HTML> will only try to convert the inlined images in the
17338file F<images.tex> which should have been generated automatically during
17339previous runs. This is very useful for correcting "bad LaTeX" in this file.
17340
17341=item B<->(B<no>)B<show_section_numbers>
17342
17343When this is set true, the section numbers are shown. The section numbers
17344should then match those that would have been produced by LaTeX.
17345The correct section numbers are obtained from the $FILE.aux file generated
17346by LaTeX.
17347Hiding the section numbers encourages use of particular sections
17348as standalone documents. In this case the cross reference to a section
17349is shown using the default symbol rather than the section number.
17350
17351=item B<->(B<no>)B<show_init>
17352
17353MISSING_DESCRIPTION
17354
17355=item B<-init_file> I<Perl_file>
17356
17357MISSING_DESCRIPTION
17358
17359=item B<-up_url> I<up_URL>, B<-up_title> I<up_title>
17360
17361=item B<-down_url> I<down_URL>, B<-down_title> I<down_title>
17362
17363=item B<-prev_url> I<prev_URL>, B<-prev_title> I<prev_title>
17364
17365=item B<-index> I<index_URL>,
17366
17367=item B<-contents> I<toc_URL>
17368
17369=item B<-biblio> I<biblio_URL>
17370
17371If both of the listed two options are set then the "Up" ("Previous" etc.)
17372button of the navigation panel in the first node/page of a converted
17373document will point to I<up_URL> etc. I<up_title> should be set
17374to some text which describes this external link.
17375Similarly you might use these options to link external documents
17376to your navigation panel.
17377
17378=item B<-external_file> I<external_aux_file>
17379
17380MISSING_DESCRIPTION
17381
17382=item B<->(B<no>)B<short_index>
17383
17384If this is set then B<makeidx.perl> will construct codified names
17385for the text of index references.
17386
17387=item B<->(B<no>)B<unsegment>
17388
17389Use this to translate a segmented document as if it were not
17390segmented.
17391
17392=item B<->(B<no>)B<debug>
17393
17394If this is set then intermediate files are left for later inspection and
17395a lot of diagnostic output is produced. This output may be useful when
17396searching for problems and/or submitting bug reports to the developers.
17397Temporary files include F<$$_images.tex> and F<$$_images.log> created during
17398image conversion. Caution: Intermediate files can be I<enormous>!
17399
17400=item B<-tmp> I<path>
17401
17402Path 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>.
17403
17404=item B<->(B<no>)B<ldump>
17405
17406This will cause LaTeX2HTML to produce a LaTeX dump of images.tex which is read
17407in on subsequent runs and speeds up startup time of LaTeX on the images.tex
17408translation. This actually consumes additional time on the first run, but pays
17409off on subsequent runs. The dump file will need about 1 Meg of disk space.
17410
17411=item B<->(B<no>)B<timing>
17412
17413MISSING_DESCRIPTION
17414
17415=item B<-verbosity> I<num>
17416
17417The amount of message information printed to the screen during processing
17418by B<LaTeX2HTML> is controlled by this setting.
17419By increasing this value, more information is displayed.
17420Here is the type of extra information that is shown at each level:
17421
17422  0   no extra information
17423  1   section types and titles
17424  2   environment
17425  3   command names
17426  4   links, labels and internal sectioning codes
17427
17428=item B<-html_version> I<list>
17429
17430Which HTML version should be generated. Currently available are:
17431C<2.0>, C<3.0>, C<3.2>, C<4.0>. Some additional options that may be
17432added are: C<math> (parse mathematics), C<i18n> (?),
17433C<table> (generate tables), C<frame> (generate frames),
17434C<latin1>...C<latin9> (use ISO-Latin-x encoding),
17435C<unicode> (generate unicode characters). Separate the options with ',',
17436e.g. C<4.0,math,frame>.
17437
17438=item B<->(B<no>)B<strict>
17439
17440MISSING_DESCRIPTION
17441
17442=back
17443
17444=head1 FILES
17445
17446=over 4
17447
17448=item F<$LATEX2HTMLPLATDIR/l2hconf.pm>
17449
17450This file holds the global defaults and configuration settings for
17451B<LaTeX2HTML>.
17452
17453=item F<$HOME/.latex2html-init>
17454
17455=item F<./.latex2html-init>
17456
17457These files may contain settings that override the global defaults, just
17458like specifying command line switches.
17459
17460=back
17461
17462=head1 ENVIRONMENT
17463
17464=over 4
17465
17466=item LATEX2HTMLDIR
17467
17468Path where LaTeX2HTML library files are found. On this installation
17469LATEX2HTMLDIR is F</home/bsbuild/dev/org-release/bacula-docs-11.0.5/latex2html>
17470
17471=item PERL5LIB
17472
17473Set by the B<latex2html> program to find perl modules.
17474
17475=item L2HCONFIG
17476
17477An alternative configuration filename. The standard configuration file
17478is F<$LATEX2HTMLPLATDIR/l2hconf.pm>. You may specify a sole filename (searched
17479for in F<$LATEX2HTMLPLATDIR> (and F<$PERL5LIB>) or a complete path.
17480
17481=item L2HINIT_NAME
17482
17483The standard user-specific configuration filename is F<.latex2html-init>.
17484This environment variable will override this name.
17485
17486=item HOME
17487
17488Evaluated if the system does not know about "home" directories (like
17489DOS, WinXX, OS/2, ...) to determine the path to F<$L2HINIT_NAME>.
17490
17491=item TEXE_DONT_INCLUDE, TEXE_DO_INCLUDE
17492
17493Used internally for communication with B<texexpand>.
17494
17495=item TEXINPUTS
17496
17497Used to find TeX includes of all sorts.
17498
17499=back
17500
17501=head1 PROBLEMS
17502
17503For information on various problems and remedies see the WWW online
17504documentation or the documents available in the distribution.
17505An online bug reporting form and various archives are available at
17506F<http://www.latex2html.org/>
17507
17508There is a mailing list for discussing B<LaTeX2HTML>: C<latex2html@tug.org>
17509
17510=head1 AUTHOR
17511
17512Nikos Drakos,  Computer Based Learning Unit, University of Leeds
17513E<lt>nikos@cbl.leeds.ac.ukE<gt>. Several people have contributed
17514suggestions, ideas, solutions, support and encouragement.
17515
17516The B<pstoimg> script was written by Marek Rouchal
17517E<lt>marek@saftsack.fs.uni-bayreuth.deE<gt>
17518as a generalisation of the B<pstogif> utility to allow graphic formats
17519other than GIF to be created. Various options and enhancements have
17520been added by Ross Moore.
17521Some of the code is based upon the pstoppm.ps postscript program
17522originally written by Phillip Conrad (Perfect Byte, Inc.)
17523and modified by L. Peter Deutsch (Aladdin Enterprises).
17524
17525=head1 SEE ALSO
17526
17527See the WWW online documentation or the F<$LATEX2HTMLDIR/doc/manual.ps>
17528file for more detailed information and examples.
17529
17530L<pstoing>, L<texexpand>
17531
17532=cut
17533
17534