"Fossies" - the Fresh Open Source Software Archive

Member "latex2html-2021.2/versions/html3_1.pl" (1 Jul 2021, 86978 Bytes) of package /linux/www/latex2html-2021.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "html3_1.pl" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2021_vs_2021.2.

    1 # -*- perl -*-
    2 #
    3 ### File: html3.1.pl
    4 ### Language definitions for HTML 3.1 (Math)
    5 ### Written by Marcus E. Hennecke <marcush@leland.stanford.edu>
    6 ### Version 0.3,  April 3, 1997
    7 
    8 ###   extended math-parsing, when $NO_SIMPLE_MATH is set
    9 ### Version 0.4,  July, August 1997  by Ross Moore
   10 
   11 ###   extended math-parsing, when $NO_SIMPLE_MATH is set
   12 ### Version 0.5, many modifications and extensions
   13 ### made during 1997 and 1998  by Ross Moore
   14 
   15 
   16 ## Copyright (C) 1995 by Marcus E. Hennecke
   17 ## This program is free software; you can redistribute it and/or modify
   18 ## it under the terms of the GNU General Public License as published by
   19 ## the Free Software Foundation; either version 2 of the License, or
   20 ## (at your option) any later version.
   21 
   22 ## This program is distributed in the hope that it will be useful,
   23 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
   24 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   25 ## GNU General Public License for more details.
   26 ## You should have received a copy of the GNU General Public License
   27 ## along with this program; if not, write to the Free Software
   28 ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   29 
   30 if ($HTML_OPTIONS =~ /math/) {
   31     do { $DOCTYPE = ''; $STRICT_HTML = 0 }
   32         unless ($NO_SIMPLE_MATH||$NO_MATH_PARSING);
   33 }
   34 
   35 #########################
   36 ## Support HTML 3.0 math
   37 
   38 #### Mathematical Formulas
   39 
   40 package main;
   41 
   42 sub do_env_math {
   43     local($_) = @_;
   44     local($math_mode, $failed, $labels, $comment,$img_params) = ("inline",'','');
   45     $failed = (/$htmlimage_rx|$htmlimage_pr_rx/); # force an image
   46     local($attribs, $border);
   47     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
   48     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
   49     local($saved) = $_;
   50     ($labels, $comment, $_) = &process_math_env($math_mode,$_);
   51     if ($failed) {
   52     $_ = join ('', $comment, $labels 
   53         , ($USING_STYLES ? '<SPAN CLASS="MATH">' : '')
   54             , &process_undefined_environment("tex2html_wrap", $id, $saved)
   55         , ($USING_STYLES ? '</SPAN>' : ''))
   56     } elsif ($NO_SIMPLE_MATH) {
   57         if ($USING_STYLES) {
   58             $_ = join('', $comment, $labels
   59             , '<SPAN CLASS="MATH">', $_ , "</SPAN>");
   60     } else {
   61             $_ = join('', $comment, $labels, " ", $_ );
   62     }
   63     } else {
   64         $_ = join('', $comment, $labels, "<MATH CLASS=\"INLINE\">\n$_\n</MATH>");
   65     }
   66     if (($border||($attributes))&&($HTML_VERSION > 2.1 )) { 
   67     &make_table( $border, $attribs, '', '', '', $_ )
   68     } else { $_ }
   69 }
   70 
   71 $math_start_rx = "(\\\$|\\\\\\(|\\\\math\\b)(\\begin(($O|$OP)\\d+($C|$CP))tex2html_wrap\\4)?";
   72 $math_end_rx = "(\\end(($O|$OP)\\d+($C|$CP))tex2html_wrap\\7)?(\\\$|\\\\\\)|\\\\endmath\\b)";
   73 
   74 sub do_env_tex2html_wrap {
   75     local($_) = @_;
   76     local($math_mode, $failed, $labels, $comment,$img_params) = ("inline",'','');
   77     $failed = (/$htmlimage_rx|$htmlimage_pr_rx/); # force an image
   78     local($attribs, $border);
   79     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
   80     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
   81     s/^\s*|\s*$//gm;
   82     local($saved) = $_;
   83 #   if (s/^\\\(|^\$|^\\math|\\\)$|\$$|\\endmath//g) {}
   84     if (s/^$math_start_rx|${math_end_rx}$//g) {}
   85     elsif (/^\\ensuremath/om) { }
   86     else { $failed = 1 }; # catch non-math environments or commands
   87     ($labels, $comment, $_) = &process_math_env($math_mode,$_);
   88     if ($failed) {
   89     $_ = join ('', $comment, $labels 
   90              , &process_undefined_environment("tex2html_wrap", $id, $saved));
   91     } elsif ($NO_SIMPLE_MATH) {
   92         # no need for comment/labels if already inside a math-env
   93         if (defined $math_outer) { s/^\s*|\s*$//g }
   94     else { $_ = $comment . $labels ." ".$_; }
   95     } else { 
   96         $_ = $comment . $labels . "<MATH CLASS=\"INLINE\">\n$_\n</MATH>";
   97     }
   98     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
   99     &make_table( $border, $attribs, '', '', '', $_ ) 
  100     } else { $_ }
  101 }
  102 
  103 sub do_env_tex2html_wrap_inline {
  104     local($_) = @_;
  105     local($math_mode, $failed, $labels, $comment) = ("inline",'','');
  106     $failed = (/$htmlimage_rx|$htmlimage_pr_rx/); # force an image
  107     local($attribs, $border);
  108     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
  109     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
  110     local($saved) = $_;
  111 #   s/(^\s*(\$|\\\()\s*|\s*(\$|\\\))\s*$)//g; # remove the \$ signs or \(..\)
  112 #   s/^\\ensuremath(($O|$OP)\d+($C|$CP))(.*)\1/$4/; # remove an ensuremath wrapper
  113     if (s/^$math_start_rx|$math_end_rx$//gs ) {}
  114     elsif (s/^\\ensuremath(($O|$OP)\d+($C|$CP))(.*)\1/$4/){} # remove an ensuremath wrapper
  115     else { $failed = 1 }
  116     s/\\(begin|end)(($O|$OP)\d+($C|$CP))tex2html_wrap\w*\2//g; # remove wrappers
  117     $_ = &translate_environments($_) unless (($NO_SIMPLE_MATH)||($failed));
  118     ($labels, $comment, $_) = &process_math_env($math_mode,$_);
  119     if ($failed) {
  120         if ($USING_STYLES) {
  121             $env_id =~ s/\"$/ image\"/;
  122             $env_id = ' CLASS="MATH"' if ($env_id =~ /^\s*$/);
  123             $_ = join ('', $labels, $comment, "<SPAN$env_id>"
  124                 , &process_undefined_environment("tex2html_wrap_inline", $id, $saved)
  125                 , "</SPAN>");
  126         } else {
  127             $_ = join ('', $labels, $comment
  128                 , &process_undefined_environment("tex2html_wrap_inline", $id, $saved));
  129         }
  130     } elsif (($NO_SIMPLE_MATH)&&($USING_STYLES)) {
  131         $env_id = ' CLASS="MATH"' if ($env_id =~ /^\s*$/);
  132         $_ = join('', $labels, $comment, "<SPAN$env_id>", $_, "</SPAN>");
  133     } elsif ($NO_SIMPLE_MATH) {
  134         $_ = join('', $labels, $comment, $_);
  135     } else { 
  136         $_ = join('', $labels, $comment, "<MATH CLASS=\"INLINE\">\n$_\n</MATH>");
  137     }
  138     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
  139     &make_table( $border, $attribs, '', '', '', $_ ) 
  140     } else { $_ }
  141 }
  142 
  143 # Allocate a fixed width for the equation-numbers:
  144 #$seqno = "<TD WIDTH=\"10\" ALIGN=\"CENTER\">\n";
  145 $mvalign = ' VALIGN="MIDDLE"';
  146 
  147 sub do_env_equation {
  148     local($_) = @_;
  149     local($math_mode, $failed, $labels, $comment) = ("equation",'','');
  150     $failed = (/$htmlimage_rx|$htmlimage_pr_rx/); # force an image
  151     local($attribs, $border);
  152     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
  153     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
  154     local($saved) = $_;
  155     local($sbig,$ebig);
  156     ($sbig,$ebig) = ('<BIG>','</BIG>')
  157     if (($DISP_SCALE_FACTOR)&&($DISP_SCALE_FACTOR >= 1.2 ));
  158     local($math_start,$math_end)= ($sbig,$ebig);
  159 
  160     local($eqno) = '&nbsp;'; # spacer, when no numbering
  161     local($seqno) = join('',"\n<TD$eqno_class WIDTH=10 ALIGN=\""
  162                          , (($EQN_TAGS =~ /L/)? 'LEFT': 'RIGHT')
  163                  , "\">\n");
  164     do { # include the equation number, using a <TABLE>
  165     $global{'eqn_number'}++;
  166     $eqno = join('', $EQNO_START
  167         , &simplify(&translate_commands('\theequation'))
  168         , $EQNO_END);
  169     } unless ((s/(\\nonumber|\\notag)//gm)||(/\\tag/));
  170     if (s/\\tag(\*)?//m){
  171     # AmS-TEX line-number tags.
  172     local($nobrack,$before) = ($1,$`);
  173     $_ = $';
  174     s/next_pair_pr_rx//om;
  175     if ($nobrack) { $eqno = $2 }
  176     else { $eqno = join('',$EQNO_START, $2, $EQNO_END ) }
  177     $_ = $before;
  178     }
  179 
  180     local($halign) = " ALIGN=\"CENTER\"" unless $FLUSH_EQN;
  181     if ($EQN_TAGS =~ /L/) {
  182     # equation number on left
  183     ($math_start,$math_end) = 
  184         ( "\n<TABLE$env_id WIDTH=\"100%\" ALIGN=\"CENTER\""
  185         . (($border)? " BORDER=\"$border\"" : '')
  186         . (($attribs)? " $attribs" : '')
  187         . ">\n<TR$mvalign>" . $seqno . $eqno
  188         . "</TD>\n<TD$halign NOWRAP>$sbig"
  189         , "$ebig</TD>\n</TR></TABLE>");
  190     $border = $attribs = $env_id = '';
  191     } else {
  192     # equation number on right
  193     ($math_start,$math_end) = 
  194         ("\n<TABLE$env_id WIDTH=\"100%\" ALIGN=\"CENTER\""
  195         . (($border)? " BORDER=\"$border\"" : '')
  196         . (($attribs)? " $attribs" : '')
  197         . ">\n<TR$mvalign><TD></TD>"
  198         . "<TD$halign NOWRAP>$sbig"
  199         , "$ebig</TD>". $seqno . $eqno ."</TD></TR>\n</TABLE>");
  200     $border = $attribs = $env_id = '';
  201     }
  202 
  203     ($labels, $comment, $_) = &process_math_env($math_mode,$_);
  204     if ($failed) {
  205     $_ = join ('', $comment, $labels, $math_start
  206         , &process_undefined_environment('displaymath', $id, $saved)
  207         , $math_end );
  208     } elsif ($NO_SIMPLE_MATH) {
  209     $_ = join('', "<P></P><DIV$math_class>", $labels
  210         , $comment, $math_start, "\n$_\n"
  211         , $math_end, "</DIV><P></P>" );
  212     } else {
  213     $_ = join('', "<P$math_class>"
  214         , $labels, $comment, $math_start
  215         , "\n<MATH CLASS=\"EQUATION\">\n"
  216         , $_ , "\n</MATH>", $math_end );
  217     }
  218     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
  219     join('',"<BR>\n<DIV$math_class>\n"
  220         , &make_table( $border, $attribs, '', '', '', $_ )
  221         , "\n<BR CLEAR=\"ALL\">");
  222     } else { $_ }
  223 }
  224 
  225 sub do_env_displaymath {
  226     local($_) = @_;
  227     local($math_mode, $failed, $labels, $comment) = ("display",'','');
  228     $failed = (/$htmlimage_rx|$htmlimage_pr_rx/); # force an image
  229     local($attribs, $border);
  230     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
  231     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
  232     local($saved) = $_;
  233     local($sbig,$ebig);
  234     ($sbig,$ebig) = ('<BIG>','</BIG>')
  235     if (($DISP_SCALE_FACTOR)&&($DISP_SCALE_FACTOR >= 1.2 ));
  236     ($labels, $comment, $_) = &process_math_env($math_mode,$_);
  237     if ($failed) {
  238     $_ = join('', $comment, "<P$math_class>" , $labels
  239             , &process_undefined_environment("displaymath", $id, $saved )
  240             , '</P>' );
  241     } elsif ($NO_SIMPLE_MATH) {
  242     $_ =~ s/<TABLE/$ebig$&/sg; $_ =~ s/<\/TABLE>/$&$sbig/sg;
  243     $_ = "$comment\n<P></P><DIV$math_class>$labels\n$sbig$_$ebig\n</DIV><P></P>" 
  244     } else { 
  245         $_ = join('', $comment, "<P$math_class>", $labels
  246             , "$sbig\n<MATH CLASS=\"DISPLAYMATH\">\n",$_,"\n</MATH>\n$ebig</P>");
  247     }
  248     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
  249     join('',"<BR>\n<DIV$math_class>\n"
  250             , &make_table( $border, $attribs, '', '', '', $_ )
  251         , "\n<BR CLEAR=\"ALL\">");
  252     } else { $_ }
  253 }
  254 
  255 ### Some Common Structures
  256 
  257 ## Declare math mode and take care of sub- and superscripts. Also make
  258 ## sure to treat curly braces right.
  259 sub make_math {
  260     local($math_mode,$math_style,$math_face,$_) = @_;
  261     # Do spacing
  262     s/\\,/;SPMthinsp;/g;
  263     s/\\!/;SPMnegsp;/g;
  264     s/\\:/;SPMsp;/g;
  265     s/\\;/;SPMthicksp;/g;
  266     s/((^|[^\\])(\\\\)*)\\ /$1\\space /g; # convert \ to \space
  267     s/\\limits/\&limits;/g; # preserve the \limits commands
  268 
  269     # Find all _ and ^, but not \_ and \^
  270     s/\\_/\\underscore/g;
  271     s/\\^/\\circflex/g;
  272 
  273 #RRM:  The following code is just plain wrong !!!
  274 #    local(@terms) = split(/([_^])/);
  275 #    local($math,$i,$subsup,$level);
  276 #    # Do the sub- and superscripts
  277 #    $math = $terms[$[];
  278 #    for ( $i = $[+1; $i <= $#terms; $i+=2 ) {
  279 #   $subsup = ( $terms[$i] eq "_" ? "SUB" : "SUP" );
  280 #   $_ = $terms[$i+1];
  281 #   if ( s/$next_pair_rx// ) {
  282 #       $math .= "<$subsup>$2</$subsup>$_";
  283 #   } else {
  284 #       s/^\s*(\w|\\[a-zA-Z]+)//;
  285 #       $math .= "<$subsup>$1</$subsup>$_";
  286 #   };
  287 #    };
  288 #    $_ = $math;
  289 #RRM: This works much better (from   &simple_math_env ).
  290     if ($NO_SIMPLE_MATH) {
  291     s/\&ldots;/.../g;
  292     $_ = &translate_math_commands($math_mode,$math_style,$math_face,0,$_);
  293     # remove redundant tags
  294     s/<I>\s*<\/I>//go;
  295     s/<\/I>(\s*)<I>/$1/go;
  296     } else {
  297     s/\^$any_next_pair_rx/<SUP>$2<\/SUP>/go;
  298     s/_$any_next_pair_rx/<SUB>$2<\/SUB>/go;
  299     s/\^(\\[a-zA-Z]+|.)/<SUP>$1<\/SUP>/g;
  300     s/_(\\[a-zA-Z]+|.)/<SUB>$1<\/SUB>/g;
  301     }
  302 
  303     s/\\underscore/\\_/g;
  304     s/\\circflex/\\^/g;
  305     s/&limits;//g; # not implemented, except via an image
  306 
  307     # Translate all commands inside the math environment
  308     $_ = &translate_commands($_) unless ($NO_SIMPLE_MATH);
  309 
  310 
  311     if ($NO_SIMPLE_MATH) {
  312     s/&lbrace;/{/g; s/&rbrace;/}/g;
  313     s/\s*&times;\s*/ <TT>x<\/TT> /g;
  314 #   s/\s*&times;\s*/ &#215; /g;
  315     s/\s*&div;\s*/ &#247; /g;
  316     s/\s*&circ?;\s*/<TT>o<\/TT>/g;
  317     s/\s*&ast;\s*/ <TT>\*<\/TT> /g;
  318     s/\s*&l?dots;\s*/.../g;
  319     s/\s*&mid;\s*/ | /g;
  320     s/\s*&vert;\s*/\|/g;
  321     s/\s*&parallel;\s*/ || /g;
  322     s/;SPM(thin)?sp;/&nbsp;/g; s/&thinsp;/&nbsp;/g; s/&sp;/&nbsp;/g;
  323     s/;SPMthicksp;/ &nbsp;/g; s/&thicksp;/ &nbsp;/g; s/&ensp; /&nbsp;/g;
  324 #        &replace_math_constructions($math_mode);
  325     } else { 
  326     # Inside <MATH>, { and } have special meaning. Thus, need &lcub;
  327     # and &rcub;
  328 #    s/{/&lcub;/g; s/}/&rcub;/g; # Where are these defined ?
  329     s/{/&lbrace;/g;
  330     s/}/&rbrace;/g;
  331 
  332     # Remove the safety markers for math-entities
  333     s/(\&\w+)#\w+;/$1;/g; 
  334 
  335     # Substitute <BOX> and </BOX> with { and } to improve readability
  336     # on browsers that do not support math.
  337     s/<BOX>/$level++;'{'/ge;
  338     s/<\/BOX>/$level--;'}'/ge;
  339     # Make sure braces are matching.
  340     $_ .= '}' if ( $level > 0 );
  341     $_ = '{'.$_ if ( $level < 0 );
  342 #   s/<\/?SUB>/_/g; s/<\/?SUP>/^/g;
  343     }
  344 
  345     # contract spaces
  346     s/(\s)\s+/\1/g;
  347 
  348     # remove bogus entities
  349     s/;SPMnegsp;//g;
  350     s/\&limits;/\\limits/g;
  351 
  352     # remove white space at the extremities
  353 #   do{ $*=1; s/(^\s+|\s+$)//; $*=0; } unless ($NO_SIMPLE_MATH);
  354     s/^\s//o;s/\s$//m;
  355 
  356     $_;
  357 }
  358 
  359 
  360 
  361 ## Fractions
  362 sub do_math_cmd_frac {
  363     local($_) = @_;
  364     local($fbarwidth,$optwidth) = &get_next_optional_argument;
  365     local($numer,$denom);
  366     local($cmd) = $cmd;
  367     if ($optwidth) { $optwidth = ''
  368     unless ($preamble =~ /[\{,]amstex[,\}]/ ) }
  369     $cmd = "frac" unless ($cmd =~ /frac/);
  370 
  371     $numer = &get_next_token();
  372 #    $numer = &missing_braces unless (
  373 #   (s/$next_pair_pr_rx/$numer = $2;''/e)
  374 #   ||(s/$next_pair_rx/$numer = $2;''/e ));
  375     $denom = &get_next_token();
  376 #    $denom = &missing_braces unless (
  377 #   (s/$next_pair_pr_rx/$denom = $2;''/e)
  378 #   ||(s/$next_pair_rx/$denom = $2;''/e ));
  379 
  380     if (($numer =~ /^\d$/)&&($denom =~ /^\d$/)) {
  381     local($frac) = &check_frac_entity($numer,$denom);
  382     if ($frac) {
  383         if ($NO_SIMPLE_MATH) { return ($frac , $_) }
  384         else { return ($frac . $_) }
  385     }
  386     }
  387     if ($NO_SIMPLE_MATH) {
  388     local($after) = $_;
  389     local($fracstyle) = "";
  390     $fracstyle = "\\textstyle" if (
  391         ($mode =~ /display|equation|eqnarray/)
  392         && ($numer =~ /^[\d\s]+$/)&& ($denom =~ /^[\d\s]+$/));
  393 
  394     ( &process_math_in_latex( $mode, $math_style, $slevel
  395         , "{$fracstyle\\$cmd${optwidth}{$numer}{$denom}}") , $after )
  396     } else { "<BOX>$numer<OVER>$denom</BOX>$_" }
  397 }
  398 
  399 sub check_frac_entity {
  400     local($num,$den) = @_;
  401     local($ent,$cset,$char) = ("frac".$num.$den,$CHARSET,$char);
  402     $cset =~ s/\-/_/go; $cset = "\$${cset}_character_map{$ent}";
  403     eval ("\$char = $cset");
  404     $char;
  405     '';  # browsers don't recognise these characters yet.
  406 }
  407 
  408 ## Roots
  409 sub do_math_cmd_sqrt {
  410     local($_) = @_;
  411     local($n) = &get_next_optional_argument;
  412     local($surd) = &get_next_token();
  413     if ($NO_SIMPLE_MATH) { local($after) = $_;
  414         ( &process_math_in_latex( $mode, $math_style, $slevel
  415         , "\\sqrt".( $n ? "[$n]" : '') . "{$surd}") , $after )
  416     } else { $n ? "<ROOT>$n<OF>$surd</ROOT>$_" : "<SQRT>$surd</SQRT>$_"; }
  417 }
  418 
  419 sub do_math_cmd_thin_sp {
  420     '&thinsp;';
  421 }
  422 sub do_math_cmd_norm_sp {
  423     '&sp;';
  424 }
  425 sub do_math_cmd_thick_sp {
  426     '&ensp;';
  427 }
  428 
  429 %mathnomacros = (
  430                  'omicron', 'o',
  431          'Alpha', 'A', 'Beta', 'B', 'Epsilon', 'E', 'Zeta', 'Z',
  432          'Eta', 'H', 'Iota', 'J', 'Kappa', 'K', 'Mu', 'M', 'Nu', 'N',
  433          'Omicron', 'O', 'Rho', 'R', 'Tau', 'T', 'Chi', 'X'
  434          );
  435 
  436 do {
  437     local($key, $val);
  438     foreach $key (keys %mathnomacros) {
  439     $val = $mathnomacros{$key};
  440     $LaTeXmacros .= "\\providecommand{\\$key}{\\textrm{$val}}\n";
  441     }
  442 };
  443 
  444 %greekentities = (
  445          # Greek letters  %ISOgrk3;  and  %HTMLsymbol;
  446          'alpha', 'alpha', 'beta', 'beta', 'gamma', 'gamma',
  447          'delta', 'delta', 'epsilon', 'epsi', 'varepsilon', 'epsiv',
  448          'zeta', 'zeta', 'eta', 'eta', 'theta', 'thetas',
  449          'vartheta', 'thetav', 'iota', 'iota', 'kappa', 'kappa',
  450          'lambda', 'lambda', 'mu', 'mu',
  451          'nu', 'nu', 'xi', 'xi', 'pi', 'pi', 'varpi', 'piv',
  452          'rho', 'rho', 'varrho', 'rhov', 'sigma', 'sigma',
  453          'varsigma', 'sigmav', 'tau', 'tau', 'upsilon', 'upsi',
  454          'phi', 'phis', 'varphi', 'phiv', 'chi', 'chi',
  455          'psi', 'psi', 'omega', 'omega',
  456          'Gamma', 'Gamma', 'Delta', 'Delta', 'Theta', 'Theta',
  457          'Lambda', 'Lambda', 'Xi', 'Xi', 'Pi', 'Pi',
  458          'Sigma', 'Sigma', 'Upsilon', 'Upsi', 'Phi', 'Phi',
  459          'Psi', 'Psi', 'Omega', 'Omega',
  460          'Alpha', 'Alpha', 'Beta', 'Beta', 'Epsilon', 'Epsilon',
  461          'Zeta', 'Zeta', 'Eta', 'Eta', 'Iota', 'Iota',
  462          'Kappa', 'Kappa', 'Mu', 'Mu', 'Nu', 'Nu',
  463          'Omicron', 'Omicron', 'Rho', 'Rho', 'Tau', 'Tau', 'Chi', 'Chi',
  464          'straightepsilon', 'epsis', 'omicron', 'omicron'
  465 );
  466 
  467 %mathentities = (
  468          # Ellipsis  %ISOpub 
  469          'ldots', 'hellip', 'cdots', 'cdots', 'vdots', 'vellip',
  470          'ddots', 'ddots', 'dotfill', 'dotfill',
  471 ### Mathematical Symbols
  472          %greekentities ,
  473 
  474          # Binary operators   %ISOnum  %ISOamsb
  475          'pm', 'plusmn', 'mp', 'mnplus', 'times', 'times',
  476          'div', 'divide', 'ast', 'ast', 'star', 'sstarf',
  477          'circ', 'cir', 'bullet', 'bull', 'cdot', 'sdot',
  478          'cap', 'cap', 'cup', 'cup', 'uplus', 'uplus',
  479          'sqcap', 'sqcap', 'sqcup', 'sqcup',
  480          'vee', 'or', 'wedge', 'and', 'setminus', 'setmn',
  481          'wr', 'wreath', 'diamond', 'diam',
  482          'bigtriangleup', 'xutri', 'bigtriangledown', 'xdtri',
  483          'triangleleft', 'ltri', 'triangleright', 'rtri',
  484          'lhd', '', 'rhd', '', 'unlhd', '', 'unrhd', '',
  485          'oplus', 'oplus', 'ominus', 'ominus', 'otimes', 'otimes',
  486          'oslash', 'osol', 'odot', 'odot', 'bigcirc', 'xcirc',
  487          'dagger', 'dagger', 'ddagger', 'Dagger', 'amalg', 'amalg',
  488 
  489          # Relations  %ISOamsr  %ISOtech
  490          'leq', 'le', 'le', 'le', 'prec', 'pr', 'preceq', 'pre', 'll', 'Lt',
  491          'subset', 'sub', 'subseteq', 'sube', 'sqsubset', 'sqsub',
  492          'sqsubseteq', 'sqsube', 'in', 'isin', 'vdash', 'vdash',
  493          'geq', 'ge', 'ge', 'ge', 'succ', 'sc', 'succeq', 'sce', 'gg', 'Gt',
  494          'supset', 'sup', 'supseteq', 'supe', 'sqsupset', 'sqsup',
  495          'sqsupseteq', 'sqsupe', 'ni', 'ni', 'dashv', 'dashv', 'owns', 'ni',
  496          'equiv', 'equiv', 'sim', 'sim', 'simeq', 'sime', 'smallamalg', 'samalg',
  497          'asymp', 'asymp', 'approx', 'ap', 'cong', 'cong',
  498          'neq', 'ne', 'ne', 'ne', 'doteq', 'esdot', 'propto', 'prop',
  499          'models', 'models', 'perp', 'perp', 'mid', 'mid',
  500          'parallel', 'par', 'bowtie', 'bowtie', 'Join', '',
  501          'smile', 'smile', 'frown', 'frown', 
  502          'vee', 'or', 'land', 'and', 'lor', 'or',
  503 
  504          # Arrows and pointers  %ISOamsa  %ISOnum
  505          'leftarrow', 'larr', 'rightarrow', 'rarr',
  506          'uparrow', 'uarr', 'downarrow', 'darr',
  507          'Leftarrow', 'lArr', 'Rightarrow', 'rArr',
  508          'Uparrow', 'uArr', 'Downarrow', 'dArr',
  509          'longleftarrow', 'larr', 'longrightarrow', 'rarr',
  510          'Longleftarrow', 'xlArr', 'Longrightarrow', 'xrArr',
  511          'leftrightarrow', 'harr', 'Leftrightarrow', 'hArr',
  512          'longleftrightarrow', 'xharr', 'Longleftrightarrow', 'xhArr',
  513          'updownarrow', 'varr', 'Updownarrow', 'vArr',
  514          'mapsto', 'map', 'longmapsto', 'map',
  515          'hookleftarrow', 'larrhk', 'hookrightarrow', 'rarrhk',
  516          'nearrow', 'nearr', 'searrow', 'drarr',
  517          'swarrow', 'dlarr', 'nwarrow', 'nwarr',
  518          'leftharpoonup', 'lharu', 'leftharpoondown', 'lhard',
  519          'rightharpoonup', 'rharu', 'rightharpoondown', 'rhard',
  520          'rightleftharpoons', 'rlhar2', 'leadsto', '',
  521          'gets', 'larr', 'to', 'rarr', 'iff', 'iff',
  522 
  523          # Various other symbols   %ISOpub  %ISOamso  %ISOnum  %ISOtech
  524          'aleph', 'aleph', 'hbar', 'planck',
  525          'imath', 'inodot', 'jmath', 'jnodot', 'ell', 'ell',
  526          'wp', 'weierp', 'Re', 'real', 'Im', 'image',
  527          'beth', 'beth', 'gimel', 'gimel', 'daleth', 'daleth',
  528          'emptyset', 'empty', 'nabla', 'nabla', 'surd', 'radic',
  529          'top', 'top', 'bot', 'bottom', 'angle', 'ang',
  530          'forall', 'forall', 'exists', 'exist', 'neg', 'not',
  531          'flat', 'flat', 'natural', 'natur', 'sharp', 'sharp',
  532          'partial', 'part', 'infty', 'infin', 'sphericalangle', 'angsph',
  533          'varprime', 'vprime', 'sbs', 'sbsol', 'yen', 'yen',
  534          'Box', '', 'Diamond', '', 'triangle', 'utri',
  535          'clubsuit', 'clubs', 'diamondsuit', 'diams',
  536          'heartsuit', 'hearts', 'spadesuit', 'spades',
  537          'checkmark', 'check', 'maltese', 'malt',
  538          'backslash', 'bsol', 'circledR', 'reg', 'centerdot', 'middot',
  539          'prime', 'prime', 'square', 'square',
  540 
  541          # Integral type entities   %ISOamsb
  542          'sum', 'sum', 'prod', 'prod', 'coprod', 'coprod',
  543          'int', 'int', 'oint', 'conint',
  544 
  545          # Delimiters  %ISOamsc   %ISOtech
  546          'lfloor', 'lfloor', 'rfloor', 'rfloor',
  547          'lceil', 'lceil', 'rceil', 'rceil',
  548          'langle', 'lang', 'rangle', 'rang',
  549          'lbrace', 'lcub', 'rbrace', 'rcub',
  550          'lbrack', 'lsqb', 'rbrack', 'rsqb',
  551          'Vert', 'Verbar', 'vert', 'vert',
  552 
  553          # AMS package
  554          # Greek letters
  555          'digamma', 'gammad', 'varkappa', 'kappav',
  556 
  557          # Delimiters %ISOamsc
  558          'ulcorner', 'ulcorn', 'urcorner', 'urcorn',
  559          'llcorner', 'dlcorn', 'lrcorner', 'drcorn',
  560          'leftparengtr', 'lpargt', 'rightparengtr', 'rpargt',
  561 
  562          # Arrows  %ISOamsa 
  563          'dashrightarrow', '', 'dashleftarrow', '',
  564          'leftleftarrows', 'larr2', 'leftrightarrows', 'lrarr2',
  565          'Lleftarrow', 'lArr', 'twoheadleftarrow', 'Larr',
  566          'leftarrowtail', 'larrtl', 'looparrowleft', 'larrlp',
  567          'leftrightharpoons', 'lrhar2', 'curvearrowleft', 'cularr',
  568          'circlearrowleft', 'olarr', 'Lsh', 'lsh',
  569          'upuparrows', 'uarr2', 'upharpoonleft', 'uharl',
  570          'downharpoonleft', 'dharl', 'multimap', 'mumap',
  571          'leftrightsquigarrow', 'harrw',
  572          'rightrightarrows', 'rarr2', 'rightleftarrows', 'rlarr2',
  573          'Rrightarrow', 'rArr', 'twoheadrightarrow', 'Rarr',
  574          'rightarrowtail', 'rarrtl', 'looparrowright', 'rarrlp',
  575          'rightleftharpoons', 'rlhar2', 'curvearrowright', 'curarr',
  576          'circlearrowright', 'orarr', 'Rsh', 'rsh',
  577          'downdownarrows', 'darr2', 'upharpoonright', 'uharr',
  578          'downharpoonright', 'dharr','rightsquigarrow', 'rarrw',
  579 
  580          # Negated arrows  %ISOamsa
  581          'nleftarrow', 'nlarr', 'nrightarrow', 'nrarr',
  582          'nLeftarrow', 'nlArr', 'nRightarrow', 'nrArr',
  583          'nleftrightarrow', 'nharr', 'nLeftrightarrow', 'nhArr',
  584 
  585          # Binary relations  %ISOamsr  %ISOamsb
  586          'leqq', 'lE', 'leqslant', 'les', 'eqslantless', 'els',
  587          'lesssim', 'lsim', 'lessapprox', 'lap', 'approxeq', 'ape',
  588          'lessdot', 'ldot', 'lll', 'Ll', 'Ll', 'Ll', 'llless', 'Ll',
  589          'lessgtr', 'lg', 'lesseqgtr', 'leg', 'lesseqqgtr', 'lEg',
  590          'backcong', 'bcong', 
  591          'barwedge', 'barwed', 'doublebarwedge', 'Barwed',
  592          'doublecap', 'Cap', 'doublecup', 'Cup',
  593          'curlyvee', 'cuvee', 'curlywedge', 'cuwed',
  594          'divideontimes', 'divonx', 'intercal', 'intcal',
  595          'doteqdot', 'eDot', 'risingdotseq', 'erDot', 'Doteq', 'eDot',
  596          'leftthreetimes', 'lthree', 'rightthreetimes', 'rthree',
  597          'ltimes', 'ltimes', 'rtimes', 'rtimes',
  598          'boxminus', 'minusb', 'boxplus', 'plusb', 'boxtimes', 'timesb',
  599          'circledast', 'oast', 'circledcirc', 'ocirc', 'circleddash', 'odash',
  600          'dotplus', 'plusdo', 'dotsquare', 'sdotb', 'smallsetminus', 'ssetmn',
  601          'fallingdotseq', 'efDot', 'backsim', 'bsim',
  602          'backsimeq', 'bsime', 'subseteqq', 'subE', 'Subset', 'Sub',
  603          'curlypreceq', 'cupre', 'curlyeqprec', 'cuepr', 
  604          'precsim', 'prsim', 'precapprox', 'prap', 
  605          'vartriangleleft', 'vltri', 'trianglelefteq', 'ltrie', 
  606          'vDash', 'vDash', 'Vvdash', 'Vvdash', 'Vdash', 'Vdash',
  607          'smallsmile', 'ssmile', 'smallfrown', 'sfrown', 
  608          'bumpeq', 'bumpe', 'Bumpeq', 'bump',
  609          'coloneq', 'colone', 'eqcolon', 'ecolon',
  610          'geqq', 'gE', 'geqslant', 'ges', 'eqslantgtr', 'egs',
  611          'gtrsim', 'gsim', 'gtrapprox', 'gap', 'gtrdot', 'gsdot',
  612          'ggg', 'Gg', 'Gg', 'Gg', 'gggtr', 'Gg',
  613          'gtrless', 'gl', 'gtreqless', 'gel',
  614          'gtreqqless', 'gEl', 'eqcirc', 'ecir', 'circeq', 'cire',
  615          'triangleeq', 'trie', 'thicksim', 'thksim',
  616          'thickapprox', 'thkap', 'supseteqq', 'supE', 'Supset', 'Sup',
  617          'succcurlyeq', 'sccue', 'veebar', 'veebar',
  618          'curlyeqsucc', 'cuesc', 'succsim', 'scsim',
  619          'succapprox', 'scap', 'vartriangleright', 'vrtri',
  620          'trianglerighteq', 'rtrie',
  621          'shortmid', 'smid', 'shortparallel', 'spar',
  622          'between', 'twixt', 'pitchfork', 'fork', 'bigstar', 'starf',
  623          'varpropto', 'vprop', 'because', 'becaus',
  624          'therefore', 'there4', 'backepsilon', 'bepsi',
  625          'blacksquare', 'squf', 'lozenge', 'loz', 'blacklozenge', 'lozf',
  626          'blacktriangle', 'utrif', 'blacktriangledown', 'dtrif',
  627          'blacktriangleleft', 'ltrif', 'blacktriangleright', 'rtrif',
  628 
  629          # Negated binary relations  %ISOamsn 
  630          'gnapprox', 'gnap', 'gneq', 'gne', 'gneqq', 'gnE', 
  631          'lnapprox', 'lnap', 'lneq', 'lne', 'lneqq', 'lnE', 
  632          'gnsim', 'gnsim', 'gvertneqq', 'gvnE',
  633          'lnsim', 'lnsim', 'lvertneqq', 'lvnE',
  634          'nsim', 'nsim', 'nsimeq', 'nsime',
  635          'napprox', 'nap', 'ncong', 'ncong', 'nequiv', 'nequiv',
  636          'ngeq', 'nge', 'ngeqq', 'ngE', 'ngeqslant', 'nges', 'ngtr', 'ngt',
  637          'nleq', 'nle', 'nleqq', 'nlE', 'nleqslant', 'nles', 'nless', 'nlt',
  638          'ntriangleleft', 'nltri', 'ntrianglelefteq', 'nltrie', 
  639          'ntriangleright', 'nrtri', 'ntrianglerighteq', 'nrtrie',
  640          'nmid', 'nmid', 'nparallel', 'npar',
  641          'nprec', 'npr', 'npreceq', 'npre', 'nsucc', 'nps', 'nsucceq', 'npse',
  642          'nshortmid', 'nsmid', 'nshortparallel', 'nspar',
  643          'nsubset', 'nsub', 'nsubseteq', 'nsube', 'nsubseteqq', 'nsubE',
  644          'nsupset', 'nsup', 'nsupseteq', 'nsupe', 'nsupseteqq', 'nsupE',
  645          'nvdash', 'nvdash', 'nvDash', 'nvDash',
  646          'nVdash', 'nVdash', 'nVDash', 'nVDash',
  647          'precnapprox', 'prnap', 'precneqq', 'prnE', 'precnsim', 'prnsim',
  648          'succnapprox', 'scnap', 'succneqq', 'scnE', 'succnsim', 'scnsim',
  649          'subsetneq', 'subne', 'subsetneqq', 'subnE',
  650          'supsetneq', 'supne', 'supsetneqq', 'supnE',
  651          'varsubsetneq', 'vsubne', 'varsubsetneqq', 'vsubnE',
  652          'varsupsetneq', 'vsupne', 'varsupsetneqq', 'vsupnE',
  653 
  654          # Binary operators
  655          'Cup', 'Cup', 'Cap', 'Cap',
  656          # miscellaneous  %ISOamso 
  657          'hslash', 'planck', 'circledS', 'oS', 
  658          'nexists', 'nexist', 'varnothing', 'empty',
  659          'measuredangle', 'angmsd',
  660          'complement', 'comp', 'backprime', 'bprime',
  661 );
  662 
  663 ## environments with alignment
  664 $array_env_rx = "array|cases|\\w*matrix";
  665 
  666 
  667 ## from AMS-packages
  668 $array_env_rx .= "|\\w*align\\w*|split|gather|multline|(fl|x|xx)?align(at|ed)?";
  669 $subAMS_array_env_rx = "\\w*align\\w*|split|gather|multline";
  670 $sub_array_env_rx .= '|'.$subAMS_array_env_rx;
  671 
  672 ## Log-like Functions
  673 @mathfunctions = ('arccos', 'arcsin', 'arctan', 'arg', 'cos', 'cosh',
  674           'cot', 'coth', 'csc', 'deg', 'dim', 'exp', 'hom',
  675           'ker', 'lg', 'ln', 'log', 'sec', 'sin', 'sinh',
  676           'tan', 'tanh', 'mod'
  677           );
  678 @limitfunctions = ('det', 'gcd', 'inf', 'lim', 'liminf'
  679            , 'limsup', 'max', 'min', 'Pr', 'sup'
  680            );
  681            
  682 foreach (@mathfunctions) {
  683     eval "sub do_math_cmd_$_\{\"<T CLASS=\\\"FUNCTION\\\">$_</T>\$_[\$[]\";}";
  684 }
  685 foreach (@limitfunctions) {
  686     eval "sub do_math_cmd_$_\{
  687     local(\$_) = \@_;
  688     s/^\\s*<SUB>/<SUB ALIGN=\\\"CENTER\\\">/ unless ( \$math_mode eq \"inline\" );
  689     \"<T CLASS=\\\"FUNCTION\\\">$_</T>\$_\";}";
  690 }
  691 
  692 
  693 sub do_math_cmd_pmod {
  694     local($_) = @_;
  695     local($mod) = &get_next_token();
  696     if ($NO_SIMPLE_MATH) { local($after) = $_;
  697     $mod = &process_math_toks($mode, $math_style, $face, $slevel, 0, $mod);
  698     join( '', "(mod $mod)", $after)
  699     } else {"(<T CLASS=\"FUNCTION\">mod</T> $mod)$_"}
  700  }
  701 
  702 sub do_math_cmd_bmod {
  703     local($_) = @_;
  704     local($mod) = '';
  705     if ($NO_SIMPLE_MATH) { join( '', " mod " , $_) }
  706     else {"(<T CLASS=\"FUNCTION\"> mod </T>)$_"}
  707  }
  708  
  709 sub do_math_cmd_circ {
  710     if ($NO_SIMPLE_MATH) { ("<TT>o</TT>","@_") }
  711     else { "o@_"}
  712 }
  713 
  714 ### Arrays
  715 sub do_env_array {
  716     local($_) = @_;
  717     if (($NO_SIMPLE_MATH)&&(!$math_mode)) {
  718 #    if ($NO_SIMPLE_MATH) {
  719         # make an image
  720         $_ = &process_math_in_latex( $mode, $style, $slevel
  721             , "\\begin{array}". $_ . "\\end{array}");
  722 #           , "\\begin{array}". $_ );
  723         return($_);
  724     } 
  725     
  726     local($failed, $labels, $comment) = ('','');
  727     local($attribs, $border);
  728     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
  729     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
  730     local($saved) = $_;
  731     local($sbig,$ebig);
  732     ($sbig,$ebig) = ('<BIG>','</BIG>')
  733     if (($DISP_SCALE_FACTOR)&&($DISP_SCALE_FACTOR >= 1.2 )
  734         &&($slevel == 0)&&(!($mode =~/inline/)));
  735 #    $failed = 1 if ($NO_SIMPLE_MATH); # simplifies the next call
  736 #    ($labels, $comment, $_) = &process_math_env($math_mode,$_);
  737     if (($failed)&&!($NO_SIMPLE_MATH)) {
  738     $_ = join ('', $labels, $comment
  739         , &process_undefined_environment("array", $id, $saved));
  740     $_ = join('','<P'
  741             , (($HTML_VERSION >2.0)? "$math_class" : '')
  742             ,'>', $labels, $comment, $_, '<BR'
  743             , (($HTML_VERSION >2.0)? " CLEAR=\"ALL\"" : '')
  744         , '>',"\n<P>");
  745     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
  746         $_ = join('',"<BR>\n<DIV$math_class>\n"
  747             , &make_table( $border, $attribs, '', '', '', $_ )
  748         , "\n<BR CLEAR=\"ALL\">");
  749     }
  750         return ($_);
  751     }
  752 
  753     local($valign) = &get_next_optional_argument;
  754     if ( $valign =~ /^\s*b/ ) { $valign = " VALIGN=\"BOTTOM\"" } 
  755     elsif ( $valign =~ /^\s*t/ ) { $valign = " VALIGN=\"TOP\"" } 
  756     elsif (($NO_SIMPLE_MATH)&&($mode=~/inline/)) { $valign = "" } 
  757     else { $valign = $mvalign };
  758     local($colspec);
  759     $colspec = &missing_braces unless (
  760     (s/$next_pair_pr_rx/$colspec = $2;''/e)
  761         ||(s/$next_pair_rx/$colspec = $2;''/e ));
  762 
  763     s/\n\s*\n/\n/g; # Remove empty lines (otherwise will have paragraphs!)
  764     local($i,@colspec,$char,$cols,$cell,$htmlcolspec,$frames,$rules);
  765     local(@rows,@cols,$border);
  766     local($colspan);
  767     
  768     $_ = &revert_array_envs($_);
  769     if ($NO_SIMPLE_MATH) {
  770         local($return) = "<TABLE$env_id>"; $env_id = '';
  771         ($htmlcolspec,$frames,$rules,$cols,@colspec) =
  772         &translate_colspec($colspec, 'TD');
  773 
  774     s/\\\\[ \t]*\[[^\]]*]/\\\\/g; # remove forced line-heights
  775         @rows = split(/\\\\/);
  776 
  777     $#rows-- if ( $rows[$#rows] =~ /^\s*$/ );
  778     foreach (@rows) {
  779         $return .= "\n<TR$valign>";
  780         @cols = split(/$html_specials{'&'}/o);
  781         for ( $i = 0; $i <= $#colspec; $i++ ) {
  782         $colspec = $colspec[$i];
  783         $colspan = 0;
  784         $cell = shift(@cols);
  785 
  786         # remove any \parbox commands, leaving the contents
  787         $cell =~ s/\\parbox[^<]*<<(\d*)>>([\w\W]*)<<\1>>/$1/g;
  788         if ($cell =~ /\\multicolumn/) {
  789             $id = $global{'max_id'}++;
  790             $cell = (($cell) ? &make_math($mode,'','', $cell) : "$cell");
  791         } else {
  792             $id = $global{'max_id'}++;
  793             $cell = (($cell) ? &make_math($mode,'','', $cell) : "$cell");
  794         }
  795         # remove leading/trailing space
  796         $cell =~ s/^\s*|\s*$//g;
  797         $cell = "\&nbsp;" if ($cell eq '');
  798 
  799         if ( $colspan ) {
  800             for ( $cellcount = 0; $colspan > 0; $colspan-- ) {
  801             $i++; $cellcount++;
  802             }
  803             $i--;
  804             $colspec =~ s/>$content_mark/ COLSPAN=$cellcount$&/;
  805         };
  806         $colspec =~ s/$content_mark/${sbig}${cell}$ebig/;
  807         $return .= $colspec;
  808         };
  809         $return .= "</TR>";
  810     };
  811     $_ = $return . "\n</TABLE>";
  812 
  813     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
  814         $_ = join('',"<BR>\n<DIV$math_class>\n"
  815         , &make_table( $border, $attribs, '', '', '', $_ )
  816         , "\n<BR CLEAR=\"ALL\">");
  817     }
  818     return ($_);
  819     }
  820 
  821     ($htmlcolspec,$frames,$rules,$cols,@colspec) =
  822     &translate_colspec($colspec, 'ITEM');
  823 
  824     s/\\\\[ \t]*\[[^\]]*]/\\\\/g; # remove forced line-heights
  825     @rows = split(/\\\\/);
  826 
  827     $#rows-- if ( $rows[$#rows] =~ /^\s*$/ );
  828     local($return) = "<ARRAY COLS=${cols}$valign>\n$htmlcolspec\n";
  829     foreach (@rows) {
  830     $return .= "<ROW>";
  831     @cols = split(/$html_specials{'&'}/o);
  832     for ( $i = 0; $i <= $#colspec; $i++ ) {
  833         $colspec = $colspec[$i];
  834         $colspan = 0;
  835         $cell = &make_math("", '', '', shift(@cols)); # May modify $colspan, $colspec
  836         if ( $colspan ) {
  837         for ( $cellcount = 0; $colspan > 0; $colspan-- ) {
  838             $colspec[$i++] =~ s/<ITEM/$cellcount++;"<ITEM"/ge;
  839         }
  840         $i--;
  841         $colspec =~ s/>$content_mark/ COLSPAN=$cellcount$&/;
  842         };
  843         $colspec =~ s/$content_mark/$cell/;
  844         $return .= $colspec;
  845     };
  846     $return .= "</ROW>\n";
  847     };
  848     $return .= "</ARRAY>\n";
  849     $failed = 1 if ($NO_SIMPLE_MATH);
  850     $return;
  851 }
  852 
  853 ### Delimiters
  854 
  855 $math_delimiters_rx = "^\\s*(\\[|\\(|\\\\{|\\\\lfloor|\\\\lceil|\\\\langle|\\/|\\||\\)|\\]|\\\\}|\\\\rfloor|\\\\rceil|\\\\rangle|\\\\backslash|\\\\\\||\\\\uparrow|\\\\downarrow|\\\\updownarrow|\\\\Uparrow|\\\\Downarrow|\\\\Updownarrow|\\.)";
  856 
  857 %ord_brackets = ( 'le' , '{', 're', '}', 'lk', '[', 'rk', ']' );
  858 
  859 ### Variable-sized operators
  860 
  861 $var_sized_ops_rx = "(sum|(co)?prod|(o|i+|idots)?int|big(cap|cup|vee|wedge|o(dot|times|plus)|uplus))";
  862 
  863 $var_limits_rx = "(var(inj|proj)?lim(sup|inf)?)";
  864 $arrow_over_ops_rx = "((ov|und)er(left|right)+arrow)";
  865 
  866 
  867 sub do_math_cmd_left {
  868     local($_) = @_;
  869     s/$math_delimiters_rx//;
  870     $failed = 1 if ($NO_SIMPLE_MATH);
  871     "<BOX>" . ( $1 && $1 ne "." ? "$1<LEFT>" : "" ) . $_ .
  872     ( /\\right/ ? "" : "</BOX>" );
  873 }
  874 
  875 sub do_math_cmd_right {
  876     local($_) = @_;
  877     s/$math_delimiters_rx//;
  878     if ( !($ref_before =~ /<LEFT>/) ) {
  879     $ref_before = "<BOX>" . $ref_before;
  880     };
  881     $failed = 1 if ($NO_SIMPLE_MATH);
  882     ( $1 eq "." ? "" : "<RIGHT>$1" ) . "</BOX>$_";
  883 }
  884 
  885 ### Multiline formulas
  886 
  887 sub do_env_eqnarray {
  888     local($_) = @_;
  889     local($math_mode, $failed, $labels, $comment, $doimage) = ("equation",'','');
  890     local($attribs, $border);
  891     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
  892     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
  893     local($eqnarray_warning) =
  894     "{eqnarray} does not have 3 columns, inserting blank cell";
  895     local($saved) = $_;
  896     local($sbig,$ebig,$falign) = ('','','CENTER');
  897     ($sbig,$ebig) = ('<BIG>','</BIG>')
  898     if (($DISP_SCALE_FACTOR)&&($DISP_SCALE_FACTOR >= 1.2 ));
  899     $failed = 1 if ($NO_SIMPLE_MATH); # simplifies the next call
  900     ($labels, $comment, $_) = &process_math_env($math_mode,$_);
  901     if (( $failed && !($NO_SIMPLE_MATH))
  902     ||(/$htmlimage_rx|$htmlimage_pr_rx/)) {
  903 #   ||((/$htmlimage_rx|$htmlimage_pr_rx/)&&($& =~/thumb/))) {
  904     # image of whole environment, no equation-numbers
  905     $failed = 1;
  906     $falign = (($EQN_TAGS =~ /L/)? 'LEFT' : 'RIGHT')
  907         unless $no_eqn_numbers;
  908     $_ = &process_undefined_environment(
  909         "eqnarray".(($no_eqn_numbers) ? "star" : '')
  910         , $id, $saved );
  911     $_ = join(''
  912         , (($HTML_VERSION >2.0)? "<P ALIGN=\"$falign\">" : '')
  913         , $labels, $comment, $_
  914         , (($HTML_VERSION >2.0)? "<BR CLEAR=\"ALL\">\n<P>" : '')
  915         );
  916 
  917     } elsif ($NO_SIMPLE_MATH) {
  918     $failed = 0;
  919     s/$htmlimage_rx/$doimage = $&;''/eo ; # force an image
  920     s/$htmlimage_pr_rx/$doimage .= $&;''/eo ; # force an image
  921     local($valign) = join('', " VALIGN=\"",
  922         ($NETSCAPE_HTML)? "BASELINE" : "MIDDLE", "\"");
  923     local($sarray, $srow, $slcell, $eccell, $srcell, $ercell, $erow, $earray);
  924     ($sarray, $eccell, $srcell, $erow, $earray, $sempty) = ( 
  925         "\n<TABLE$env_id CELLPADDING=\"0\" "
  926         , "</TD>\n<TD WIDTH=\"10\" ALIGN=\"CENTER\" NOWRAP>"
  927         , "</TD>\n<TD ALIGN=\"LEFT\" NOWRAP>"
  928         , "</TD></TR>", "\n</TABLE>", "</TD>\n<TD>" );
  929     $sarray .= "ALIGN=\"CENTER\" WIDTH=\"100%\">";
  930     $env_id = '';
  931 
  932     local($seqno) = join('',"\n<TD$eqno_class WIDTH=10 ALIGN=\""
  933         , (($EQN_TAGS =~ /L/)? 'LEFT': 'RIGHT')
  934         , "\">\n");
  935     if ($EQN_TAGS =~ /L/) { # number on left
  936         ($srow, $slcell, $ercell) = (
  937         "\n<TR$valign>". $seqno
  938         , "</TD>\n<TD NOWRAP ALIGN=", '');
  939     } else { # equation number on right
  940         ($srow, $slcell, $ercell) = (
  941         "\n<TR$valign>" , "<TD NOWRAP ALIGN="
  942         , '</TD>'. $seqno );
  943     }
  944 
  945     $_ = &protect_array_envs($_);
  946 
  947     local(@rows,@cols,$eqno,$return,$thismath);
  948     s/\\\\[ \t]*\[[^\]]*]/\\\\/g; # remove forced line-heights
  949     @rows = split(/\\\\/);
  950 
  951     $#rows-- if ( $rows[$#rows] =~ /^\s*$/ );
  952     $return = join(''
  953         , (($border||($attribs))? '': "<BR>")
  954         , (($doimage)? '' : "\n<DIV$math_class>")
  955         , (($labels)? $labels : "\n") , $comment, $sarray);
  956 
  957     foreach (@rows) { # displaymath
  958         $eqno = '&nbsp;';
  959         do { 
  960         $global{'eqn_number'}++ ;
  961         $eqno = join('', $EQNO_START
  962                 , &simplify(&translate_commands('\theequation'))
  963                 , $EQNO_END );
  964         } unless ((s/\\nonumber//)||($no_eqn_numbers));
  965         $return .= $srow;
  966         $return .= $eqno if ($EQN_TAGS =~ /L/);
  967         $return .= $slcell;
  968 
  969         if (s/\\lefteqn//) {
  970         $return .= "\"LEFT\" COLSPAN=\"3\">";
  971         s/(^\s*|$html_specials{'&'}|\s*$)//gm;
  972         if (($doimage)||($failed)) {
  973             $_ = (($_)? &process_math_in_latex(
  974             "indisplay" , '', '', $doimage.$_ ):'');
  975         } else {
  976             $_ = &revert_array_envs($_);
  977             $_ = (($_) ? &make_math('display', '', '', $_) : "$_");
  978         }
  979         if ($_) {
  980             $return .= join('', $sbig, $_, $ebig, $erow);
  981         } else { $return .= join('',"\&nbsp;", $erow); } 
  982         next;
  983         }
  984 
  985         # columns to be set using math-modes
  986         @cols = split(/$html_specials{'&'}/o);
  987 
  988         # left column, set using \displaystyle
  989         $thismath = shift(@cols); 
  990         $thismath =~ s/(^\s*|\s*$)//gm;
  991         if (($doimage)||($failed)) {
  992         $thismath = (($thismath ne '')? &process_math_in_latex(
  993             "indisplay" , '', '', $doimage.$thismath ):'');
  994         } elsif ($thismath ne '') {
  995         $id = $global{'max_id'}++;
  996         $thismath = &revert_array_envs($thismath);
  997         $thismath = &make_math('displaymath', '', '', $thismath);
  998         }
  999         if ($thismath ne '') {
 1000         $return .= join('',"\"RIGHT\">$sbig",$thismath,"$ebig");
 1001         } else { $return .= "\"RIGHT\">\&nbsp;" }
 1002 
 1003         # center column, set using \textstyle
 1004         $thismath = shift(@cols);
 1005         if (!($#cols < 0)) {
 1006 #print "\nEQNARRAY:$#cols : $thismath";
 1007         $thismath =~ s/(^\s*|\s*$)//gm;
 1008         if (($doimage)||($failed)) {
 1009             $thismath = (($thismath ne '')? &process_math_in_latex(
 1010             "indisplay" , 'text', '', $doimage.$thismath ):'');
 1011         } elsif ($thismath ne '') {
 1012             $id = $global{'max_id'}++;
 1013             $thismath = &revert_array_envs($thismath);
 1014             $thismath = &make_math('displaymath', '', '', $thismath);
 1015         }
 1016         if ($thismath ne '') {
 1017             $return .= join('', $eccell, $sbig , $thismath, $ebig);
 1018         } else { $return .= join('', $sempty,"\&nbsp;") }
 1019 
 1020         # right column, set using \displaystyle
 1021         $thismath = shift(@cols);
 1022         } else {
 1023         $return .= join('', $sempty,"\&nbsp;");
 1024         &write_warnings($eqnarray_warning);
 1025         print "\n\n *** $eqnarray_warning \n";
 1026         }
 1027         $thismath =~ s/(^\s*|\s*$)//gm;
 1028         if (($doimage)||($failed)) {
 1029         $thismath = (($thismath ne '')? &process_math_in_latex(
 1030             "indisplay" , '', '', $doimage.$thismath ):'');
 1031         } elsif ($thismath ne '') {
 1032         $id = $global{'max_id'}++;
 1033         $thismath = &revert_array_envs($thismath);
 1034         $thismath = &make_math('displaymath', '', '', $thismath);
 1035         }
 1036         if ($thismath ne '') {
 1037         $return .= join('', $srcell, $sbig, $thismath, $ebig, $ercell);
 1038         } else { $return .= join('', $sempty, "\&nbsp;", $ercell) }
 1039 
 1040         $return .= $eqno unless ($EQN_TAGS =~ /L/);
 1041         $return .= $erow;
 1042     }
 1043     $_ = join('', $return , $earray, (($doimage)? '' : "</DIV>" ));
 1044     } else {
 1045     $_ = join('', $comment, "<P$math_class>$sbig"
 1046         , $labels, "\n<MATH CLASS=\"EQNARRAY\">"
 1047         , &do_env_array("$O$max_id${C}rcl$O$max_id$C$_")
 1048         , "</MATH>\n$ebig</P>" )
 1049     }
 1050     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
 1051     join('',"<BR>\n<DIV$math_class>\n"
 1052         , &make_table( $border, $attribs, '', '', '', $_ )
 1053         , "\n<BR CLEAR=\"ALL\"></DIV>");
 1054     } elsif ($failed &&($HTML_VERSION > 2.1 )) {
 1055     local($fclass) = $math_class;
 1056     $fclass =~ s/(ALIGN=\")[^"]*/$1$falign/;
 1057     join('',"<BR>\n<DIV$fclass>\n"
 1058         , $_ , "\n<BR CLEAR=\"ALL\"></DIV><P></P>")
 1059     } else { 
 1060     join('', $_ , "\n<BR CLEAR=\"ALL\"><P></P>");
 1061     }
 1062 }
 1063 
 1064 sub do_env_eqnarraystar {
 1065     local($_) = @_;
 1066     local($math_mode, $failed, $labels, $comment) = ("equation",'','');
 1067     $failed = (/$htmlimage_rx|$htmlimage_pr_rx/); # force an image
 1068     local($attribs, $border);
 1069     local($saved) = $_;
 1070     local($sbig,$ebig);
 1071     ($sbig,$ebig) = ('<BIG>','</BIG>')
 1072     if (($DISP_SCALE_FACTOR)&&($DISP_SCALE_FACTOR >= 1.2 ));
 1073 
 1074     if (($NO_SIMPLE_MATH)||($failed)) {
 1075         local($no_eqn_numbers) = 1;
 1076     $_ = &do_env_eqnarray($_) unless ($failed);
 1077     if ($failed) {
 1078             if ($saved =~ s/$htmlborder_rx//o)  {
 1079             $attribs = $2; $border = (($4)? "$4" : 1)
 1080             } elsif ($saved =~ s/$htmlborder_pr_rx//o) {
 1081             $attribs = $2; $border = (($4)? "$4" : 1)
 1082         }
 1083             $_ = join('', $labels
 1084 #       , &process_undefined_environment("eqnarraystar", $id, $saved));
 1085         , &process_undefined_environment("eqnarray*", $id, $saved));
 1086     }
 1087     } else {
 1088     if (s/$htmlborder_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
 1089     elsif (s/$htmlborder_pr_rx//o) { $attribs = $2; $border = (($4)? "$4" : 1) }
 1090     $saved = $_;
 1091     ($labels, $comment, $_) = &process_math_env($math_mode,$_);
 1092     if ($failed) {
 1093         $_ = join('', $labels
 1094 #           , &process_undefined_environment("eqnarraystar", $id, $saved));
 1095             , &process_undefined_environment("eqnarray*", $id, $saved));
 1096     } else {
 1097         $_ = join('', $comment, "<P$math_class>$sbig", $labels
 1098             , "\n<MATH CLASS=\"EQNARRAYSTAR\">"
 1099             , &do_env_array("$O$max_id${C}rcl$O$max_id$C$_")
 1100             , "</MATH>\n$ebig</P>" );
 1101     }
 1102     }
 1103     if (($border||($attribs))&&($HTML_VERSION > 2.1 )) { 
 1104     $_ = &make_table( $border, $attribs, '', '', '', $_ ) 
 1105     } else { $_ }
 1106 }
 1107 
 1108 sub do_math_cmd_nonumber {
 1109     $_[$[];
 1110 };
 1111 
 1112 ### Putting One Thing Above Another
 1113 
 1114 ## Over- and Underlining
 1115 
 1116 sub do_math_cmd_overline {
 1117     local($_) = @_;
 1118     local($over) = &get_next_token(1);
 1119     if ($NO_SIMPLE_MATH) { 
 1120         local($supsub) = &get_supsub;
 1121         local($after) = $_;
 1122         ( &process_math_in_latex( $mode, $math_style, $slevel
 1123             , "\\overline{$over}$supsub") , $after)
 1124     } else {"<ABOVE>$over</ABOVE>$_" }
 1125 }
 1126 
 1127 sub do_math_cmd_underline {
 1128     local($_) = @_;
 1129     local($under) = &get_next_token(1);
 1130     if ($NO_SIMPLE_MATH) {
 1131         local($supsub) = &get_supsub;
 1132         local($after) = $_;
 1133         ( &process_math_in_latex( $mode, $math_style, $slevel
 1134             , "\\underline{$under}$supsub") , $after)
 1135     } else { "<BELOW>$under</BELOW>$_" }
 1136 }
 1137 
 1138 sub do_math_cmd_overbrace {
 1139     local($_) = @_;
 1140     local($over) = &get_next_token(1);
 1141     if ($NO_SIMPLE_MATH) {
 1142         local($supsub) = &get_supsub;
 1143         local($after) = $_;
 1144         ( &process_math_in_latex( $mode, $math_style, $slevel
 1145             , "\\overbrace{$over}$supsub\\,") , $after)
 1146     } else { "<ABOVE SYM=\"CUB\">$over</ABOVE>$_" }
 1147 }
 1148 
 1149 sub do_math_cmd_underbrace {
 1150     local($_) = @_;
 1151     local($under) = &get_next_token(1);
 1152     if ($NO_SIMPLE_MATH) {
 1153         local($supsub) = &get_supsub;
 1154         local($after) = $_;
 1155         ( &process_math_in_latex( $mode, $math_style, $slevel
 1156             , "\\underbrace{$under}$supsub\\,") , $after)
 1157     } else { "<BELOW SYM=\"CUB\">$under</BELOW>$_" }
 1158 }
 1159 
 1160 ## Accents
 1161 
 1162 sub do_math_cmd_vec {
 1163     local($_) = @_;
 1164     local($over) = &get_next_token(1);
 1165     if ($NO_SIMPLE_MATH) {
 1166     local($supsub) = &get_supsub;
 1167     # \vec often makes the arrowhead fall outside its box
 1168     # fix this by adding small space when at the end
 1169     $supsub = "\\," unless ($supsub);
 1170     local($after) = $_;
 1171     ( &process_math_in_latex( $mode, $math_style, $slevel
 1172         , "\\vec{$over}$supsub") , $after)
 1173     } else { "<VEC>$over</VEC>$_" }
 1174 }
 1175 
 1176 sub do_math_cmd_bar {
 1177     local($_) = @_;
 1178     local($over) = &get_next_token(1);
 1179     if ($NO_SIMPLE_MATH) {
 1180     local($supsub) = &get_supsub;
 1181     local($after) = $_;
 1182     ( &process_math_in_latex( $mode, $math_style, $slevel
 1183         , "\\bar{$over}$supsub") , $after)
 1184     } else { "<BAR>$over</BAR>$_" }
 1185 }
 1186 
 1187 sub do_math_cmd_dot {
 1188     local($_) = @_;
 1189     local($over) = &get_next_token(1);
 1190     if ($NO_SIMPLE_MATH) {
 1191     local($supsub) = &get_supsub;
 1192     local($after) = $_;
 1193     ( &process_math_in_latex( $mode, $math_style, $slevel
 1194         , "\\dot{$over}$supsub") , $after)
 1195     } else { "<DOT>$over</DOT>$_" }
 1196 }
 1197 
 1198 sub do_math_cmd_ddot {
 1199     local($_) = @_;
 1200     local($over) = &get_next_token(1);
 1201     if ($NO_SIMPLE_MATH) {
 1202     local($supsub) = &get_supsub;
 1203     local($after) = $_;
 1204     ( &process_math_in_latex( $mode, $math_style, $slevel
 1205         , "\\ddot{$over}$supsub") , $after)
 1206     } else { "<DDOT>$over</DDOT>$_" }
 1207 }
 1208 
 1209 sub do_math_cmd_hat {
 1210     local($_) = @_;
 1211     local($over) = &get_next_token(1);
 1212     if ($NO_SIMPLE_MATH) {
 1213     local($supsub) = &get_supsub;
 1214     local($after) = $_;
 1215     ( &process_math_in_latex( $mode, $math_style, $slevel
 1216         , "\\hat{$over}$supsub") , $after)
 1217     } else { "<HAT>$over</HAT>$_" }
 1218 }
 1219 
 1220 sub do_math_cmd_tilde {
 1221     local($_) = @_;
 1222     local($over) = &get_next_token(1);
 1223     if ($NO_SIMPLE_MATH) {
 1224     local($supsub) = &get_supsub;
 1225     local($after) = $_;
 1226     ( &process_math_in_latex( $mode, $math_style, $slevel
 1227         , "\\tilde{$over}$supsub") , $after)
 1228     } else { "<TILDE>$over</TILDE>$_" }
 1229 }
 1230 
 1231 sub do_math_cmd_widehat {
 1232     local($_) = @_;
 1233     local($over) = &get_next_token(1);
 1234     if ($NO_SIMPLE_MATH) {
 1235     local($supsub) = &get_supsub;
 1236     local($after) = $_;
 1237     ( &process_math_in_latex( $mode, $math_style, $slevel
 1238         , "\\widehat{$over}$supsub") , $after)
 1239     } else { "<ABOVE SYM=\"HAT\">$over</ABOVE>$_" }
 1240 }
 1241 
 1242 sub do_math_cmd_widetilde {
 1243     local($_) = @_;
 1244     local($over) = &get_next_token(1);
 1245     if ($NO_SIMPLE_MATH) {
 1246     local($supsub) = &get_supsub;
 1247     local($after) = $_;
 1248     ( &process_math_in_latex( $mode, $math_style, $slevel
 1249         , "\\widetilde{$over}$supsub") , $after)
 1250     } else { "<ABOVE SYM=\"TILDE\">$over</ABOVE>$_" }
 1251 }
 1252 
 1253 ## Stacking Symbols
 1254 
 1255 sub do_math_cmd_stackrel {
 1256     local ($_) = @_;
 1257     local($top,$bot);
 1258     $top = &get_next_token(1);
 1259     $bot = &get_next_token(1);
 1260     if ($NO_SIMPLE_MATH) { 
 1261     local($after) = $_;
 1262     ( &process_math_in_latex( $mode, $math_style, $slevel
 1263         , "\\;\\stackrel{$top}{$bot}\\;") , $after)
 1264     } else { "<BOX>$2</BOX><SUP ALIGN=\"CENTER\">$top</SUP>$_" }
 1265 }
 1266 
 1267 # Kill $ref_before in case we're not in math mode.
 1268 sub do_math_cmd_atop {
 1269     local ($before) = $ref_before;
 1270     $before =~ s/^[\s%]*//; $before =~ s/[\s%]*$//;
 1271     $ref_before = "";
 1272     $failed = 1 if ($NO_MATH_MARKUP);
 1273     "<BOX>$before<ATOP>$_[$[]</BOX>";
 1274 }
 1275 
 1276 sub do_math_cmd_choose {
 1277     local ($before) = $ref_before;
 1278     $before =~ s/^\s*//; $before =~ s/\s*$//;
 1279     $ref_before = "";
 1280     $failed = 1 if ($NO_MATH_MARKUP);
 1281     "<BOX>$before<CHOOSE>$_[$[]</BOX>";
 1282 }
 1283 sub do_math_cmd_binom { &do_math_cmd_choose(@_) }
 1284 
 1285 sub do_math_cmd_mbox {
 1286     local($_) = @_;
 1287     local($cmd,$text,$after)=('mbox','','');
 1288     $text = &missing_braces
 1289     unless ((s/$next_pair_pr_rx[\s%]*/$text = $2;''/eo)
 1290         ||(s/$next_pair_rx[\s%]*/$text = $2;''/eo));
 1291 
 1292     # incomplete macro replacement
 1293     if ($text =~ /(^|[^\\<])#\d/) { return($_) }
 1294 
 1295     if ($NO_SIMPLE_MATH) {
 1296     $after = $_;
 1297     if (!($text)||($text =~ /^\s*$/)) { ("\&nbsp; ", $after) }
 1298     elsif (!($text =~ 
 1299         /tex2html_wrap_inline|^(($O|$OP)\d+($C|$CP))?\$|\$(($O|$OP)\d+($C|$CP))\4\$/)) { 
 1300         $text =~ s/$OP(\d+)$CP/$O$1$C/g;
 1301         if ($text =~ /\$/) {
 1302             $_ = $text;
 1303             $text = &wrap_math_environment;
 1304         }
 1305         $text = &translate_environments("${O}1$C$text${O}1$C") if $text;
 1306         $text = &translate_commands($text) if ($text =~ /\\/);
 1307         $text =~ s/ $/;SPMnbsp;/; # preserve trailing spaces
 1308         ($text, $after)
 1309     } else {
 1310         ( &process_math_in_latex( $mode, $math_style, $slevel
 1311         , "\\mbox{$text}") , $after)
 1312     }
 1313     } else { "<TEXT>$text</TEXT>$_" }
 1314 }
 1315 
 1316 sub do_math_cmd_display {
 1317     $_[$[];
 1318 }
 1319 
 1320 sub do_math_cmd_text {
 1321     $_[$[];
 1322 }
 1323 
 1324 sub do_math_cmd_script {
 1325     $_[$[];
 1326 }
 1327 
 1328 sub do_math_cmd_scriptscript {
 1329     $_[$[];
 1330 }
 1331 
 1332 # This is supposed to put the font back into math italics.
 1333 # Since there is no HTML equivalent for reverting 
 1334 # to math italics we keep track of the open font tags in 
 1335 # the current context and close them.
 1336 # *** POTENTIAL ERROR ****#  
 1337 # This will produce incorrect results in the exceptional
 1338 # case where \mit is followed by another context
 1339 # containing font tags of the type we are trying to close
 1340 # e.g. {a \bf b \mit c {\bf d} e} will produce
 1341 #       a <b> b </b> c   <b> d   e</b>
 1342 # i.e. it should move closing tags from the end 
 1343 sub do_math_cmd_mit {
 1344     local($_, @open_font_tags) = @_;
 1345     local($next);
 1346     for $next (@open_font_tags) {
 1347     $next = ($declarations{$next});
 1348     s/<\/$next>//;
 1349     $_ = join('',"<\/$next>",$_);
 1350     }
 1351     $_;
 1352 }
 1353 
 1354 
 1355 
 1356 $ams_aligned_envs_rx = "((\\w*align\\w*|gather\\w*|split|multline|array|cases)(\\*|star)?)";
 1357 $space_commands_rx = "(\\\\(q+uad|[,; ]|hs(kip|pace)(($O|$OP)\\d+($C|$CP))[^<]+\\4)|\\s)*";
 1358 
 1359 sub translate_math_commands {
 1360     local($mode,$style,$face,$slevel,$_) = @_;
 1361     local($pre_text, $labels);
 1362     if ($NO_MATH_PARSING) {
 1363     s/\\\n/\\ \n/g;
 1364         if ($_ =~ /$space_commands_rx\\(text|mbox)\b/) {
 1365         $pre_text = $`; $_ = $& . $';
 1366             # Do not split if inside any kind of grouping
 1367         local($pre_test,$use_all)=($pre_text,'');
 1368         while ($pre_test =~ s/(($O|$OP)\d+($C|$CP))(.*)\1/$4/) {}
 1369         $use_all = 1 if ($pre_test=~s/($O|$OP)\d+($C|$CP)//);
 1370         if (!$use_all) {
 1371             while ($pre_test =~ s/\\begin(($O|$OP)\d+($C|$CP))(.*)\\end\1/$4/){};
 1372         $use_all = 1 if ($pre_test=~s/\\(begin|end)($O|$OP)\d+($C|$CP)//);
 1373         };
 1374         if (!$use_all) {
 1375             local($gp_cnt) = 0;
 1376         $pre_test =~ s/\\left\b/$gp_cnt++;''/eg;
 1377         $pre_test =~ s/\\right\b/$gp_cnt--;''/eg;
 1378         $use_all = 1 if $gp_cnt;
 1379             };
 1380         if ($use_all) { $pre_text .= $_ ; $_ = '' };
 1381         } else {
 1382         $pre_text = $_; $_ = '';
 1383         }
 1384 
 1385     ($pre_text,$labels) = &extract_labels($pre_text);
 1386     local($savedRS) = $/; $/ = '';
 1387 #   if ($pre_text =~ m/^((.|\n)*)\\begin\s*(($O|$OP)\d+($C|$CP))$ams_aligned_envs_rx\3/m) {
 1388     if ($pre_text =~ m/^()\\begin\s*(($O|$OP)\d+($C|$CP))$ams_aligned_envs_rx\3/m) {
 1389         local($env,$star,$orig,$cnt) = ($7,$8,$pre_text.$_,1);
 1390         local($this_env,$pre_pre_text, $post_pre_text,$found) = ('', $1, $'.$_ , 1);
 1391         $pre_text = $_ = '';
 1392 #       local($savedRS) = $/; $/ = ''; $*=1;
 1393         while ( $cnt && $found ) {
 1394         $found = '';
 1395         if ($post_pre_text =~ /\\(begin|end)(($O|$OP)\d+($C|$CP))$env$star\2/sm)
 1396             { $pre_text .= $`; $found = $1;
 1397               $this_env = $&; $post_pre_text = $'; }
 1398         if ($found =~ /begin/) {
 1399             $cnt++; $pre_text .= $this_env;
 1400         } elsif ($found =~ /end/) {
 1401             $cnt--; $pre_text .= $this_env if ($cnt > 0) ;
 1402         }
 1403         }
 1404         $/ = $savedRS;
 1405         $env .= 'star' if $star;
 1406         local($env_cmd) = 'do_env_'.$env;
 1407         # parse it further, when possible...
 1408         if ((defined &$env_cmd) && !$cnt) {
 1409         $_ = $post_pre_text . $_;
 1410         $pre_text = join( '', $labels
 1411             , &$env_cmd($pre_text)
 1412             , (($_)? &translate_math_commands($mode
 1413                  ,$style,$face,$slevel,$_):'')
 1414             );
 1415         return( $pre_pre_text . $pre_text );
 1416         }
 1417         # ...else put it back inside a {displaymath} for an image
 1418         if ($cnt) { $orig .= $_; $_ = ''; }
 1419         local($math_env) = 'displaymath';
 1420         $math_env = $outer_math if ($outer_math =~ /^subequations/);
 1421         $pre_text = join('', '\begin{',$math_env,'}'
 1422             , $orig ,'\end{',$math_env,'}' );
 1423         local($after_undef) = $_;
 1424         $pre_text = &process_undefined_environment(
 1425         $math_env, ++$global{'max_id'}, $orig);
 1426         $_ = $after_undef;
 1427     } else {
 1428         $pre_text = &process_math_in_latex($mode,$style,$slevel,$pre_text)
 1429         if ($pre_text);
 1430     }
 1431     $/ = $savedRS;
 1432     return($labels . $pre_text) unless ($_);
 1433 
 1434     local($post_text, $this_text, $which_text);
 1435     if (/^$space_commands_rx\\(text|mbox)\b(($O|$OP)\d+($C|$CP))/){
 1436         local($end_text) = $8; $which_text = $7;
 1437         $post_text = $';
 1438         $pre_text .= ";SPMnbsp; ;SPMnbsp;" if ($1);
 1439         if ($post_text =~ /$end_text/) {
 1440         $post_text = $'; $this_text = $`;
 1441         if ($which_text =~ /mbox/) {
 1442             $this_text = join('',$end_text,$this_text,$end_text);
 1443             ($this_text) = &do_math_cmd_mbox($this_text);
 1444         } else {
 1445             $this_text = &translate_environments($this_text);
 1446             $this_text = &translate_commands($this_text);
 1447         }
 1448         $post_text = &translate_math_commands( $mode
 1449             ,$style,$face,$slevel,$post_text) if ($post_text);
 1450         }
 1451         $pre_text = join('', $pre_text, $this_text, $post_text);
 1452         return($labels . $pre_text);
 1453     }
 1454     if ($pre_text) {
 1455         $_ = join('', $labels , $pre_text ,
 1456         &translate_math_commands($mode,$style,$face,$slevel,$_));
 1457     } else {
 1458         $_ = join('', $labels , $pre_text ,
 1459         &process_math_in_latex($mode,$style,$slevel,$_));
 1460         }
 1461     return($_);
 1462     }
 1463     &replace_strange_accents;
 1464     for (;;) {          # For each opening bracket ...
 1465     last unless (/$begin_cmd_rx/o);
 1466     local($before, $contents, $br_id, $after, $pattern);
 1467     ($before, $br_id, $after, $pattern) = ($`, $1, $', $&);
 1468     local($end_cmd_rx) = &make_end_cmd_rx($br_id);
 1469     if ($after =~ /$end_cmd_rx/) { # ... find the the matching closing one
 1470         $NESTING_LEVEL++;
 1471         ($contents, $after) = ($`, $');
 1472         $_ = join("", $before,"$OP$br_id$CP", $contents,"$OP$br_id$CP", $after);
 1473         $NESTING_LEVEL--;
 1474     }
 1475     else {
 1476         $pattern = &escape_rx_chars($pattern);
 1477         s/$pattern//;
 1478         print STDERR "\nCannot find matching bracket for $br_id";
 1479     }
 1480     }
 1481 #    &parse_math_toks($mode,$style,$face,$slevel,1,$_);
 1482     &process_math_toks($mode,$style,$face,$slevel,1,$_);
 1483 }
 1484 
 1485 
 1486 sub make_math_comment{
 1487     local($_) = @_;
 1488     local($scomm,$ecomm)=("\$","\$");
 1489     return() if (/$image_mark/);
 1490     do {
 1491     $scomm = "\\begin{$env}\n";
 1492     $ecomm = "\n\\end{$env}";
 1493     } unless ($env =~/tex2html/);
 1494     $_ = &revert_to_raw_tex;
 1495     s/^\s+//; s/\s+$//m;
 1496     $_ = $scomm . $_ . $ecomm;
 1497     return() if (length($_) < 12);
 1498     $global{'verbatim_counter'}++;
 1499     $verbatim{$global{'verbatim_counter'}} = $_;
 1500     &write_mydb('verbatim_counter', $global{'verbatim_counter'}, $_ );
 1501     join('', $verbatim_mark, '#math' , $global{'verbatim_counter'},'#')
 1502 } 
 1503 
 1504 sub process_math_env {
 1505     local($mode,$_) = @_;
 1506     local($labels, $comment);
 1507     ($_,$labels) = &extract_labels($_); # extract labels
 1508     $comment = &make_math_comment($_);
 1509     local($max_id) = ++$global{'max_id'};
 1510     if ($failed) { return($labels, $comment, $_) };
 1511     $_ = &protect_array_envs($_);
 1512     if ($BOLD_MATH) {
 1513         ($labels, $comment
 1514             , join('','<B>',&make_math($mode,'','',$_),'</B>'))
 1515     } else { ($labels, $comment, &make_math($mode,'','',$_)) }
 1516 }
 1517 
 1518 sub process_math_toks {
 1519     if ($NO_MATH_PARSING) {
 1520     local($mode,$style,$face,$slevel,$math_outer,$_) = @_;
 1521     if (/(aligned|gathered|alignedat|split)/) {
 1522 #print "\n***SPECIAL AMS:\n$_\n";
 1523     }
 1524     $_ = &process_math_in_latex($mode,$style,$slevel,$_);
 1525     return($_);
 1526     }
 1527     &parse_math_toks(@_);
 1528 }
 1529     
 1530 sub parse_math_toks {
 1531     local($mode,$style,$face,$slevel,$math_outer,$_) = @_;
 1532     local($pre,$keep,$this,$cmd,$tmp);
 1533     local($lastclosespace, $joinspace) = (1,1);
 1534     $face = "I" unless (($face)||($slevel));  # default text is italiced
 1535     $face =~ s/math//;
 1536     local($afterint) = 0;    # device to detect integral d
 1537     print "\$";
 1538     print STDERR "\nMATH_IN:$_" if ($VERBOSITY > 4);
 1539     while (
 1540     /[\s%]*(\\([a-zA-Z]+|.)|$image_mark#[^#]+#|(<#\d*#>)|(<[^>]*>)(#math\d+#)?|\^|\_|&[a-zA-Z]+;|;SPM[a-z]+;|&)/
 1541     ) {
 1542     $lastclosespace = 1; $joinspace=1;
 1543     #  $keep  holds the results from processed tokens
 1544     #  $pre  should be all simple letters and other characters
 1545     $pre = $`;
 1546     #  $_  holds the tokens yet to come
 1547     $_ = $';
 1548     #  $this  holds the current token
 1549     $this = $1;
 1550     if ($4) {
 1551         # tags already processed from an earlier cycle
 1552         #    includes math-comment markers
 1553         $this = $4.$5;
 1554         $lastclosespace = 0; $joinspace=0;
 1555     } elsif ($3) {
 1556         # an opening brace
 1557         local($br_idm) = $3;
 1558         $_ = $br_idm.$_;
 1559         if (s/$next_pair_pr_rx/$br_idm=$1; $this=$2;''/eo) {
 1560         $this =~ s/^\s*//; $this =~ s/\s*$//;
 1561         } else {
 1562         s/$br_idm//;
 1563         print "\n ** ignoring unmatched brace $br_idm in math **\n";
 1564         $this = ''; $br_idm = '';
 1565         }
 1566 
 1567         # if there is \atop.. or \over.. then make an image
 1568         # Better would be to create a table after establishing 
 1569         # the minimum number of tokens involved...
 1570         #    ...but that's getting pretty complicated.
 1571         if ($this =~ /\\(atop|over([^a-zA-Z]|withdelims))/) {
 1572         print ".";
 1573         print STDERR "$1" if ($VERBOSITY > 2);
 1574         $this = "{".$this."}";
 1575         $this .= &get_supsub;
 1576         $this = &process_math_in_latex($mode, $style, $slevel,$this);
 1577         $lastclosespace = 0;
 1578         } else {
 1579         local($extra) = &get_supsub;
 1580 # contents of $extra may require an image !!
 1581         # revert the brace-pairs
 1582         if ($extra =~ /{|}/) { 
 1583             &mark_string($extra);
 1584             $extra =~ s/$O(\d+)$C/$OP$1$CP/g;
 1585         }
 1586         $this .= $extra; undef $extra;
 1587         # otherwise the braces may delimit style-changes...
 1588         do{
 1589             local(@save_open_tags) = @$open_tags_R;
 1590             local($open_tags_R) = [ @save_open_tags ];
 1591             local($env_id) = $br_idm;
 1592             $this = &parse_math_toks($mode,$style,$face,$slevel,0,$this);
 1593 #           $this .= &balance_tags();
 1594             undef $open_tags_R; undef @save_open_tags;
 1595         };
 1596         # ...perhaps deliberate, to suppress space.
 1597         $lastclosespace = 0; $joinspace=0;
 1598         }
 1599     } elsif (($2) && $new_command{$2}) {
 1600         # macro-replacement required
 1601         print "\nReplacing \\$2 " if ($VERBOSITY > 5);
 1602         do {
 1603         local($cmd,$after) = ($2,$_);
 1604         $_ = &substitute_newcmd;
 1605         print " with: $_\n" if ($VERBOSITY > 5);
 1606         $_ .= $after;
 1607         undef $cmd; undef $after;
 1608         };
 1609         $this = '';
 1610     } elsif (($2) && ($2 =~/^latex$/)) { # discard the argument
 1611         $this = &missing_braces unless (
 1612                 (s/$next_pair_pr_rx\s*/$this = $2;''/eo)
 1613         ||(s/$next_pair_rx\s*/$this = $2;''/eo));
 1614         $this = '';
 1615     } elsif (($2) && ($2 =~/(acute|breve|check|grave)$/)) {
 1616         # accented characters, not implemented separately
 1617         print ".";
 1618         print STDERR "$1" if ($VERBOSITY > 2);
 1619         $this .= join('', "{", &get_next_token(1), "}");
 1620         $this .= &get_supsub;
 1621         $this = &process_math_in_latex($mode, $style, $slevel,$this);
 1622     } elsif (($2) && ($2 =~/^end$/)) {
 1623         s/^\s*(<[<#]\d+[#>]>)[^<>]*\1//o;
 1624         $this = '';
 1625     } elsif (($2) && ($2 =~/^begin$/)) {
 1626         # embedded environment; e.g.  tex2html_wrap 
 1627         if (s/^\s*<([<#])(\d+)([#>])>(tex2html_(deferred|wrap(\w*)))<\1\2\3>//so) {
 1628         $this = '';         
 1629         } elsif (s/^\s*(<[<#](\d+)[#>]>)($array_env_rx)(\*|star)?\1//so) {
 1630             print ".";
 1631             print STDERR "$4$9" if ($VERBOSITY > 2);
 1632             # make image, including any sup/sub-scripts
 1633             local($id,$env,$star) = ($2,$3,$8);
 1634             $this = "\\begin".$&;
 1635             local ($saved) = $_;
 1636             $_ = $';
 1637             # find the \end, including nested environments of same type.
 1638             local($cnt, $thisbit, $which) = (1,'','');
 1639             while ( /\\(begin|end)(<#\d+#>)($env|$array_env_rx)(\*|star)?\2/sm ) {
 1640            $thisbit = $` . $&; $_ = $'; $which = $1;
 1641            do {
 1642                 # mark rows/columns in nested arrays
 1643                 $thisbit =~ s/;SPMamp;/$array_col_mark/gm;
 1644                 $thisbit =~ s/\\(\\|cr(cr)?(\b|$|\d|\W))/$array_row_mark$3/gm;
 1645            } if ($cnt > 1);
 1646            $this .= $thisbit;
 1647                 if ($which =~ /begin/) {$cnt++} else {$cnt--};
 1648                 last if (!$cnt);
 1649             }
 1650 
 1651 #       $this =~ s/\\cr(cr)?(\b|$|\d|\\|\W)/\\\\$2/g;
 1652             local($env_cmd) = "do_env_$env".(($star)? "star" : '');
 1653             if ($cnt) {
 1654            print "\n *** cannot find end of environment: $this ";
 1655            &write_warnings("\n *** failed to find \\end for: $this ");
 1656                 $this = ''; $_ = $saved;
 1657 #       } elsif ($env =~ /^tex2html_wrap_(inline)?$/) {
 1658 #           $this =~ 
 1659 #   s/^\\begin(($O|$OP)\d+($C|$CP))$env\1\s*|\\end(($O|$OP)\d+($C|$CP))$env\4\s*$//sg;
 1660 #           $_ = $this.$_; $this = '';
 1661         } elsif ($env =~ /^array/) {
 1662             local($extra) = &get_supsub;
 1663             if (($in_array)||($extra)||($pre)||($keep)) {
 1664             $this .= $extra;
 1665             $this = &process_math_in_latex($mode,$style,$slevel,$this);
 1666             } else { 
 1667             $star =~ s/\*/\\\*/om if ($star);
 1668             $this =~ s/^\\begin(<#\d+#>)$env$star\1//m;
 1669             $this =~ s/\\end(<#\d+#>)$env$star\1\s*$//m;
 1670             do {
 1671                 local($in_array) = 1;
 1672                 local($_) = $this;
 1673                 $this = &do_env_array($this);
 1674             };
 1675             }
 1676         } elsif (defined &$env_cmd) {
 1677             $star =~ s/\*/\\\*/o if ($star);
 1678             $this =~ s/^\\begin(<#\d+#>)$env$star\1//;
 1679             $this =~ s/\\end(<#\d+#>)$env$star\1\s*$//;
 1680             local($contents) = $_;
 1681             $this =  &$env_cmd($this);
 1682             undef $contents;
 1683         } else {
 1684             $this .= &get_supsub;
 1685             $this = &process_math_in_latex($mode,$style,$slevel,$this);
 1686         };
 1687         undef $cnt;
 1688         } else {
 1689         #RRM: revert brace-processing, else translation loops
 1690         s/$OP(\d+)$CP/$O$1$C/g;
 1691         $this = '';
 1692         do {
 1693             $_ = '\begin'.$_;  $_ =~ s/^$begin_env_rx//;
 1694             local($env, $mpat, $inner_math) = ($5, $&, $mode);
 1695             &find_end_env($env,$this,$_);
 1696             s/$O(\d+)$C/$OP$1$CP/g;
 1697 
 1698             local($br_id) = ++$global{'max_id'};
 1699             $this .= "\\end$O$br_id$C$env$O$br_id$C";
 1700 
 1701             if ($env =~ /$ams_aligned_envs_rx/) {
 1702             do {
 1703                 $NO_MATH_PARSING = 1; # $inner_math = '';
 1704                 $this = &make_math($mode,$style,$face,$mpat.$this);
 1705                 $NO_MATH_PARSING = '';
 1706             };
 1707             } else {
 1708             $this = &translate_environments($mpat.$this);
 1709             $this = &translate_commands($this) if ($this =~ /\\/);
 1710             s/$O(\d+)$C/$OP$1$CP/g;
 1711             }
 1712             undef $env; undef $mafter; undef $mpat; undef $inner_math;
 1713         };
 1714         }
 1715     } elsif (($2) && ($2 =~ /(\{|\}|\%|\|)/ )) {
 1716              $this = $1;
 1717     } elsif (($2) && ($2 =~ /\w+/)) {
 1718         # macro or math-entity
 1719         $cmd = $&; 
 1720         print ".";
 1721         print STDERR "$cmd" if ($VERBOSITY > 2);
 1722         local($dum1, $dum2) = ($cmd, '');
 1723         $dum1 = $cmd unless ($dum1 = &normalize($dum1, $dum2));
 1724         local($mtmp, $ctmp, $wtmp) = 
 1725         ("do_math_cmd_$dum1","do_cmd_$dum1", "wrap_cmd_$dum1");
 1726         if ($cmd =~/color/) {
 1727         do {
 1728             local($color_env,$inside_math) = ($color_env,1);
 1729             local(@save_open_tags) = @$open_tags_R;
 1730             $open_tags_R = [];
 1731             ($this, $_) = &$ctmp($_);
 1732             $this = &parse_math_toks($mode,$style,$face,$slevel,1,$this);
 1733             $open_tags_R = [ @save_open_tags ];
 1734             undef $color_env; undef $inside_math; undef @save_open_tags;
 1735         };
 1736         } elsif ($cmd eq 'left') {
 1737         #expandable delimiter: make an image
 1738         $this = "\\$cmd";
 1739         local($blevel, $delim, $lfence, $rfence) = (1,'','','');
 1740         $delim = &get_next_token();
 1741         $lfence = $this . $delim; $this = '';
 1742         while (($blevel)&&(/(\\(left|right))([^a-zA-Z])/)) {
 1743             $this .= $`.$1; $_ = $3.$';
 1744             if ($2 =~ /left/) { $blevel++ }
 1745             else { $blevel-- }
 1746         }
 1747         $this =~ s/(\\right)$/$rfence=$1;''/e;
 1748         local($mfence) = $this;
 1749         local($fenced) = $this;
 1750         $mfence =~ s/>\\par\\/>\\phantompar\\/g; # else \mathpalette fails
 1751         $delim = &get_next_token(); $rfence .= $delim;
 1752         if ($blevel) {
 1753             print STDERR "\n *** unclosed \\left$delim  starting:\n$this$_\n\n";
 1754             &write_warnings("\nunclosed \\left$delim  found");
 1755         }
 1756         undef $blevel;
 1757         undef $delim;
 1758 
 1759         # make an image of the left-fence
 1760         $this = &process_math_in_latex($mode,$style,$slevel
 1761             , "$lfence\\vphantom{$mfence}\\right.")
 1762             unless ($lfence eq '.');
 1763         #parse the  math for the contents, as if in an array-env
 1764         do { local($in_array) = 1;
 1765             $infence = &parse_math_toks($mode,$style,$face,$slevel,1,$fenced);
 1766             # and remove any paragraphing that may wrap the math contents.
 1767             $infence =~ s/^<P[^>]*>|<BR[^>]*>(\s*<P>\s*)?$//g;
 1768             $this .= $infence;
 1769         };
 1770         # make an image of the right-fence
 1771         local($endthis) = "\\left.\\vphantom{$mfence}$rfence";
 1772         # include any super/sub scripts, to position them correctly
 1773         local($rsub) = &get_supsub;
 1774         $endthis .= $rsub;
 1775         $this .= &process_math_in_latex($mode,$style,$slevel,$endthis)
 1776             unless (($rfence =~ /\.$/) && !$rsub);
 1777         $lastclosespace = 0;
 1778         undef $endthis; undef $rsub; undef $infence; undef $in_array;
 1779         } elsif ($cmd =~ /^brace(vert|[rl][ud])$/) {
 1780         $this = $cmd; $this .= &get_supsub;
 1781         $this = &process_math_in_latex($mode,$style,$slevel,"\\$this");
 1782         } elsif ($cmd =~ /(b|p)(m)?od$/) {
 1783         local($pod) = $2;
 1784         if ($cmd =~ /p/) {
 1785                  $this = &get_next_token();
 1786             $this = &parse_math_toks($mode,$style,$face,$slevel,1,$this);
 1787             $this = "(".(($pod)? "mod " : '')."$this)";
 1788         } elsif (/^\s*\w/) { 
 1789                  $this = " mod ";
 1790         }else { $this = " mod" }
 1791         } elsif ($cmd =~ /^(t|d)?frac$/) {
 1792             ($this, $_) = &do_math_cmd_frac($_);
 1793         } elsif ($cmd =~ /^(cases|matrix)$/) {
 1794         $this = &missing_braces unless (
 1795             (s/$next_pair_pr_rx\s*/$this = $&;''/eo)
 1796             ||(s/$next_pair_rx\s*/$this = $&;''/eo));
 1797         $this .= &get_supsub;
 1798         $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this");
 1799         } elsif ($cmd =~ /^(under|over|side)set$/) {
 1800         # from AMS-math packages
 1801         $this = &missing_braces unless (
 1802             (s/$next_pair_pr_rx\s*/$this = $&;''/eo)
 1803             ||(s/$next_pair_rx\s*/$this = $&;''/eo));
 1804         $this .= &get_next_token();
 1805 #           $this .= &missing_braces unless (
 1806 #           (s/$next_pair_pr_rx\s*/$this .= $&;''/eo)
 1807 #           ||(s/$next_pair_rx\s*/$this .= $&;''/eo));
 1808         if ($cmd =~ /side/) {
 1809             s/\s*\\\w+/$this .= $&;''/e;
 1810             $this .= &get_supsub;
 1811         }
 1812         $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this");
 1813         } elsif ($cmd =~ /^raisebox$/) {
 1814         $this = &missing_braces unless (
 1815             (s/$next_pair_pr_rx\s*/$this = $&;''/eo)
 1816             ||(s/$next_pair_rx\s*/$this = $&;''/eo));
 1817         local($arg, $pat) = &get_next_optional_argument;
 1818         $this .= $pat;
 1819         ($arg, $pat) = &get_next_optional_argument;
 1820         $this .= $pat;
 1821         $this .= &missing_braces unless (
 1822             (s/$next_pair_pr_rx\s*/$this .= $&;''/eo)
 1823             ||(s/$next_pair_rx\s*/$this .= $&;''/eo));
 1824         undef $arg; undef $pat;
 1825         $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this");     
 1826         } elsif ($cmd =~ /^choose|binom$/) {
 1827         $this = &missing_braces unless (
 1828             (s/$next_pair_pr_rx\s*/$this = $&;''/eo)
 1829             ||(s/$next_pair_rx\s*/$this = $&;''/eo));
 1830         $this .= &missing_braces unless (
 1831             (s/$next_pair_pr_rx\s*/$this .= $&;''/eo)
 1832             ||(s/$next_pair_rx\s*/$this .= $&;''/eo));
 1833         $this .= &get_supsub;
 1834         $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this");     
 1835         } elsif ($cmd =~ /^$var_sized_ops_rx|$var_limits_rx$/) {
 1836         # entities generally come out too small for these
 1837         $this = $cmd . &get_supsub;
 1838         $this = &process_math_in_latex($mode,$style,$slevel,"\\$this");
 1839         $lastclosespace = 0;
 1840         if ($cmd =~ /^(o|i+|idots)?int$/) { $afterint++; }
 1841         } elsif (defined &$mtmp) {
 1842         if ( grep(/\b$cmd\b/, @mathfunctions)
 1843             || grep(/\b$cmd\b/, @limitfunctions)) {
 1844             # it's a named function, to be set in upright text.
 1845             $this = "$cmd";
 1846             local($orig) = $_;
 1847             local($supsub) = &get_supsub;
 1848             if ($supsub =~ /^\\limits/) {
 1849             undef $orig;
 1850             # let LaTeX handle the vertical alignment
 1851             $this = &process_math_in_latex($mode,$style,$slevel
 1852                       , "\\$cmd$supsub" );
 1853             } elsif (($supsub)&&(grep(/\b$cmd\b/, @limitfunctions))) {
 1854             undef $orig;
 1855             # vertical alignment is implicit, use LaTeX
 1856             $this = &process_math_in_latex($mode,$style,$slevel
 1857                       , "\\$cmd$supsub" );
 1858             } elsif ($supsub) {
 1859 # contents of $supsub may require an image !!
 1860             # parse the sup/subscripts
 1861             $_ = $orig; undef $orig;
 1862             } elsif (/^\s*\w/) {
 1863             # ...else just put in the name + a space.
 1864             $this .= "\&nbsp;"; undef $orig;
 1865             } else  {
 1866             # ...else just put in the name, no space needed.
 1867             undef $orig;
 1868             }
 1869             undef $supsub;
 1870         } elsif ($cmd =~ /^(circ)$/) {
 1871             if ($_ =~ /^$/) {$this = "\&cir;"} # ...\degrees 
 1872             else { $this = " \&cir; " }  # ... as a binary relation
 1873         } elsif ($cmd =~ /^text$/) {
 1874             $this = &missing_braces unless (
 1875                 (s/$next_pair_pr_rx\s*/$this = $2;''/eo)
 1876                 ||(s/$next_pair_rx\s*/$this = $2;''/eo));
 1877             $this =~ s/$OP/$O/og; $this =~ s/$CP/$C/og; 
 1878             $this = &translate_environments($this);
 1879             $this = &translate_commands($this) if ($this =~ /\\/);
 1880         } elsif ($cmd =~ /^h?phantom$/) {
 1881             $this = &missing_braces unless (
 1882                 (s/$next_pair_pr_rx\s*/$this = $2;''/eo)
 1883                 ||(s/$next_pair_rx\s*/$this = $2;''/eo));
 1884             #reduce all control sequences to a single character.
 1885             $this =~ s/\\\w+/A/g; $this =~ s/\\./A/g;
 1886             #approximate width with hard-spaces.
 1887             $this = ";SPMnbsp;" x length($this);
 1888         } elsif ($cmd =~ /^${var_sized_ops_rx}$/) {
 1889             # entities generally come out too small for these
 1890             $this = $cmd . &get_supsub;
 1891             $this = &process_math_in_latex($mode,$style,$slevel,"\\$this");
 1892             $lastclosespace = 0;
 1893             if ($cmd =~ /^o?int$/) { $afterint++; }
 1894         } else {
 1895             # do what comes naturally ...
 1896             ($this, $_) = &$mtmp($_); s/^\s+//;
 1897             # if not a box and doesn't return a pair, then add it to $_
 1898             # the result should be separated off in subsequent cycles.
 1899             if (($this)&&(! $_)&&(!$cmd =~ /box/))
 1900                 { $_= $this; $this ='' };
 1901         }
 1902         } elsif (($mathentities{$cmd})||($latexsyms{$cmd})) {
 1903         $ent = ($mathentities{$cmd} || $latexsyms{$cmd});
 1904         do {
 1905             local($cset) = "${CHARSET}_character_map{$ent}";
 1906             $cset =~ s/\-/_/go;
 1907             local($char); eval "\$char = \$$cset";
 1908             do {
 1909             $cset = "${CHARSET}_character_map{$cmd}";
 1910             $cset =~ s/\-/_/go; eval "\$char = \$$cset";
 1911             $ent = $cmd if ($char);
 1912             } unless ($char);
 1913             $this = ($char ? $char : ''); undef($char);
 1914         };
 1915         if ($this) {
 1916             # do we want the character-code ...
 1917             if ($USE_ENTITY_NAMES) {
 1918             # ...or the entity ?
 1919             $this = ";SPM$ent;";
 1920             }
 1921             if ($greekentities{$cmd}) {
 1922                 # italicise greek symbols
 1923                 $this = "<I>$this</I>";
 1924             }
 1925         } elsif ($cmd =~ /^(en|l?dots|gt|lt|times|div|mid|vert|parallel|ast)$/) {
 1926             # standard entity
 1927             $this = &get_supsub;
 1928             if ($this) {
 1929                 $this = &process_math_in_latex($mode,$style,$slevel
 1930                     ,"\\$cmd$this" );
 1931             } else {
 1932                 $this = "\&$cmd;";
 1933             }
 1934         } elsif ($cmd =~ /^(l|r)brac(k|e)$/) {
 1935             $this = $ord_brackets{$1.$2};
 1936         } elsif ($cmd =~ /^cdot(s)?$/) {
 1937             $this = join('',"<SUP> \.",(($1)? "\.\." : '')," <\/SUP>");
 1938         } elsif ($cmd =~ /^l?dot(s)?$/) {
 1939             $this = "\. ".(($1)? "\.\." : '')." ";
 1940         } elsif ($cmd =~ /^backslash$/) {
 1941             $this = "\&#92;";
 1942         } elsif ($mathnomacros{$cmd}) {
 1943             # standard entity, no-macro needed
 1944             $cmd = $mathnomacros{$cmd};
 1945             $this = &get_supsub;
 1946             if ($this) {
 1947                 $this = &process_math_in_latex($mode,$style,$slevel
 1948                     ,"\\textrm{$cmd}$this" );
 1949             } else {
 1950                 $this = "$cmd";
 1951             }
 1952         } else {
 1953             if ($cmd =~ /^int$/) { $afterint++; }
 1954             # need an image
 1955             $this = &get_supsub;
 1956             $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this" );
 1957             # relations, known to need more space
 1958             $this = " $this "
 1959             if ($cmd =~ /$binary_ops_rx|$binary_rels_rx|$arrow_rels_rx/);
 1960         }
 1961         } elsif (defined &$wtmp) {
 1962         if ($cmd =~ /^(math(bb|cal|sf|sfsl)|cal)$/) {    # not accessible !!
 1963             # make images of these, including any sup/sub-scripts
 1964             $this = &missing_braces unless (
 1965             (s/$next_pair_pr_rx\s*/$this = $2;''/e)
 1966             ||(s/$next_pair_rx\s*/$this = $2;''/e));
 1967             $this = "\{".$this."\}";
 1968 #           $this .= &get_supsub;
 1969             $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this" );    
 1970         } elsif (defined &$ctmp) {
 1971             # do what comes naturally ...
 1972             ($this, $_) = &$ctmp($_);
 1973             if (($this =~/\\/)||!($_)) {$_= $this; $this ='' };
 1974         } else {
 1975             # make an image of all of it
 1976 #           $this = &missing_braces
 1977 #           unless ((s/$next_pair_pr_rx\s*//o)&&($this = "{$2}"));
 1978 #           $this .= &get_supsub;
 1979             $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$_" );
 1980             $_ = '';
 1981         }
 1982         } elsif ($cmd =~ /big+[lrm]?$/i ) {
 1983         s/\s*(\\(\W|[a-zA-Z]+)|\W)/$this=$1;''/eo;
 1984         $this .= &get_supsub;
 1985         $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this" );
 1986         $lastclosespace = 0; $joinspace=0;
 1987         } elsif ($cmd =~ /big(\w+)/ ) {
 1988         local($tmpname) = $1;
 1989         if (($mathentities{$tmpname})||($latexsyms{$tmpname})) {
 1990             # big version standard entity
 1991             $this = &get_supsub;
 1992             $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this" );
 1993             } else {
 1994             # need an image
 1995             $this = &get_supsub;
 1996             $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this" );
 1997             # relations, known to need more space
 1998             $this = " $this "
 1999             if ($tmpname =~ /$binary_ops_rx|$binary_rels_rx|$arrow_rels_rx/);
 2000         }
 2001 
 2002         } elsif ($cmd =~ /begin$/) {
 2003         local ($contents, $before, $br_id, $env, $after, $pattern);
 2004         if ( s/^$begin_env_rx//o ) {
 2005             local ($contents, $before, $br_id, $env, $after, $senv);
 2006             ($before, $br_id, $env, $after, $senv) = ($`, $1, $2, $', $&);
 2007         } else { print "\n *** badly formed $cmd *** "; }
 2008         if (&find_end_env($env,$contents,$after)) {
 2009             local($eenv) = "\\end$O$br_id$C";
 2010             $this = &translate_environments($senv.$contents.$eenv);
 2011         } else { print "\n *** badly formed environment in math ***"  }
 2012         $_ = $after;
 2013         } elsif ($cmd =~ /^not$/) {
 2014         $this = &get_next_token();
 2015         $this = " ".&process_math_in_latex($mode,$style,$slevel,"\\$cmd$this" );
 2016         } elsif ($cmd =~ /(display|text|(script)+)style$/) {
 2017         if ($1 =~ /scriptscript/) {
 2018             $this = ""; # $slevel = 2; $this = "";
 2019             $pre .= "<SMALL><SMALL>";
 2020             $_ .= "</SMALL></SMALL>";
 2021         } elsif ($1 =~ /script/) {
 2022             $this = ""; # $slevel = 1; $this = "";
 2023             $pre .= "<SMALL>";
 2024             $_ .= "</SMALL>";
 2025         } elsif ($slevel) {
 2026             if ($1 =~ /display/) { $mode = "display" }# ; $slevel = 0 }
 2027             elsif ($1 =~ /text/) { $mode = "inline"  }# ; $slevel = 0 }
 2028             $this = "";  # &process_math_in_latex($mode,$style,0,$_);
 2029             $pre .= "<BIG>"; $_ .= "</BIG>";
 2030         } elsif ($1 =~ /display/) { 
 2031             $mode = "display";  $this = ''; # $slevel = 0; $this = '';
 2032         } elsif ($1 =~ /text/) { 
 2033             $mode = "inline"; $this = ''; # $slevel = 0; $this = '';
 2034         }
 2035         } elsif (defined &$ctmp) {
 2036         if ($cmd =~ /(bm|boldsymbol|(text|math)?(rm|tt|bf|it))$/) {
 2037             # simulate these with ordinary fonts
 2038             $this = &missing_braces
 2039                 unless ((s/$next_pair_pr_rx\s*/$this = $2;''/oe)
 2040                     ||(s/$next_pair_rx\s*/$this = $2;''/oe));
 2041             $this = &parse_math_toks($mode,$style
 2042                 ,$cmd,$slevel,$math_outer,$this);
 2043             if ($cmd =~ /tt/)    { 
 2044                 $this =~ s/<(\/)?tt>/<$1TT>/g
 2045             } elsif ($cmd =~ /bf|bm|boldsymbol/) {
 2046                 $this =~ s/<(\/)?($cmd|bf)>/<$1B>/g;
 2047             } elsif ($cmd =~ /it/) {
 2048                 $this =~ s/<(\/)?($cmd|it)>/<$1I>/g
 2049             } elsif ($cmd =~ /rm/) { 
 2050                 $this =~ s/<(\/)?($cmd|rm)>//g
 2051             }
 2052             $this =~ s/\s+$//; # remove trailing space
 2053             } elsif ($cmd =~ /^text$/) {
 2054             $this = &missing_braces
 2055                 unless ((s/$next_pair_pr_rx\s*/$this = $2;''/oe)
 2056                     ||(s/$next_pair_rx\s*/$this = $2;''/oe));
 2057             $this = &translate_environments($this);
 2058             $this = &translate_commands($this);
 2059                 } elsif ($cmd =~ /^math(op(en)?|ord|bin|rel|punct|close)/io) {
 2060             # explicit math-class
 2061             local($mtype,$orig,$supsub) = ($1,'');
 2062             # get the contents
 2063             $this = &missing_braces unless (
 2064             (s/$next_pair_pr_rx\s*/$this = $2;''/oe)
 2065             ||(s/$next_pair_rx\s*/$this = $2;''/oe));
 2066             # see if there are sup/sub-scripts
 2067             local($orig) = $_;
 2068             local($supsub) = &get_supsub;
 2069             if (($mtype =~/^op$/i) && ($supsub =~ /^\\limits/)) {
 2070             # need an image for the vertical alignment
 2071             undef $orig;
 2072             do {
 2073                 $this = "${O}0$P$this${O}0$P";
 2074                 &make_unique($this);
 2075                 };
 2076             $this = " ". &process_math_in_latex($mode,$style
 2077                         ,$slevel,"\\$cmd$this$supsub" );
 2078             } elsif (($mtype =~/^close$/i) && ($supsub)) {
 2079                 # need an image for the sup/sub placement
 2080                 undef $orig;
 2081             do {
 2082                 $this = "${O}0$P$this${O}0$P";
 2083                 &make_unique($this);
 2084                 };
 2085             $this = " ". &process_math_in_latex($mode,$style
 2086                         ,$slevel,"\\$cmd$this$supsub" );
 2087             } else {
 2088             $_ = $orig; undef $orig;
 2089             $this = &parse_math_toks($mode,$style
 2090                     ,'',$slevel,'',$this);
 2091             $this =~ s/^\s*|\s*$//go;
 2092             $this = " ".$this unless ($mstyle =~ /ord/i);
 2093             $this .= " " if (!($supsub)&&($mstyle =~ /bin|rel|punct/i));
 2094             }
 2095             undef $supsub;
 2096             } elsif ($cmd =~ /^operatorname(\*|star|withlimits)?$/) {
 2097             do {
 2098             local($has_limits);
 2099             $has_limits = 1 if ((s/^\*//)||($cmd=~/limits/));
 2100             $this = &missing_braces
 2101                 unless ((s/$next_pair_pr_rx\s*/$this = $2;''/oe)
 2102                 ||(s/$next_pair_rx\s*/$this = $2;''/oe));
 2103             local($this_cmd) = "<#0#>".$this."<#0#>";
 2104             local($cmd_name) = $this;
 2105             local($pre_subp) = $_;
 2106             local($cmd_supsub) = &get_supsub; 
 2107             if (($cmd_supsub)&&($has_limits)) {
 2108                 $this_cmd .= $cmd_supsub;
 2109                 $this = &process_math_in_latex($mode,$style,$slevel
 2110                 , "\\$cmd$this_cmd" );
 2111             } else {
 2112                 $_ = $pre_subp;
 2113                 $this = &parse_math_toks($mode,$style, "mathrm"
 2114                 ,$slevel, $math_outer, $cmd_name );
 2115                 $this =~ s/<(\/)?rm>//g;
 2116             }
 2117             }
 2118         } elsif ($cmd =~ /qopname/) {
 2119             do{
 2120             $this = &missing_braces
 2121                 unless ((s/$next_pair_pr_rx\s*/$this = $2;''/oe)
 2122                 ||(s/$next_pair_rx\s*/$this = $2;''/oe));
 2123             local($this_cmd) = "<#0#>".$this."<#0#>";
 2124             $this = &missing_braces
 2125                 unless ((s/$next_pair_pr_rx\s*/$this = $2;''/oe)
 2126                 ||(s/$next_pair_rx\s*/$this = $2;''/oe));
 2127             $this_cmd .= "<#1#>".$this."<#1#>";
 2128             local($has_limits) = $this;
 2129             $this = &missing_braces
 2130                 unless ((s/$next_pair_pr_rx\s*/$this = $2;''/oe)
 2131                 ||(s/$next_pair_rx\s*/$this = $2;''/oe));
 2132             $this_cmd .= "<#2#>".$this."<#2#>";
 2133             local($cmd_name) = $this;
 2134             local($pre_subp) = $_;
 2135             local($cmd_supsub) = &get_supsub;
 2136             if (($cmd_supsub)&&!($has_limits =~ /^o$/)) {
 2137                 $this_cmd .= $cmd_supsub;
 2138                 $this = &process_math_in_latex($mode,$style,$slevel
 2139                     , "\\$cmd$this_cmd" );
 2140             } else {
 2141                 $_ = $pre_subp;
 2142                 $this = &parse_math_toks($mode,$style, "mathrm"
 2143                 ,$slevel, $math_outer, $cmd_name );
 2144                 $this =~ s/<(\/)?rm>//g;
 2145             }
 2146             }
 2147         } elsif ($cmd =~ /^(math|cal$)/io) {
 2148             # catches \mathcal \mathsf \mathbb etc. and \cal
 2149             $this = &missing_braces unless (
 2150                 (s/$next_pair_pr_rx\s*/$this = $2;''/e)
 2151                 ||(s/$next_pair_rx\s*/$this = $2;''/e));
 2152             $this = "<#2#>".$this."<#2#>";
 2153 #           $this .= &get_supsub;
 2154             $this = &process_math_in_latex($mode,$style,$slevel
 2155                             , "\\$cmd $this" );
 2156         } elsif ($cmd =~ /(\w*)space/) {
 2157             $this = "\&nbsp;";
 2158             if (($1 =~ /h/)&&((s/$next_pair_pr_rx\s*//)
 2159                     ||(s/$next_pair_rx\s*//)))
 2160             { $this = " \&nbsp; " }
 2161         } else {
 2162             # do what comes naturally ...
 2163             ($this, $_) = &$ctmp($_);
 2164             if (($this =~/\\/)||!($_)) {$_= $this; $this ='' };
 2165         }
 2166         } elsif ($newcommand{$cmd}) {
 2167         $_ = &replace_new_command($cmd);
 2168         } elsif ($cmd =~ /strut$/) { # ignore it
 2169         print "\nignoring \\$cmd ";
 2170         } elsif ($cmd =~ /^[vh]rule$/) { # ignore it
 2171         $this = "$cmd";
 2172         do{ local($which,$len,$pxs,%dims);
 2173             while (s/^\s*(height|width|depth)/$which=$1;''/e) {
 2174             $this .= " ".$&;
 2175             s/^\s*(\d+\.?\d*\w*)//; $this .= $&;
 2176             ($pxs,$len) = &convert_length($1); 
 2177             $dims{$which} = $pxs;
 2178             }
 2179             if ($dims{'width'} == 0 || ($dims{'height'}+$dims{'depth'} == 0)) {
 2180             print "\nignoring \\$cmd "; $this = '';
 2181             } else {
 2182             $this = &process_math_in_latex($mode,$style,$slevel,"\\$this");
 2183             }
 2184         };
 2185         } elsif ($cmd =~ /^$arrow_over_ops_rx$/) {
 2186         $this = &missing_braces unless (
 2187             (s/$next_pair_pr_rx\s*/$this = $&;''/oe)
 2188             ||(s/$next_pair_rx\s*/$this = $&;''/oe));
 2189         $this .= &get_supsub;
 2190         $this = &process_math_in_latex($mode,$style,$slevel, "\\$cmd$this" );       
 2191         } else {
 2192         # Unknown: send it to LaTeX and hope for the best.
 2193         &write_warnings("\nUnknown math command: \\$cmd , image needed.");
 2194         $this = &get_supsub;
 2195         $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this" );
 2196         }
 2197     } elsif ($this =~ /^\&(\w+)(#(\w+))?;/) {
 2198         # math-entity code
 2199         $cmd = $3;
 2200         print ".";
 2201         print STDERR "$cmd" if ($VERBOSITY > 2);
 2202         do {
 2203             $this = &get_supsub;
 2204             $this = &process_math_in_latex($mode,$style,$slevel,"\\$cmd$this" )
 2205         } if ($cmd);
 2206         $this = " $this "
 2207             if ($cmd =~ /$binary_ops_rx|$binary_rels_rx|$arrow_rels_rx/);
 2208     } elsif ($this =~ /^\s*((\^)|\_)/) {
 2209         # super/sub-script
 2210         print "$1";
 2211         print STDERR "$2" if ($VERBOSITY > 2);
 2212         $slevel++;
 2213         local($BP) = (($2) ? "P" : "B"); $tmp = "<SU$BP>";
 2214         $this = &get_next_token(1);
 2215         if ($this =~ /$array_env_rx/) {
 2216         $this = &process_math_in_latex($mode,$style,$slevel
 2217             ,(($BP =~/P/)? '^':'_')."{$this}" );
 2218         } else {
 2219         $this = &parse_math_toks($mode,$style,$face,$slevel,1,$this);
 2220         }
 2221         $this =~ s/^\s+//; $this =~ s/\s+$//;
 2222         $this = join('', $tmp, $this, "</SU$BP>");
 2223         $slevel--;
 2224         $lastclosespace = 0;
 2225     } elsif ($this =~ /^;SPM([a-z]+)/) {
 2226         $this = " $this " if ($this =~ /;SPM(gt|lt|amp);/);
 2227     } else {
 2228         # just append it; e.g. images, etc.
 2229     }
 2230     $pre =~ s/\s+//g; #remove all spaces...
 2231     if ($pre) {
 2232         # put space back around numbers
 2233 #       $pre =~ s/([\d\.,]+)($|\W)/"$1".(($2)? " $2" :'')/eg;
 2234 #       $pre =~ s/([^\s\.,\(\[\/\w])(\d+)/$1 $2/g;
 2235         #...italiced alphabetics, except if sup/subscripts
 2236         if ($face eq "I") {
 2237         $pre =~ s/([a-zA-Z][a-zA-Z\']*)/<$face>$1<\/$face>/go unless ($slevel);
 2238         # ... but not inside <...> tags
 2239         $pre =~ s/(<\/?)<$face>([a-zA-Z][a-zA-Z\']*)<\/$face>>/$1$2>/go;
 2240         } else {
 2241         # but all alphanumerics, with a special style 
 2242         $pre =~ s/(([\.\,]?\w[\w\']*)+)/<$face>$1<\/$face>/go
 2243         }
 2244         # but don't split multipliers from multiplicands
 2245         $pre =~ s/(\d) </$1</g; 
 2246         # remove spaces just created around brackets etc.
 2247         $pre =~ s/\s*(^|[\{\}\(\)\[\]\|\!\/]|$)\s*/$1/g;
 2248 
 2249         # ensure space around = + - signs
 2250         $pre =~ s/([=\+\-\:])\s*/ $1 /g if ($math_outer);
 2251         # ... but some operators should not have a preceding space...
 2252         $pre =~ s/(\s|&nbsp;)+([\}\)\]])/$2/g;
 2253         # and some should not have a trailing space
 2254         $pre =~ s/([\{\(\[])(\s|&nbsp;)+/$1/g;
 2255         # some letters usually slope too far
 2256         $pre =~ s/([dfl]<\/$face>)([\(\)\/])\s*/$1 $2/g;
 2257         # ...and sometimes don't want spaces at the end
 2258         $pre =~ s/([\w>\!\)\]\|])\s+$/$1/;
 2259 #       # ensure a space after last closing bracket, without sub/sub
 2260 #       $pre =~ s/([\)\]\|])$/$1 /  if ($lastclosespace);
 2261         $pre =~ s/\s+/ /g;
 2262     }
 2263     # remove redundant <SUP/B> tags
 2264     $this =~ s/<SU(P|B)><\/SU\1>//g;
 2265     $this =~ s/<\/SU(P|B)><SU\1>//g;
 2266 
 2267     # append processed tokens, forbidding some spaces; e.g. "> <".
 2268     if ($pre) {
 2269         if (( $keep =~/>\s*$/ )&&( $pre =~ /^\s*[<\(\{\[\w]/ )) {
 2270             $keep =~ s/\s+$//; $pre =~ s/^\s+//;
 2271         }
 2272         if (( $keep =~/\w\s*$/ )&&( $pre =~ /^\s*[<\(\{[]/ )) {
 2273             $keep =~ s/\s+$//; $pre =~ s/^\s+//;
 2274         }
 2275 #       if (($pre =~/>\s*$/)&&($this =~ /^\s*</)) {
 2276 #           $pre =~ s/\s+$//; $this =~ s/^\s+//;
 2277 #       }
 2278     }
 2279 #   elsif (($keep =~/>\s*$/)&&($this =~ /^\s*([<\([\w])/)) {
 2280 #       $keep =~ s/\s+$//; $this =~ s/^\s+//;
 2281 #   }
 2282 
 2283     print STDERR "\nMATH:${math_outer}:${keep}:${pre}:${this}:" if ($VERBOSITY > 4);
 2284     $keep .= $pre . $this;
 2285     }
 2286 
 2287     # the leftovers should be all simple characters also.
 2288     s/\s*//g;
 2289     if ($_) {
 2290 #   s/([\d\.,]+)($|\W)/"$1".(($2)? " $2" :'')/eg;
 2291 #   s/([^\s\.,\(\[\/\w])(\d+)/$1 $2/g;
 2292     if ($face eq "I") {
 2293             s/([a-zA-Z][a-zA-Z\']*)/<I>$1<\/I>/go unless ($slevel);
 2294         # ...but not inside <...> tags
 2295         s/(<\/?)<I>([a-zA-Z\']+)<\/I>>/$1$2>/go;
 2296     } elsif ($face) {
 2297             s/(([\.\,]?\w[\w\']*)+)/<$face>$1<\/$face>/go
 2298     }
 2299     s/<I>(\d+)<\/I>/$1/go unless ($slevel);
 2300     s/(\d) </$1</g;
 2301     s/\s*(^|[\{\}\(\)\[\]\|\!\/]|$)\s*/$1/g;
 2302     s/([=\+\-\:])\s*/ $1 /g if ($math_outer);
 2303     s/([\(\[\{])(\s|&nbsp;)+/$1/g;
 2304     s/(\s|&nbsp;)+([\)\]\}])/$2/g;
 2305     s/([\!\)\]\|])\s*([\(\[\|])/$1$2/g;
 2306     s/([dfl]<\/$face>)([\(\)\/])\s*/$1 $2/g;
 2307     # ensure a space after some final characters, but not all
 2308     # suppress this by enclosing the whole expression in {}s
 2309 #   s/([\)\]\|\.,!>\w])$/$1 /;  # Why ?
 2310 #   $_ .= " " if ($math_outer);
 2311     s/ +$//; # ignore trailing spaces
 2312     } elsif ($math_outer) {
 2313     # final space unless ending with </SUP> or </SUB>
 2314     $keep .=" " unless (($keep =~/SU[BP]>$/)||(!$joinspace));
 2315     }
 2316     # don't allow this space: "> <"
 2317     if (($keep =~/>\s*$/)&&($_ =~ /^\s*</)) {
 2318     $keep =~ s/\s+$//; $_=~s/^\s+//;
 2319     }
 2320     print STDERR "\nMATH_OUT:${math_outer}:${keep}$_:" if ($VERBOSITY > 4);
 2321     $keep .= $_;
 2322 #    # italiced superscripts can be too close to some letters... (what a hack!)
 2323 #    $keep =~ s/([a-zA-Z]<\/I><SUP>)\s*/$1 /g unless ($face =~ /it/);
 2324 #    $keep =~ s/([a-zA-Z\d]<\/it><SUP>)\s*/$1 /g if ($face =~ /it/);
 2325 #    # ...but nested superscripts are OK
 2326 #    $keep =~ s/([a-zA-Z]<\/(I|it)><SUP> <\2>[^<]+<\/\2><SUP>)( |\s)+/$1/g;
 2327 #    $keep =~ s/\s*(&nbsp;)+\s*/&nbsp;/g; 
 2328     $keep =~ s/\s(\s)\s*/\1/g;
 2329     $keep =~ s/^(\s*[\+\-]) ([\w\d])/$1$2/o; # unary plus/minus, not binary
 2330 #    $keep =~ s/([\,\:\|])(<I>|\w)/$1 $2/g;  # space after punctuation
 2331     $keep =~ s/([\,\|])(<I>|\w)/$1 $2/g;  # space after punctuation
 2332     # recognise an integral's differential; e.g. dx 
 2333     if (($afterint)&&($keep =~ s/(;SPM(thin|nb)sp;|~)\s*<I>d/$1d<I>/g)) {
 2334     $afterint--; $keep =~ s/<I><\/I>// }
 2335     $keep;
 2336 }
 2337 
 2338 # the next token is either {...} or \<name> or an entity.
 2339 sub get_next_token {
 2340     local($strict) = @_;
 2341     local($this,$cmd)=('',"^ or \_ ");
 2342     do {
 2343     s/$next_token_rx/$this = $&;''/eo;
 2344     if ($strict &&(length($this) > 1)&&($this =~ /^\\/)) {
 2345         local($tmp) = 'do_cmd_'.$';
 2346         if ((defined &$tmp)||($this =~ /^\\(math|text)/)) {
 2347         $_ = $this .' '. $_;
 2348         $this = &missing_braces();
 2349         }
 2350     }
 2351     } unless (
 2352         (s/$next_pair_pr_rx/$this = $2;''/eo)
 2353         ||(s/$next_pair_rx/$this = $2;''/eo));
 2354     s/^$comment_mark\d+//o; $this =~ s/^\s*//o;
 2355     if ($this =~ /^(\&|;)$/) { s/^([a-zA-Z]+;(#\w+;)?)/$this.=$1;''/eo; } 
 2356     elsif ($this eq '') { s/^\s*([&;][a-zA-Z]+;)/$this =$1;''/eo; }
 2357     $this;
 2358 }
 2359 
 2360 # This extracts sup/sub-scripts that follow immediately.
 2361 # It alters $_ in the caller.
 2362 # ...this is meant for code to be passed to LaTeX
 2363 sub get_supsub {
 2364     local($supsub,$supb,$which,$getit) = ('','','');
 2365     $supsub = "\\limits" if (s/^[\s%]*(\\limits|\&limits\;)//);
 2366     while (s/^[\s%]*(\^|_|\'|\\prime|\\begin(($O|$OP)\d+($C|$CP))(Sb|Sp)\2)/$supb=$1;''/eo ) {
 2367     $which .= $supb;
 2368     if ($supb =~ /\^|\_/) {
 2369         $getit = &get_next_token(1);
 2370         $supsub .= join('', $supb,"\{",$getit,"\}")
 2371             unless ($getit eq '');
 2372     } elsif ($5) {
 2373         $supsub .= $1; $which .= (($5 =~ /b/) ? '_' : '^');
 2374         local($multisub_type) = $5;
 2375         s/\\end(($O|$OP)\d+($C|$CP))$multisub_type\1/$supsub .= $`.$&;''/em;
 2376     } else { $supsub .= "\{^\\prime\}" }
 2377     }
 2378     # include dummy sup/sub-scripts to enhance the vertical spacing
 2379     # when not a nested sup/subscript
 2380     do {
 2381     $supsub .= "_{}" unless ($which =~ /\_|\\prime|\'/);
 2382     $supsub .= "^{}" unless ($which =~ /\^|\'|\\prime/ );
 2383     } unless (($slevel)||(!$which));
 2384     $supsub =~ s/^\\limits$//;
 2385     $supsub;
 2386 }
 2387 
 2388 
 2389 # These regular expressions help decide the type of a math-entity,
 2390 # so that extra white space may be inserted, as desirable or necessary.
 2391 
 2392 #$binary_ops_rx = "(pm|mp|times|plus|minus|div|ast|star|circ|dot|triangle\\w|cap|cup|vee|wedge|bullet|diamond\$|wr\$|oslash|amalg|dagger|lhd|rhd)";
 2393 
 2394 $binary_ops_rx = "(times|plus|minus|div|circ|dot|cap|cup|vee|wedge|wr\$|amalg|lhd|rhd)";
 2395 
 2396 $binary_rels_rx = "(eq|prec|succ|\^ll\$|\^gg\$|subset|supset|\^in\$|\^ni\$|dash|sim|approx|cong|asymp|prop|models|perp|\^mid\$|parallel|bowtie|Join|smile|frown)";
 2397 
 2398 $arrow_rels_rx = "(arrow|harpoon|mapsto|leadsto)";
 2399 
 2400      
 2401 
 2402 &ignore_commands( <<_IGNORED_CMDS_);
 2403 allowbreak
 2404 mathord
 2405 mathbin
 2406 mathrel
 2407 mathop
 2408 mathopen
 2409 mathclose
 2410 mathpunct
 2411 mathalpha
 2412 mathrm
 2413 mathbf
 2414 mathtt
 2415 mathit
 2416 mathbb
 2417 mathcal
 2418 cal
 2419 mathsf
 2420 smash
 2421 _IGNORED_CMDS_
 2422 
 2423     # Commands which need to be passed, ALONG WITH THEIR ARGUMENTS, to TeX.
 2424 
 2425 &process_commands_inline_in_tex( <<_LATEX_CMDS_);
 2426 #mathbb # {}
 2427 #mathcal # {}
 2428 #mathsf # {}
 2429 _LATEX_CMDS_
 2430 
 2431 
 2432 1;
 2433 
 2434 
 2435 
 2436 
 2437 
 2438 
 2439 
 2440 
 2441