<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># Copyright (C) 1998-09  Stephane Galland &lt;galland@arakhne.org&gt;
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.  If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

=pod

=head1 NAME

Bib2HTML::Translator::TeX - A translator from TeX to HTML

=head1 SYNOPSYS

use Bib2HTML::Translator::BibTeX ;

my $gen = Bib2HTML::Translator::TeX-&gt;new( filename ) ;

=head1 DESCRIPTION

Bib2HTML::Translator::TeX is a Perl module, which translate a
TeX string into an HTML string

=head1 GETTING STARTED

=head2 Initialization

To create a parser, say something like this:

    use Bib2HTML::Translator::TeX;

    my $parser = Bib2HTML::Translator::TeX-&gt;new( 'toto.bib', '&lt;math&gt;', '&lt;/math&gt;' ) ;

...or something similar. Acceptable parameters to the constructor are:

=over

=item * filename (string)

is the filename under parsing.

=item * start_math (optional string)

is the HTML balise which permits to start the math mode

=item * stop_math (optional string)

is the HTML balise which permits to stop the math mode

=back

=head1 METHOD DESCRIPTIONS

This section contains only the methods in Parser.pm itself.

=over

=cut

package Bib2HTML::Translator::TeX;

@ISA = ('Exporter');
@EXPORT = qw();
@EXPORT_OK = qw( &amp;addtrans_char &amp;gettrans_char
		 &amp;addtrans_cmd_noparam &amp;addtrans_cmd
		 &amp;addtrans_cmd_func &amp;gettrans_cmd
		 &amp;display_supported_commands );

use strict;
use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
use Exporter;
use Carp ;

use Bib2HTML::General::Misc ;
use Bib2HTML::General::HTML ;
use Bib2HTML::General::Error ;
use Bib2HTML::General::Verbose ;
use Bib2HTML::Translator::BibTeXEntry ;

#------------------------------------------------------
#
# Global vars
#
#------------------------------------------------------

# Version number of the parser
my $VERSION = "3.0" ;

###############################################################
# This is the list of characters which will be automatically
# and directly translatable into a HTML entity
#
my %TEX_HTML_CHAR_TRANS = ( '~' =&gt; '&amp;nbsp;', #unsecable space
			    '£' =&gt; '&amp;pound;', #pound sign
			    '¤' =&gt; '&amp;curren;', #currency sign
			    '|' =&gt; '&amp;brvbar', #broken bar = broken vertical bar
			    '§' =&gt; '&amp;sect;', #section sign
			    '°' =&gt; '&amp;deg;', #degree sign
			    '²' =&gt; '&amp;sup2;', #superscript two = superscript digit two = squared
			    'µ' =&gt; '&amp;micro;', #micro sign
			    'À' =&gt; '&amp;Agrave;', #latin capital letter A with grave = latin capital letter A grave
			    'Á' =&gt; '&amp;Aacute;', #latin capital letter A with acute
			    'Â' =&gt; '&amp;Acirc;', #latin capital letter A with circumflex
			    'Ã' =&gt; '&amp;Atilde;', #latin capital letter A with tilde
			    'Ä' =&gt; '&amp;Auml;', #latin capital letter A with diaeresis
			    'Å' =&gt; '&amp;Aring;', #latin capital letter A with ring above = latin capital letter A ring
			    'Æ' =&gt; '&amp;AElig;', #latin capital letter AE = latin capital ligature AE
			    'Ç' =&gt; '&amp;Ccedil;', #latin capital letter C with cedilla
			    'È' =&gt; '&amp;Egrave;', #latin capital letter E with grave
			    'É' =&gt; '&amp;Eacute;', #latin capital letter E with acute
			    'Ê' =&gt; '&amp;Ecirc;', #latin capital letter E with circumflex
			    'Ë' =&gt; '&amp;Euml;', #latin capital letter E with diaeresis
			    'Ì' =&gt; '&amp;Igrave;', #latin capital letter I with grave
			    'Í' =&gt; '&amp;Iacute;', #latin capital letter I with acute
			    'Î' =&gt; '&amp;Icirc;', #latin capital letter I with circumflex
			    'Ï' =&gt; '&amp;Iuml;', #latin capital letter I with diaeresis
			    'Ñ' =&gt; '&amp;Ntilde;', #latin capital letter N with tilde
			    'Ò' =&gt; '&amp;Ograve;', #latin capital letter O with grave
			    'Ó' =&gt; '&amp;Oacute;', #latin capital letter O with acute
			    'Ô' =&gt; '&amp;Ocirc;', #latin capital letter O with circumflex
			    'Õ' =&gt; '&amp;Otilde;', #latin capital letter O with tilde
			    'Ö' =&gt; '&amp;Ouml;', #latin capital letter O with diaeresis
			    'Ø' =&gt; '&amp;Oslash;', #latin capital letter O with stroke = latin capital letter O slash
			    'Ù' =&gt; '&amp;Ugrave;', #latin capital letter U with grave
			    'Ú' =&gt; '&amp;Uacute;', #latin capital letter U with acute
			    'Û' =&gt; '&amp;Ucirc;', #latin capital letter U with circumflex
			    'Ü' =&gt; '&amp;Uuml;', #latin capital letter U with diaeresis
			    'Ý' =&gt; '&amp;Yacute;', #latin capital letter Y with acute
			    'à' =&gt; '&amp;agrave;', #latin small letter a with grave = latin small letter a grave
			    'á' =&gt; '&amp;aacute;', #latin small letter a with acute
			    'â' =&gt; '&amp;acirc;', #latin small letter a with circumflex
			    'ã' =&gt; '&amp;atilde;', #latin small letter a with tilde
			    'ä' =&gt; '&amp;auml;', #latin small letter a with diaeresis
			    'å' =&gt; '&amp;aring;', #latin small letter a with ring above = latin small letter a ring
			    'æ' =&gt; '&amp;aelig;', #latin small letter ae = latin small ligature ae
			    'ç' =&gt; '&amp;ccedil;', #latin small letter c with cedilla
			    'è' =&gt; '&amp;egrave;', #latin small letter e with grave
			    'é' =&gt; '&amp;eacute;', #latin small letter e with acute
			    'ê' =&gt; '&amp;ecirc;', #latin small letter e with circumflex
			    'ë' =&gt; '&amp;euml;', #latin small letter e with diaeresis
			    'ì' =&gt; '&amp;igrave;', #latin small letter i with grave
			    'í' =&gt; '&amp;iacute;', #latin small letter i with acute
			    'î' =&gt; '&amp;icirc;', #latin small letter i with circumflex
			    'ï' =&gt; '&amp;iuml;', #latin small letter i with diaeresis
			    'ñ' =&gt; '&amp;ntilde;', #latin small letter n with tilde
			    'ò' =&gt; '&amp;ograve;', #latin small letter o with grave
			    'ó' =&gt; '&amp;oacute;', #latin small letter o with acute
			    'ô' =&gt; '&amp;ocirc;', #latin small letter o with circumflex
			    'õ' =&gt; '&amp;otilde;', #latin small letter o with tilde
			    'ö' =&gt; '&amp;ouml;', #latin small letter o with diaeresis
			    'ø' =&gt; '&amp;oslash;', #latin small letter o with stroke = latin small letter o slash
			    'ù' =&gt; '&amp;ugrave;', #latin small letter u with grave
			    'ú' =&gt; '&amp;uacute;', #latin small letter u with acute
			    'û' =&gt; '&amp;ucirc;', #latin small letter u with circumflex
			    'ü' =&gt; '&amp;uuml;', #latin small letter u with diaeresis
			    'ý' =&gt; '&amp;yacute;', #latin small letter y with acute
			    'ÿ' =&gt; '&amp;yuml;', #latin small letter y with diaeresis
			    '"' =&gt; '&amp;quot;', #quotation mark = APL quote
			    '^' =&gt; '&amp;circ;', #modifier letter circumflex accent
			    '&lt;' =&gt; '&amp;lt;', #less-than sign
			    '&gt;' =&gt; '&amp;gt;', #greater-than sign
			  ) ;

###############################################################
# This is the list of text-mode commands.
# The commands must respect one of the following formats:
# 1) 'TeXCmdName' =&gt; "HTML code"
#       permits to translate the LaTeX command \TeXCmdName
#       into the specified "HTML code".
# 2) 'TeXCmdName' =&gt; { 'params' =&gt; params
#                      'html' =&gt; "HTML code"
#                    }
#         replaces the command \TeXCmdName by the specified
#         "HTML code". This last could contains a parameter
#         number (eg, #1 for the first, #2 for the second,
#         etc.) which will be replaced by the value
#         passed to the LaTeX command. The params specifies
#         the parameter prototype of the LaTeX command. It
#         must contains one (or more) of:
#         {}     for a needed parameter
#         [d]    for an optional parameter. d
#                is the default value given to this parameter
#                if it was not provided inside the LaTeX code
#         \\     for a LaTeX command name
#         !      indicates that the following sign ({} or[])
#                must not be interpreted by the LaTeX
#                translator. It must be used for verbatim
#                output
#         -      to read the text until the end of the current
#                LaTeX context
# 3) 'TeXCmdName' =&gt; { 'params' =&gt; params
#                      'latex' =&gt; "LaTeX code"
#                    }
#         replaces the command \TeXCmdName by the specified
#         "LaTeX code". This last could contains a parameter
#         number (eg, #1 for the first, #2 for the second,
#         etc.)  which will be replaced by the value
#         passed to the LaTeX command. The params specifies
#         the parameter prototype of the LaTeX command. It
#         must contains one (or more) of the macros defined
#         in the point 2).
# 4) 'TeXCmdName' =&gt; { 'params' =&gt; params
#                      'func' =&gt; "callback_function_name"
#                    }
#         replaces the command \TeXCmdName by the result of
#         the specified callback function. This callback
#         function must take, at least, 1 parameters:
#         the current line number. The parameters of the
#         LaTeX command will be passed to this callback
#         function after this line number.
#         Example: for \newcommand{\cmdname}[4][default]{code #2}
#                  we implements the callback function:
#                  sub texcommand_newcommand {
#                    my $lineno = shift || 0 ;
#                    my ($cmdname,$nb_params) =
#                       ( $_[0], $_[1] || 0 ) ;
#                    my ($default,$code) =
#                       ($_[2] || '', $_[3] || '') ;
#                    ...
#                    return '' ;
#                  }
#         The params specifies the parameter prototype of
#         the LaTeX command. It must contains one (or more)
#         of the macros defined in the point 2).
# 5) 'TeXCmdName' =&gt; { 'params' =&gt; params
#                      'texfunc' =&gt; "callback_function_name"
#                    }
#         replaces the command \TeXCmdName by the result of
#         the specified callback function. The callback
#         must assume that its result was some LaTeX expression
#         which will be evaluated (this is the major difference
#         between a 'func' and a 'texfunc', VERY IMPORTANT point).
#         The callback function works same as for 'func' (point 4).
#
my %TEX_HTML_COMMANDS = (

			 ' '                 =&gt; ' ',
			 '_'                 =&gt; '_', # underline sign
			 '-'                 =&gt; '', # hyphenation sign
			 '$'                 =&gt; '\$',
			 ','                 =&gt; '&amp;nbsp;',
			 ';'                 =&gt; '&amp;nbsp;',
			 '%'                 =&gt; '%',
			 '}'                 =&gt; '}',
			 '{'                 =&gt; '{',
			 '&amp;'                 =&gt; '&amp;amp;',
			 '\\'                =&gt; '&lt;br&gt;',
			 '&amp;'                 =&gt; '&amp;amp;', #ampersand
			 # Patch by Norbert Preining added the 2003/03/17
			 '#'		     =&gt; '#',
			 '\''                =&gt; { 'params' =&gt; '{}',
						  'func' =&gt; 'texcommand_acute',
						},
			 '`'                 =&gt; { 'params' =&gt; '{}',
						  'func' =&gt; 'texcommand_grave',
						},
			 '~'                 =&gt; { 'params' =&gt; '{}',
						  'func' =&gt; 'texcommand_tilde',
						},
			 '"'                 =&gt; { 'params' =&gt; '{}',
						  'func' =&gt; 'texcommand_uml',
						},
			 '^'                 =&gt; { 'params' =&gt; '{}',
						  'func' =&gt; 'texcommand_circ',
						},
			 '='                 =&gt; { 'params' =&gt; '{}', # One parameter
						  'func' =&gt; 'texcommand_bar',
						},
			 'AA'                =&gt; '&amp;Aring;',
			 'aa'                =&gt; '&amp;aring;',
			 'AE'                =&gt; '&amp;AElig;', #latin small letter ae = latin small ligature ae
			 'ae'                =&gt; '&amp;aelig;', #latin small letter ae = latin small ligature ae
			 'begin'             =&gt; { 'params' =&gt; '!{}', # Start environment
						  'texfunc' =&gt; 'texcommand_beginenv',
						},
			 'backslash'         =&gt; '\\',
			 'beginblock'        =&gt; '', # Ignored
			 'bf'                =&gt; { 'params' =&gt; '-', # Bold font
						  'func' =&gt; 'texcommand_font_bold',
						},
			 'bfseries'          =&gt; { 'params' =&gt; '-', # Bold font
						  'func' =&gt; 'texcommand_font_bold',
						},
			 'BibtoHTML'         =&gt; 'B&lt;small&gt;IB&lt;/small&gt;2HTML', # Bib2HTML logo
			 'bibtohtml'         =&gt; 'B&lt;small&gt;IB&lt;/small&gt;2HTML', # Bib2HTML logo
			 'BibTeX'            =&gt; 'B&lt;small&gt;IB&lt;/small&gt;T&lt;small&gt;E&lt;/small&gt;X', # BibTeX logo
			 'c'                 =&gt; { 'params' =&gt; '{}',
					          'func' =&gt; 'texcommand_cedil',
						},
			 'cdot'              =&gt; '&amp;middot;', #middle dot = Georgian comma = Greek middle dot
			 'cite'              =&gt; { 'params' =&gt; '[]{}',
						  'func' =&gt; 'texcommand_cite',
						},
			 'def'               =&gt; { 'params' =&gt; '\\{}',
						  'func' =&gt; 'texcommand_def',
						},
			 'degree'            =&gt; '&amp;deg;', #degree sign
			 'dg'                =&gt; '&amp;eth;', #latin small letter eth
			 'DH'                =&gt; '&amp;ETH;', #latin capital letter ETH
			 'div'               =&gt; '&amp;divide;', #division sign
			 'edef'              =&gt; { 'params' =&gt; '\\{}',
						  'func' =&gt; 'texcommand_edef',
						},
			 'Emph'              =&gt; { 'params' =&gt; '{}',
						  'html' =&gt; '&lt;strong&gt;#1&lt;/strong&gt;',
						},
			 'em'                =&gt; { 'params' =&gt; '-', # Emphasis
						  'html' =&gt; "&lt;em&gt;#1&lt;/em&gt;",
						},
			 'emph'              =&gt; { 'params' =&gt; '{}', # Emphasis
						  'html' =&gt; '&lt;em&gt;#1&lt;/em&gt;',
						},
			 'end'               =&gt; { 'params' =&gt; '!{}', # End environment
						  'texfunc' =&gt; 'texcommand_endenv',
						},
			 'enditemize'        =&gt; '&lt;/UL&gt;',
			 'ensuremath'        =&gt; { 'params' =&gt; '{}',
						  'func' =&gt; 'texcommand_ensuremath',
						},
			 'footnotesize'      =&gt; { 'params' =&gt; '-',
						  'html' =&gt; "&lt;font size=\"-2\"&gt;#1&lt;/font&gt;",
						},
			 'gdef'              =&gt; { 'params' =&gt; '\\{}',
						  'func' =&gt; 'texcommand_def',
						},
			 'global'            =&gt; '', # ignored
			 'guillemotleft'     =&gt; '&amp;laquo;', #left-pointing double angle quotation mark
			 'guillemotright'    =&gt; '&amp;raquo;', #right-pointing double angle quotation mark = right pointing guillemet
			 'Huge'              =&gt; { 'params' =&gt; '-',
						  'html' =&gt; "&lt;font size=\"+5\"&gt;#1&lt;/font&gt;",
						},
			 'html'              =&gt; { 'params' =&gt; '!{}', # verbatim HTML code
						  'html' =&gt; '#1',
						},
			 'huge'              =&gt; { 'params' =&gt; '-',
						  'html' =&gt; "&lt;font size=\"+4\"&gt;#1&lt;/font&gt;",
						},
			 'i'                 =&gt; 'i',
			 'it'                =&gt; { 'params' =&gt; '-', # Italic font
						  'func' =&gt; 'texcommand_font_italic',
						},
			 'item'              =&gt; '&lt;LI&gt;',
			 'itshape'           =&gt; { 'params' =&gt; '-', # Italic font
						  'func' =&gt; 'texcommand_font_italic',
						},
			 # Patch by Norbert Preining added the 2003/03/17
			 'L'		     =&gt; 'L', # L bar
			 'LARGE'             =&gt; { 'params' =&gt; '-',
						  'html' =&gt; "&lt;font size=\"+3\"&gt;#1&lt;/font&gt;",
						},
			 'Large'             =&gt; { 'params' =&gt; '-',
						  'html' =&gt; "&lt;font size=\"+2\"&gt;#1&lt;/font&gt;",
						},
			 'LaTeX'             =&gt; 'L&lt;sup&gt;&lt;small&gt;A&lt;/small&gt;&lt;/sup&gt;T&lt;small&gt;E&lt;/small&gt;X', # LaTeX logo
			 'large'             =&gt; { 'params' =&gt; '-',
						  'html' =&gt; "&lt;font size=\"+1\"&gt;#1&lt;/font&gt;",
						},
			 'latex'             =&gt; { 'params' =&gt; '{}', # Ignore the LaTeX commands
						  'html' =&gt; '',
						},
			 'lnot'              =&gt; '&amp;not;', #not sign
			 'mdseries'          =&gt; { 'params' =&gt; '-', # Unbold Font
						  'func' =&gt; 'texcommand_font_medium',
						},
			 'newcommand'        =&gt; { 'params' =&gt; '{}[][]{}',
						  'func' =&gt; 'texcommand_newcommand',
						},
			 'normalfont'        =&gt; { 'params' =&gt; '-',
						  'func' =&gt; 'texcommand_font_normal',
						},
			 'normalsize'        =&gt; { 'params' =&gt; '-',
						  'html' =&gt; "&lt;font size=\"+0\"&gt;#1&lt;/font&gt;",
						},
			 'O'                 =&gt; '&amp;Oslash;',
			 'o'                 =&gt; '&amp;oslash;',
			 'OE'                =&gt; '&amp;OElig;', #latin capital ligature OE
			 'oe'                =&gt; '&amp;oelig;', #latin small ligature oe
			 'P'                 =&gt; '&amp;para;', #pilcrow sign = paragraph sign
			 'pm'                =&gt; '&amp;plusmn;', #plus-minus sign = plus-or-minus sign
			 'pounds'            =&gt; '&amp;pounds;', #pound sign
			 'renewcommand'      =&gt; { 'params' =&gt; '{}[][]{}',
						  'func' =&gt; 'texcommand_newcommand',
						},
			 'rm'                =&gt; { 'params' =&gt; '-', # Roman font
						  'func' =&gt; "texcommand_font_roman",
						},
			 'rmfamily'          =&gt; { 'params' =&gt; '-', # Roman font
						  'func' =&gt; "texcommand_font_roman",
						},
			 'S'                 =&gt; '&amp;sect;', #section sign
			 'sc'                =&gt; { 'params' =&gt; '-', # Small-caps font
						  'func' =&gt; "texcommand_font_smallcap",
						},
			 'scriptsize'        =&gt; { 'params' =&gt; '-',
						  'html' =&gt; "&lt;font size=\"-3\"&gt;#1&lt;/font&gt;",
						},
			 'scshape'           =&gt; { 'params' =&gt; '-', # Small-caps font
						  'func' =&gt; "texcommand_font_smallcap",
						},
			 'sf'                =&gt; { 'params' =&gt; '-', # Sans Serif font
						  'func' =&gt; "texcommand_font_serif",
						},
			 'sffamily'          =&gt; { 'params' =&gt; '-', # Sans Serif font
						  'func' =&gt; "texcommand_font_serif",
						},
			 'sl'                =&gt; { 'params' =&gt; '-', # Slanted font
						  'func' =&gt; "texcommand_font_slanted",
						},
			 'slshape'           =&gt; { 'params' =&gt; '-', # Slanted font
						  'func' =&gt; "texcommand_font_slanted",
						},
			 'small'             =&gt; { 'params' =&gt; '-',
						  'html' =&gt; "&lt;font size=\"-1\"&gt;#1&lt;/font&gt;",
						},
			 'ss'                =&gt; '&amp;szlig;', #latin small letter sharp s = ess-zed
			 'startblock'        =&gt; '', # Ignored
			 'startitemize'      =&gt; '&lt;UL&gt;',
			 'string'            =&gt; { 'params' =&gt; '{}',
						  'html' =&gt; "#1",
						},
			 'TeX'               =&gt; 'T&lt;small&gt;E&lt;/small&gt;X', # TeX logo
			 'text'              =&gt; { 'params' =&gt; '{}',
						  'func' =&gt; 'texcommand_ensuretext',
						},
			 'textasciicircum'   =&gt; '&amp;circ;', # circumflex accent sign
			 'textasciitilde'    =&gt; '~', # tilde sign
			 'textbackslash'     =&gt; '\\',
			 'textbf'            =&gt; { 'params' =&gt; '{}', # Bold font
						  'func' =&gt; 'texcommand_font_bold',
						},
			 'textbrokenbar'     =&gt; '&amp;brvbar;', #broken bar = broken vertical bar
			 'textcent'          =&gt; '&amp;cent;', #cent sign
			 'textcopyright'     =&gt; '&amp;copy;', #copyright sign
			 'textcurrency'      =&gt; '&amp;curren;', #currency sign
			 'textexcladown'     =&gt; '&amp;iexcl;', #inverted exclamation mark, U+00A1 ISOnum
			 'textit'            =&gt; { 'params' =&gt; '{}', # Italic Font
						  'func' =&gt; 'texcommand_font_italic',
						},
			 'textmd'            =&gt; { 'params' =&gt; '{}', # Unbold Font
						  'func' =&gt; 'texcommand_font_medium',
						},
			 'textnormal'        =&gt; { 'params' =&gt; '{}',
						  'func' =&gt; 'texcommand_font_normal',
						},
			 'textonehalf'       =&gt; '&amp;frac12;', #vulgar fraction one half = fraction one half
			 'textonequarter'    =&gt; '&amp;frac14;', #vulgar fraction one quarter = fraction one quarter
			 'textordfeminine'   =&gt; '&amp;ordf;', #feminine ordinal indicator
			 'textordmasculine'  =&gt; '&amp;ordm;', #masculine ordinal indicator
			 'textquestiondown'  =&gt; '&amp;iquest;', #inverted question mark = turned question mark
			 'textregistered'    =&gt; '&amp;reg;', #registered sign = registered trade mark sign
			 'textrm'            =&gt; { 'params' =&gt; '{}', # Roman Font
						  'func' =&gt; 'texcommand_font_roman',
						},
			 'textsc'            =&gt; { 'params' =&gt; '{}', # Small-caps Font
						  'func' =&gt; 'texcommand_font_smallcap',
						},
			 'textsf'            =&gt; { 'params' =&gt; '{}', # Sans Serif Font
						  'func' =&gt; 'texcommand_font_serif',
						},
			 'textsl'            =&gt; { 'params' =&gt; '{}', # Slanted Font
						  'func' =&gt; 'texcommand_font_slanted',
						},
			 'textthreequarters' =&gt; '&amp;frac34;', #vulgar fraction three quarters = fraction three quarters
			 'texttt'            =&gt; { 'params' =&gt; '{}',
						  'func' =&gt; 'texcommand_font_typewriter',
						},
			 'textup'            =&gt; { 'params' =&gt; '{}', # Up right font
						  'func' =&gt; 'texcommand_font_upright',
						},
			 'textyen'           =&gt; '&amp;yen;', #yen sign = yuan sign
			 'times'             =&gt; '&amp;times;', #multiplication sign
			 'tiny'              =&gt; { 'params' =&gt; '-',
						  'html' =&gt; "&lt;font size=\"-4\"&gt;#1&lt;/font&gt;",
						},
			 'TH'                =&gt; '&amp;THORN;', #latin capital letter THORN
			 'th'                =&gt; '&amp;thorn;', #latin small letter thorn
			 'tt'                =&gt; { 'params' =&gt; '-', # Typewriter font
						  'func' =&gt; "texcommand_font_typewriter",
						},
			 'ttfamily'          =&gt; { 'params' =&gt; '-', # Type writer font
						  'func' =&gt; 'texcommand_font_typewriter',
						},
			 'u'                 =&gt; { 'params' =&gt; '{}', # added by Tobia
					          'func' =&gt; 'texcommand_ucircle',
						},
			 'uline'             =&gt; { 'params' =&gt; '{}', # Underline font
						  'html' =&gt; "&lt;u&gt;#1&lt;/u&gt;",
						},
			 'upshape'           =&gt; { 'params' =&gt; '{}', # Up right font
						  'func' =&gt; 'texcommand_font_upright',
						},
			 'url'               =&gt; { 'params' =&gt; '{}', # URL hyperlink
						  'html' =&gt; "&lt;a=\"#1\"&gt;#1&lt;/a&gt;",
						},
			 'v'                 =&gt; { 'params' =&gt; '{}',
						  'func' =&gt; 'texcommand_caron',
						},
			 'xdef'              =&gt; { 'params' =&gt; '\\{}',
						  'func' =&gt; 'texcommand_edef',
						},

			) ;

###############################################################
# This is the list of math-mode commands.
# The commands must respect one of the following formats:
# 1) 'TeXCmdName' =&gt; "HTML code"
#       permits to translate the LaTeX command \TeXCmdName
#       into the specified "HTML code".
# 2) 'TeXCmdName' =&gt; { 'params' =&gt; params
#                      'html' =&gt; "HTML code"
#                    }
#         replaces the command \TeXCmdName by the specified
#         "HTML code". This last could contains a parameter
#         number (eg, #1 for the first, #2 for the second,
#         etc.) which will be replaced by the value
#         passed to the LaTeX command. The params specifies
#         the parameter prototype of the LaTeX command. It
#         must contains one (or more) of:
#         {}     for a needed parameter
#         [d]    for an optional parameter. d
#                is the default value given to this parameter
#                if it was not provided inside the LaTeX code
#         \\     for a LaTeX command name
#         !      indicates that the following sign ({} or[])
#                must not be interpreted by the LaTeX
#                translator. It must be used for verbatim
#                output
#         -      to read the text until the end of the current
#                LaTeX context
# 3) 'TeXCmdName' =&gt; { 'params' =&gt; params
#                      'latex' =&gt; "LaTeX code"
#                    }
#         replaces the command \TeXCmdName by the specified
#         "LaTeX code". This last could contains a parameter
#         number (eg, #1 for the first, #2 for the second,
#         etc.)  which will be replaced by the value
#         passed to the LaTeX command. The params specifies
#         the parameter prototype of the LaTeX command. It
#         must contains one (or more) of the macros defined
#         in the point 2).
# 3) 'TeXCmdName' =&gt; { 'params' =&gt; params
#                      'func' =&gt; "callback_function_name"
#                    }
#         replaces the command \TeXCmdName by the result of
#         the specified callback function. This callback
#         function must take, at least, 1 parameters:
#         the current line number. The parameters of the
#         LaTeX command will be passed to this callback
#         function after this line number.
#         Example: for \newcommand{\cmdname}[4][default]{code #2}
#                  we implements the callback function:
#                  sub texcommand_newcommand {
#                    my $lineno = shift || 0 ;
#                    my ($cmdname,$nb_params) =
#                       ( $_[0], $_[1] || 0 ) ;
#                    my ($default,$code) =
#                       ($_[2] || '', $_[3] || '') ;
#                    ...
#                    return '' ;
#                  }
#         The params specifies the parameter prototype of
#         the LaTeX command. It must contains one (or more)
#         of the macros defined in the point 2).
# 4) 'TeXCmdName' =&gt; { 'params' =&gt; params
#                      'texfunc' =&gt; "callback_function_name"
#                    }
#         replaces the command \TeXCmdName by the result of
#         the specified callback function. The callback
#         must assume that its result was some LaTeX expression
#         which will be evaluated (this is the major difference
#         between a 'func' and a 'texfunc', VERY IMPORTANT point).
#         The callback function works same as for 'func' (point 3).
#
my %MATH_TEX_HTML_COMMANDS = (

			      '}'                 =&gt; '}',
			      '{'                 =&gt; '{',
			      '&amp;'                 =&gt; '&amp;amp;',
			      '_'                 =&gt; { 'params' =&gt; "{}",
						       'html' =&gt; "&lt;sub&gt;#1&lt;/sub&gt;",
						       'special' =&gt; 1,
						     },
			      '^'                 =&gt; { 'params' =&gt; "{}",
						       'html' =&gt; "&lt;sup class=\"exponent\"&gt;#1&lt;/sup&gt;",
						       'special' =&gt; 1,
						     },

			      'mathmicro'         =&gt; '&amp;micro;', #micro sign
			      'maththreesuperior' =&gt; '&amp;sup3;', #superscript three = superscript digit three = cubed
			      'mathtwosuperior'   =&gt; '&amp;sup2;', #superscript two = superscript digit two = squared

			      # MATH-ML commands
			      'alpha' =&gt; "&amp;alpha;",
			      'angle' =&gt; "&amp;ang;",
			      'approx' =&gt; "&amp;asymp;",
			      'ast' =&gt; "&amp;lowast;",
			      'beta' =&gt; "&amp;beta;",
			      'bot' =&gt; "&amp;perp;",
			      'bullet' =&gt; "&amp;bull;",
			      'cap' =&gt; "&amp;cap;",
			      'cdots' =&gt; "&amp;hellip;",
			      'chi' =&gt; "&amp;chi;",
			      'clubsuit' =&gt; "&amp;clubs;",
			      'cong' =&gt; "&amp;cong;",
			      'cup' =&gt; "&amp;cup;",
			      'dagger' =&gt; "&amp;dagger;",
			      'ddagger' =&gt; "&amp;Dagger;",
			      'delta' =&gt; "&amp;delta;",
			      'Delta' =&gt; "&amp;Delta;",
			      'diamondsuit' =&gt; "&amp;loz;",
			      'div' =&gt; "&amp;divide;",
			      'downarrow' =&gt; "&amp;darr;",
			      'Downarrow' =&gt; "&amp;dArr;",
			      'emptyset' =&gt; "&amp;empty;",
			      'epsilon' =&gt; "&amp;epsilon;",
			      'Epsilon' =&gt; "&amp;Epsilon;",
			      'equiv' =&gt; "&amp;equiv;",
			      'eta' =&gt; "&amp;eta;",
			      'exists' =&gt; "&amp;exist;",
			      'forall' =&gt; "&amp;forall;",
			      'gamma' =&gt; "&amp;gamma;",
			      'Gamma' =&gt; "&amp;Gamma;",
			      'geq' =&gt; "&amp;ge;",
			      'heartsuit' =&gt; "&amp;hearts;",
			      'Im' =&gt; "&amp;image;",
			      'in' =&gt; "&amp;isin;",
			      'infty' =&gt; "&amp;infin;",
			      'infinity' =&gt; "&amp;infin;",
			      'int' =&gt; "&amp;int;",
			      'iota' =&gt; "&amp;iota;",
			      'kappa' =&gt; "&amp;kappa;",
			      'lambda' =&gt; "&amp;lambda;",
			      'Lambda' =&gt; "&amp;Lambda;",
			      'langle' =&gt; "&amp;lang;",
			      'lceil' =&gt; "&amp;lceil;",
			      'ldots' =&gt; "&amp;hellip;",
			      'leftarrow' =&gt; "&amp;larr;",
			      'Leftarrow' =&gt; "&amp;lArr;",
			      'leftrightarrow' =&gt; "&amp;harr;",
			      'Leftrightarrow' =&gt; "&amp;hArr;",
			      'leq' =&gt; "&amp;le;",
			      'lfloor' =&gt; "&amp;lfloor;",
			      'mathbb'  =&gt; { 'params' =&gt; '{}', # Math Set characters
					     'func' =&gt; 'texcommand_font_mathset',
					   },
			      'mathbf'  =&gt; { 'params' =&gt; '{}', # Bold font
					     'func' =&gt; 'texcommand_font_bold',
					   },
			      'mathit'  =&gt; { 'params' =&gt; '{}', # Italic Font
				 	     'func' =&gt; 'texcommand_font_italic',
				    	   },
			      'mathrm'  =&gt; { 'params' =&gt; '{}', # Roman Font
				             'func' =&gt; 'texcommand_font_roman',
					   },
			      'mathsf'	=&gt; { 'params' =&gt; '{}', # Sans Serif Font
			                     'func' =&gt; 'texcommand_font_serif',
			                   },
			      'mathtt'  =&gt; { 'params' =&gt; '{}',
			                     'func' =&gt; 'texcommand_font_typewriter',
					   },
			      'mathnormal'  =&gt; { 'params' =&gt; '{}',
					         'func' =&gt; 'texcommand_font_normal',
						},
			      'mu' =&gt; "&amp;mu;",
			      'nabla' =&gt; "&amp;nabla;",
			      'neg' =&gt; "&amp;not;",
			      'neq' =&gt; "&amp;ne;",
			      'ni' =&gt; "&amp;ni;",
			      'not\in' =&gt; "&amp;notin;",
			      'not\subset' =&gt; "&amp;nsub;",
			      'nu' =&gt; "&amp;nu;",
			      'omega' =&gt; "&amp;omega;",
			      'Omega' =&gt; "&amp;Omega;",
			      'ominus' =&gt; "&amp;ominus;",
			      'oplus' =&gt; "&amp;oplus;",
			      'oslash' =&gt; "&amp;oslash;",
			      'Oslash' =&gt; "&amp;Oslash;",
			      'otimes' =&gt; "&amp;otimes;",
			      'partial' =&gt; "&amp;part;",
			      'phi' =&gt; "&amp;phi;",
			      'Phi' =&gt; "&amp;Phi;",
			      'pi' =&gt; "&amp;pi;",
			      'Pi' =&gt; "&amp;Pi;",
			      'pm' =&gt; "&amp;plusmn;",
			      'prime' =&gt; "&amp;prime;",
			      'prod' =&gt; "&amp;prod;",
			      'propto' =&gt; "&amp;prop;",
			      'psi' =&gt; "&amp;psi;",
			      'Psi' =&gt; "&amp;Psi;",
			      'rangle' =&gt; "&amp;rang;",
			      'rceil' =&gt; "&amp;rceil;",
			      'Re' =&gt; "&amp;real;",
			      'rfloor' =&gt; "&amp;rfloor;",
			      'rho' =&gt; "&amp;rho;",
			      'rightarrow' =&gt; "&amp;rarr;",
			      'Rightarrow' =&gt; "&amp;rArr;",
			      'sigma' =&gt; "&amp;sigma;",
			      'Sigma' =&gt; "&amp;Sigma;",
			      'sim' =&gt; "&amp;sim;",
			      'spadesuit' =&gt; "&amp;spades;",
			      'sqrt' =&gt; "&amp;radic;",
			      'subseteq' =&gt; "&amp;sube;",
			      'subset' =&gt; "&amp;sub;",
			      'sum' =&gt; "&amp;sum;",
			      'supseteq' =&gt; "&amp;supe;",
			      'supset' =&gt; "&amp;sup;",
			      'surd' =&gt; "&amp;radic;",
			      'tau' =&gt; "&amp;tau;",
			      'theta' =&gt; "&amp;theta;",
			      'Theta' =&gt; "&amp;Theta;",
			      'times' =&gt; "&amp;times;",
			      'to' =&gt; "&amp;rarr;",
			      'uparrow' =&gt; "&amp;uarr;",
			      'Uparrow' =&gt; "&amp;uArr;",
			      'upsilon' =&gt; "&amp;upsilon;",
			      'Upsilon' =&gt; "&amp;Upsilon;",
			      'varpi' =&gt; "&amp;piv;",
			      'vee' =&gt; "&amp;or;",
			      'wedge' =&gt; "&amp;and;",
			      'wp' =&gt; "&amp;weierp;",
			      'xi' =&gt; "&amp;xi;",
			      'Xi' =&gt; "&amp;Xi;",
			      'zeta' =&gt; "&amp;zeta;",

			     ) ;

#------------------------------------------------------
#
# Constructor
#
#------------------------------------------------------

sub new($;$$) : method {
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $parent = ref($proto) &amp;&amp; $proto ;

  my $self ;
  if ( $parent ) {
    %{$self} = %{$parent} ;
  }
  else {
    $self = { 'FILENAME' =&gt; $_[0] || '',
	      'DATABASE' =&gt; undef,
	      'MATH_MODE' =&gt; 0,
	      'MATH_MODE_START' =&gt; $_[2] || "&lt;math&gt;",
	      'MATH_MODE_STOP' =&gt; $_[3] || "&lt;/math&gt;",
	      'FONTS' =&gt; { 'ALLS' =&gt; [],
			   'SERIES' =&gt; [],
			   'FAMILIES' =&gt; [],
			   'SHAPES' =&gt; [],
			 },
	      'ENVIRONMENTS' =&gt; [],
	    } ;
  }
  bless( $self, $class );
  return $self;
}

#------------------------------------------------------
#
# Translation API
#
#------------------------------------------------------

=pod

=item * translate()

Translate the specified string from a TeX string to
an HTML string
Takes 3 args:

=over

=item * text (string)

is the text to translate

=item * database (hash)

is the complee database content.

=item * lineno (optional integer)

is the line number where the text can be found

=back

=cut
sub translate($$;$) : method {
  my $self = shift ;
  my $text = $_[0] || '' ;
  my $lineno = $_[2] || 0 ;
  my $html = '' ;

  if ( $_[1] ) {
    $self-&gt;{'DATABASE'} = $_[1] ;
  }

  # Search the first separator
  my ($eaten,$sep,$tex) = $self-&gt;eat_to_separator($text) ;

  while ($sep) {

    # Translate the already eaten string
    $eaten = $self-&gt;translate_chars( $eaten, $lineno ) ;

    if ( ( $sep eq '{' ) || ( $sep eq '}' ) ) {
      # Ignore braces
    }
    elsif ( $sep eq '\\' ) {
      (my $eaten2,$tex) = $self-&gt;translate_cmd($tex, $lineno, '\\') ;
      $eaten .= $eaten2 ;
    }
    elsif ( $sep eq '$' ) {
      # Math mode
      if ( ! $self-&gt;is_math_mode() ) {
	$eaten .= $self-&gt;start_math_mode(1) ;
      }
      elsif ( $self-&gt;is_inline_math_mode() ) {
	$eaten .= $self-&gt;stop_math_mode() ;
      }
      else {
	Bib2HTML::General::Error::warm( "you try to close with a '\$' a mathematical mode opened with '\\['",
					$self-&gt;{'FILENAME'},
					$lineno ) ;
      }
    }
    elsif ( ( $sep eq '_' ) ||
	    ( $sep eq '^' ) ) {
      # Special math mode commands
      (my $eaten2,$tex) = $self-&gt;translate_cmd($sep.$tex, $lineno ) ;
      $eaten .= $eaten2 ;
    }
    else { # Unknow separator, treat as text
      $eaten .= $self-&gt;translate_chars( $sep, $lineno ) ;
    }

    # Translate the text before the separator
    $html .= $eaten ;

    # Search the next separator
    ($eaten,$sep,$tex) = $self-&gt;eat_to_separator($tex) ;
  }

  if ( $eaten ) {
    $html .= $self-&gt;translate_chars( $eaten, $lineno ) ;
  }

  # Remove multiple white spaces
  $html =~ s/ +/ /g ;

  return $html ;
}

=pod

=item * eat_to_separator()

Eats the specified text until the first separator.
Takes 2 args:

=over

=item * text (string)

is the text to eat

=item * seps (optional string)

is the list of additional separators

=back

=cut
sub eat_to_separator($;$) : method {
  my $self = shift ;
  my $text = $_[0] || '' ;
  my $separators = $_[1] || '' ;
  my ($before,$sep,$after) ;

  $separators .= "_^{}\$\\\\" ;

  if ( $text =~ /^(.*?)([$separators])(.*)$/ ) {
    ($before,$sep,$after) = ($1,$2,$3) ;
  }
  else {
    $before = $text ;
    $sep = $after = '' ;
  }
  return ($before,$sep,$after) ;
}

=pod

=item * translate_chars()

Translate the chars inside the specified string.
Takes 2 args:

=over

=item * text (string)

is the text to translate

=item * lineno (integer)

=back

=cut
sub translate_chars($$) : method {
  my $self = shift ;
  my $html = $_[0] || '' ;
  my $lineno = $_[1] || 0 ;
  my @parts = split( /\&amp;/, $html ) ;
  for(my $i=0; $i&lt;@parts; $i++) {
    # Translate from the trans table
    while ( my ($char,$hstr) = each( %TEX_HTML_CHAR_TRANS ) ) {
      if ( $i &gt; 0 ) {
	Bib2HTML::General::Error::warm( "you type a '\&amp;'. It could be a LaTeX syntax error. Assume '\\&amp;'.",
					$self-&gt;{'FILENAME'}, $lineno ) ;
      }
      $parts[$i] =~ s/\Q$char\E/$hstr/g ;
    }
  }
  $html = join( '&amp;amp;', @parts ) ;
  return  get_restricted_html_entities( $html ) ;
}

=pod

=item * translate_cmd()

Translate a TeX command.
Takes 3 args:

=over

=item * text (string)

is the text, which follows the backslash, to scan

=item * lineno (integer)

=item * prefix (optional string)

is a prefix merged to the command name. Use carefully.

=back

=cut
sub translate_cmd($$;$) : method {
  my $self = shift ;
  my ($eaten,$tex,$lineno) = ('',
			      $_[0] || '',
			      $_[1] || 0 ) ;
  my $cmd_prefix = $_[2] || '' ;

  # Gets the command name
  if ( $tex =~ /^\[(.*)/ ) { # Starts multi-line math mode
    $tex = $1 ;
    if ( ! $self-&gt;is_math_mode() ) {
      $eaten .= $self-&gt;start_math_mode(2) ;
    }
    else {
      Bib2HTML::General::Error::warm( "you try to open twice a mathematical mode with '".$cmd_prefix."['",
				      $self-&gt;{'FILENAME'},
				      $lineno ) ;
    }
  }
  elsif ( $tex =~ /^\](.*)/ ) { # Stop multi-line math mode
    $tex = $1 ;
    if ( $self-&gt;is_multiline_math_mode() ) {
      $eaten .= $self-&gt;stop_math_mode() ;
    }
    elsif ( $self-&gt;is_math_mode() ) {
      Bib2HTML::General::Error::warm( "you try to close with a '".$cmd_prefix."[' a mathematical mode opened with '\$'",
				      $self-&gt;{'FILENAME'},
				      $lineno ) ;
    }
    else {
      Bib2HTML::General::Error::warm( "you try to close with '".$cmd_prefix."]' a mathematical mode which was not opened",
				      $self-&gt;{'FILENAME'},
				      $lineno ) ;
    }
  }
  elsif ( $tex =~ /^((?:[a-zA-Z]+)|.)(.*)/ ) { # default LaTeX command
    (my $cmdname,$tex) = ($1,$2) ;
    if ( $cmdname ) {
      my $trans = $self-&gt;search_cmd_trans( $cmdname, $lineno, ($cmd_prefix ne "\\") ) ;
      if ( defined( $trans ) ) {
	# Seach the command inside the translation table
	($eaten,$tex) = $self-&gt;run_cmd( $cmd_prefix.$cmdname, $trans, $tex, $lineno ) ;
      }
      elsif ( $self-&gt;is_math_mode() ) {
	Bib2HTML::General::Error::warm( "unrecognized TeX command in mathematical mode: ".
					$cmd_prefix.$cmdname,
					$self-&gt;{'FILENAME'},
					$lineno ) ;
	$eaten = "&lt;font color=\"gray\"&gt;[$cmdname]&lt;/font&gt;" ;
      }
      else {
	Bib2HTML::General::Error::warm( "unrecognized TeX command: ".
					$cmd_prefix.$cmdname,
					$self-&gt;{'FILENAME'},
					$lineno ) ;
	$eaten = "&lt;font color=\"gray\"&gt;[$cmdname]&lt;/font&gt;" ;
      }
    }
    else {
      Bib2HTML::General::Error::warm( "invalid syntax for the TeX command: ".
				      $cmd_prefix.$_[0],
				      $self-&gt;{'FILENAME'},
				      $lineno ) ;
      $eaten = $cmd_prefix ;
    }
  }
  else {
    Bib2HTML::General::Error::warm( "invalid syntax for the TeX command: ".
				    $cmd_prefix.$_[0],
                                    $self-&gt;{'FILENAME'},
				    $lineno ) ;
    $eaten = $cmd_prefix ;
  }

  return ($eaten,$tex) ;
}

=pod

=item * search_cmd_trans()

Replies the translation entry that corresponds to
the specified TeX command.
Takes 3 args:

=over

=item * name (string)

is the name of the TeX command to search.

=item * lineno (integer)

=item * special (optional boolean)

indicates if the searched command has a special purpose
(example: _ in math mode)

=back

=cut
sub search_cmd_trans($$;$) : method {
  my $self = shift ;
  my $lineno = $_[1] || 0 ;
  my $special = $_[2] ;
  my ($math, $text) ;
  my ($found_math,$found_text) = (0,0) ;
  if ( ( $_[0] ) &amp;&amp;
       ( exists $MATH_TEX_HTML_COMMANDS{$_[0]} ) ) {
    $found_math = ( ( ( !$special ) &amp;&amp;
		      ( ( ! ishash( $MATH_TEX_HTML_COMMANDS{$_[0]} ) ) ||
			( ! exists $MATH_TEX_HTML_COMMANDS{$_[0]}{'special'} ) ||
			( ! $MATH_TEX_HTML_COMMANDS{$_[0]}{'special'} ) ) ) ||
		    ( ( $special ) &amp;&amp;
		      ( ishash( $MATH_TEX_HTML_COMMANDS{$_[0]} ) ) &amp;&amp;
		      ( exists $MATH_TEX_HTML_COMMANDS{$_[0]}{'special'} ) &amp;&amp;
		      ( $MATH_TEX_HTML_COMMANDS{$_[0]}{'special'} ) ) ) ;
    $math = $MATH_TEX_HTML_COMMANDS{$_[0]}
      if ( $found_math ) ;
  }
  if ( ( $_[0] ) &amp;&amp;
       ( exists $TEX_HTML_COMMANDS{$_[0]} ) ) {
    $found_text = ( ( ( !$special ) &amp;&amp;
		      ( ( ! ishash( $TEX_HTML_COMMANDS{$_[0]} ) ) ||
			( ! exists $TEX_HTML_COMMANDS{$_[0]}{'special'} ) ||
			( ! $TEX_HTML_COMMANDS{$_[0]}{'special'} ) ) ) ||
		    ( ( $special ) &amp;&amp;
		      ( ishash( $TEX_HTML_COMMANDS{$_[0]} ) ) &amp;&amp;
		      ( exists $TEX_HTML_COMMANDS{$_[0]}{'special'} ) &amp;&amp;
		      ( $TEX_HTML_COMMANDS{$_[0]}{'special'} ) ) ) ;
    $text = $TEX_HTML_COMMANDS{$_[0]}
      if ( $found_text ) ;
  }

  if ( $found_math || $found_text ) {
    if ( $self-&gt;is_math_mode() ) {
      if ( ! $found_math ) {
	Bib2HTML::General::Error::warm( "the command ".
					( $special ? '' : '\\' ).
					$_[0].
					" was not defined for math-mode, assumes to use the text-mode version instead",
					$self-&gt;{'FILENAME'}, $lineno ) ;
	return $text ;
      }
      else {
	return $math ;
      }
    }
    elsif ( ! $found_text ) {
      Bib2HTML::General::Error::warm( "the command ".
				      ( $special ? '' : '\\' ).
				      $_[0].
				      " was not defined for text-mode, assumes to use the math-mode version instead",
				      $self-&gt;{'FILENAME'}, $lineno ) ;
      return $math ;
    }
    else {
      return $text ;
    }
  }
  return undef ;
}

=pod

=item * run_cmd()

Eaten the specified tex according to the specified command.
Takes 4 args:

=over

=item * name (string)

is the name of the TeX command.

=item * trans (mixed)

is the translation for the command.

=item * text (string)

is the text from which some data must be extracted to
treat the command.

=item * lineno(integer)

is le line number where the text starts

=back

=cut
sub run_cmd($$$$) : method {
  my $self = shift ;
  my ($eaten,$cmdname,$tex,$lineno) = ('',
				       $_[0] || confess( 'you must supply the TeX command name'),
				       $_[2] || '',
				       $_[3] || 0 ) ;
  if ( ( ishash( $_[1] ) ) &amp;&amp;
       ( exists $_[1]-&gt;{'params'} ) ) {
    # This command has params
    ($tex,my @params) = $self-&gt;eat_cmd_parameters( $_[1]-&gt;{'params'}, $tex, $lineno ) ;
    # Apply the command
    if ( exists $_[1]-&gt;{'html'} ) {
      # Replace by the HTML translation
      $eaten = $_[1]-&gt;{'html'} ;
      for(my $i=1; $i&lt;=@params; $i++) {
	if ( $eaten =~ /\#$i/ ) {
	  my $p = ($params[$i-1])-&gt;{'text'} ;
	  if ( ($params[$i-1])-&gt;{'eval'} ) {
	    $p = $self-&gt;translate( $p, undef, $lineno ) ;
	  }
	  $eaten =~ s/\#$i/$p/g ;
	}
      }
    }
    elsif ( exists $_[1]-&gt;{'latex'} ) {
      # Replace by the LaTeX commands
      my $cmd = $_[1]-&gt;{'latex'} ;
      for(my $i=1; $i&lt;=@params; $i++) {
	if ( $cmd =~ /\#$i/ ) {
	  my $p = ($params[$i-1])-&gt;{'text'} ;
	  if ( ($params[$i-1])-&gt;{'eval'} ) {
	    $p = $self-&gt;translate( $p, undef, $lineno ) ;
	  }
	  $cmd =~ s/\#$i/$p/g ;
	}
      }
      $tex = $cmd.$tex ;
    }
    elsif ( exists $_[1]-&gt;{'func'} ) {
      # Replace by the string replied by the callback function
      my $reffunc = $self-&gt;can($_[1]-&gt;{'func'}) ;
      if ( $reffunc ) {
	$eaten = $self-&gt;$reffunc( $lineno, @params ) ;
      }
      elsif ( issub( $_[1]-&gt;{'func'} ) ) {
	$eaten = $_[1]-&gt;{'func'}( $lineno, @params ) ;
      }
      else {
        Bib2HTML::General::Error::warm( "unable to find the callback function 'sub ".
                                        $_[1]-&gt;{'func'}.
                                        "{}' for the TeX command $cmdname",
                                        $self-&gt;{'FILENAME'},
					$lineno ) ;
      }
    }
    elsif ( exists $_[1]-&gt;{'texfunc'} ) {
      # Replace by the string replied by the callback function
      my $reffunc = $self-&gt;can($_[1]-&gt;{'texfunc'}) ;
      if ( $reffunc ) {
	my $result = $self-&gt;$reffunc( $lineno, @params ) ;
	$tex = $result . $tex ;
      }
      elsif ( issub( $_[1]-&gt;{'texfunc'} ) ) {
	my $result = $_[1]-&gt;{'texfunc'}( $lineno, @params ) ;
	$tex = $result . $tex ;
      }
      else {
        Bib2HTML::General::Error::warm( "unable to find the callback function 'sub ".
                                        $_[1]-&gt;{'func'}.
                                        "{}' for the TeX command $cmdname",
                                        $self-&gt;{'FILENAME'},
					$lineno ) ;
      }
    }
  }
  else {
    # No param, put the HTML string inside the output stream
    $eaten = $_[1] ;
  }
  return ($eaten,$tex) ;
}

=pod

=item * eat_cmd_parameters()

Eaten the specified command parameters.
Takes 3 args:

=over

=item * params (string)

is the description of the parameters to eat.

=item * text (string)

is the text from which some data must be extracted.

=item * lineno (integer)

=back

=cut
sub eat_cmd_parameters($$$) : method {
  my $self = shift ;
  my $p_params = $_[0] || '' ;
  my $tex = $_[1] || '' ;
  my $lineno = $_[2] || 0 ;
  my @params = () ;
  while ( $p_params =~ /((?:\!?\{\})|(?:\!?\[[^\]]*\])|-|\\)/g ) {
    my $p = $1 ;
    # Eats no significant white spaces
    $tex =~ s/^ +// ;
    if ( $p =~ /^(\!?)\{\}/ ) { # Eates a needed parameter
      my $optional = $1 || '' ;
      my $prem = substr($tex,0,1) ;
      $tex = substr($tex,1) ;
      if ( $prem eq '{' ) {
	(my $context,$tex) = $self-&gt;eat_context( $tex, '\\}' ) ;
	push @params, { 'eval' =&gt; ($optional ne '!'),
			'text' =&gt; $context,
		      } ;
      }
      elsif ( $prem eq '\\' ) {
	(my $eaten,$tex) = $self-&gt;translate_cmd($tex, $lineno, '\\') ;
	push @params, { 'eval' =&gt; 0,
			'text' =&gt; $eaten,
		      } ;
      }
      else {
	push @params, { 'eval' =&gt; ($optional ne '!'),
			'text' =&gt; $prem,
		      } ;
      }
    }
    elsif( $p =~ /^(\!?)\[([^\]]*)\]/ ) { # Eates an optional parameter
      my ($optional,$default_val) = ( $1 || '', $2 || '' ) ;
      my $prem = substr($tex,0,1) ;
      if ( $prem eq '[' ) {
	(my $context,$tex) = $self-&gt;eat_context( substr($tex,1), '\\]' ) ;
	push @params, { 'eval' =&gt; ($optional ne '!'),
			'text' =&gt; $context,
		      } ;
      }
      else {
	push @params, { 'eval' =&gt; ($optional ne '!'),
			'text' =&gt; $default_val,
		      } ;
      }
    }
    elsif( $p eq '\\' ) { # Eates a TeX command name
      if ( $tex =~ /^\\((?:[a-zA-Z]+|.))(.*)$/ ) {
	$tex = $2 ;
	push @params, { 'eval' =&gt; 1,
			'text' =&gt; $1,
		      } ;
      }
      else {
        Bib2HTML::General::Error::warm( "expected a TeX command name: ".$tex,
                                        $self-&gt;{'FILENAME'},
					$lineno ) ;
	push @params, { 'eval' =&gt; 1,
			'text' =&gt; '',
		      } ;	
      }
    }
    elsif ( $p eq '-' ) { # Eates until the end of the current context
      (my $context,$tex) = $self-&gt;eat_context( $tex, '\\}' ) ;
      push @params, { 'eval' =&gt; 1,
		      'text' =&gt; $context,
		    } ;
    }
    else {
      confess( "unable to recognize the following argument specification: $p" ) ;
    }
  }
  return ($tex,@params) ;
}

=pod

=item * eat_context()

Eaten the current context.
Takes 2 args:

=over

=item * text (string)

is the text from which some data must be extracted.

=item * end (string)

is the ending separator

=back

=cut
sub eat_context($$) : method {
  my $self = shift ;
  my $text = $_[0] || '' ;
  my $enddelim = $_[1] || confess( 'you must supply the closing delimiter' ) ;
  my $context = '' ;
  my $contextlevel = 0 ;

  # Search the first separator
  my ($eaten,$sep,$tex) = $self-&gt;eat_to_separator($text,$enddelim) ;

  while ($sep) {

    if ( $sep eq '{' )  { # open a context
      $contextlevel ++ ;
      $eaten .= $sep ;
    }
    elsif ( $sep eq '}' ) { # close a context
      if ( $contextlevel &lt;= 0 ) {
	return ($context.$eaten,$tex) ;
      }
      $eaten .= $sep ;
      $contextlevel -- ;
    }
    elsif ( $sep eq '\\' ) {
      $tex =~ /^([a-zA-Z]+|.)(.*)$/ ;
      $eaten .= "\\$1";
      $tex = $2 ;
    }
    elsif ( ( $contextlevel &lt;= 0 ) &amp;&amp;
	    ( $sep =~ /$enddelim/ ) ) { # The closing delemiter was found
      return ($context.$eaten,$tex) ;
    }
    else { # Unknow separator, treat as text
      $eaten .= $sep ;
    }

    # Translate the text before the separator
    $context .= $eaten ;

    # Search the next separator
    ($eaten,$sep,$tex) = $self-&gt;eat_to_separator($tex,$enddelim) ;
  }

  return ($context.$eaten,$tex) ;
}

#------------------------------------------------------
#
# Translation table updates
#
#------------------------------------------------------

=pod

=item * start_math_mode()

Starts the mathematical mode.
Takes 1 arg:

=over

=item * mode (integer)

is the math mode to start (1: inline, 2: multi-line)

=back

=cut
sub start_math_mode($) {
  my $self = shift ;
  if ( $self-&gt;is_math_mode() ) {
    return '' ;
  }
  else {
    $self-&gt;{'MATH_MODE'} = ( $_[0] % 3 ) ;
    my $tag = '' ;
    if ( $self-&gt;{'MATH_MODE'} == 2 ) {
      $tag .= "&lt;blockquote&gt;" ;
    }
    return $tag.$self-&gt;{'MATH_MODE_START'} ;
  }
}

=pod

=item * stop_math_mode()

Stops the mathematical mode.

=cut
sub stop_math_mode() {
  my $self = shift ;
  if ( $self-&gt;is_math_mode() ) {
    my $tag = $self-&gt;{'MATH_MODE_STOP'} ;
    if ( $self-&gt;{'MATH_MODE'} == 2 ) {
      $tag .= "&lt;/blockquote&gt;" ;
    }
    $self-&gt;{'MATH_MODE'} = 0 ;
    return $tag ;
  }
  else {
    return '' ;
  }
}

=pod

=item * is_math_mode()

Replies if inside a mathematical mode.

=cut
sub is_math_mode() {
  my $self = shift ;
  return ( $self-&gt;{'MATH_MODE'} != 0 ) ;
}

=pod

=item * is_inline_math_mode()

Replies if inside a inlined mathematical mode.

=cut
sub is_inline_math_mode() {
  my $self = shift ;
  return ( $self-&gt;{'MATH_MODE'} == 1 ) ;
}

=pod

=item * is_multiline_math_mode()

Replies if inside a multi-lined mathematical mode.

=cut
sub is_multiline_math_mode() {
  my $self = shift ;
  return ( $self-&gt;{'MATH_MODE'} == 2 ) ;
}

#------------------------------------------------------
#
# Information
#
#------------------------------------------------------

=pod

=item * display_supported_commands()

Display the list of supported LaTeX commands.
Takes 1 arg:

=over

=item * perldir (string)

is the path to the directory where the Perl packages
are stored.

=back

=cut
sub display_supported_commands($) {
  my $path = $_[0] || confess( 'you must specify the pm path' ) ;
  my (@c1,@c2) = ((),()) ;
  foreach my $cmd ( keys %TEX_HTML_COMMANDS ) {
    my $prefix = '' ;
    if ( ( !ishash( $TEX_HTML_COMMANDS{$cmd} ) ) ||
	 ( ! exists $TEX_HTML_COMMANDS{$cmd}{'special'} ) ||
	 ( ! $TEX_HTML_COMMANDS{$cmd}{'special'} ) ) {
      $prefix = "\\" ;
    }
    if ( $cmd =~ /^[a-zA-Z0-9]/ ) {
      push @c2, $prefix.$cmd ;
    }
    else {
      push @c1, $prefix.$cmd ;
    }
  }
  foreach my $cmd ( keys %MATH_TEX_HTML_COMMANDS ) {
    if ( ! exists $TEX_HTML_COMMANDS{$cmd} ) {
      my $prefix = '' ;
      if ( ( !ishash( $TEX_HTML_COMMANDS{$cmd} ) ) ||
	   ( ! exists $TEX_HTML_COMMANDS{$cmd}{'special'} ) ||
	   ( ! $TEX_HTML_COMMANDS{$cmd}{'special'} ) ) {
	$prefix = "\\" ;
      }
      if ( $cmd =~ /^[a-zA-Z0-9]/ ) {
	push @c2, $prefix.$cmd ;
      }
      else {
	push @c1, $prefix.$cmd ;
      }
    }
  }
  foreach my $cmd ( sort @c1 ) {
    print "$cmd\n" ;
  }
  foreach my $cmd ( sort @c2 ) {
    print "$cmd\n" ;
  }
}

#------------------------------------------------------
#
# Translation table updates
#
#------------------------------------------------------

=pod

=item * addtrans_char()

Static method which permits to add a translation entry
for a character.
Takes 2 args:

=over

=item * char (string)

is the character to translate

=item * html (string)

is the HTML translation of the character.

=back

=cut
sub addtrans_char($$) {
  confess( 'you must supply the character to translate' ) unless $_[0] ;
  Bib2HTML::General::Verbose::three( "\tadd the HTML translation for '".$_[0]."'" ) ;
  $TEX_HTML_CHAR_TRANS{$_[0]} = ( $_[1] || '' ) ;
}

=pod

=item * gettrans_char()

Static method which replies the translation table from a character to HTML string.

=cut
sub gettrans_char() {
  return \%TEX_HTML_CHAR_TRANS ;
}

=pod

=item * addtrans_cmd_noparam()

Static method which permits to add a translation entry
for a TeX command. The new TeX command does not have any
parameter.
Takes 3 args:

=over

=item * cmd (string)

is the name od the TeX command

=item * html (string)

is the HTML translation of the character.

=item * tex_content (optional boolean)

indicates if the content contains LaTeX code (if true)
or HTML code (if false - default).

=back

=cut
sub addtrans_cmd_noparam($$;$) {
  confess( 'you must supply the character to translate' ) unless $_[0] ;
  Bib2HTML::General::Verbose::three( "\tadd the TeX translation for {\\".$_[0]."}" ) ;
  if ( $_[2] ) {
    $TEX_HTML_COMMANDS{$_[0]} = { 'params' =&gt; '',
				  'latex' =&gt; ( $_[1] || '' ),
				} ;
  }
  else {
    $TEX_HTML_COMMANDS{$_[0]} = ( $_[1] || '' ) ;
  }
}

=pod

=item * addtrans_cmd_html()

Static method which permits to add a translation entry
for a TeX command. The new TeX command has parameters, but
it can be directly translated as HTML code.
Takes 4 args:

=over

=item * cmd (string)

is the name od the TeX command

=item * params (string)

is the description of the parameters:

=over

=item {} for a parameter

=item [val] for an optional parameter where val is the default value

=item \ for a TeX command name

=item ! will avoid the LaTeX interpretation of the following sign ({} or [])

=item - for all the text until the end of the current context

=back

=item * html (string)

is the HTML translation of the character. #n means the n-th parameter,
where n is an integer greater or equal to 1.

=item * tex_content (optional boolean)

indicates if the content contains LaTeX code (if true)
or HTML code (if false - default).

=back

=cut
sub addtrans_cmd_html($$$;$) {
  confess( 'you must supply the TeX command name' ) unless $_[0] ;
  my $params = $_[1] || confess( 'you must supply the parameter description' ) ;
  my $html = $_[2] || '' ;
  if ( ( $params eq '-' ) ||
       ( $params =~ /(?:(?:\{\})|(?:\[[^\]]*\])|\\)+/ ) ) {
    Bib2HTML::General::Verbose::three( "\tadd the TeX translation for \\".$_[0].$params ) ;
    if ( $_[3] ) {
      %{$TEX_HTML_COMMANDS{$_[0]}} = ( 'params' =&gt; $params,
				       'latex' =&gt; $html,
				     ) ;
    }
    else {
      %{$TEX_HTML_COMMANDS{$_[0]}} = ( 'params' =&gt; $params,
				       'html' =&gt; $html,
				     ) ;
    }
  }
  else {
    Bib2HTML::General::Error::syserr( "invalid syntax for the parameters of the ".
                                      "TeX command '".$_[0]."': ".$params ) ;
  }
}

=pod

=item * addtrans_cmd_func()

Static method which permits to add a translation entry
for a TeX command. The new TeX command has parameters, but
a callback function must be called to treat this command.
Takes 3 args:

=over

=item * cmd (string)

is the name od the TeX command

=item * params (string)

is the description of the parameters:

=over

=item {} for a parameter

=item [val] for an optional parameter where val is the default value

=item \ for a TeX command name

=item ! will avoid the LaTeX interpretation of the following sign ({} or [])

=item - for all the text until the end of the current context

=back

=item * func (string)

is the name of the method to call.

=back

=cut
sub addtrans_cmd_func($$$) {
  confess( 'you must supply the TeX command name' ) unless $_[0] ;
  my $params = $_[1] || confess( 'you must supply the parameter description' ) ;
  my $func = $_[2] || confess( 'you must supply the callback function' ) ;
  if ( ( $params eq '-' ) ||
       ( $params =~ /(?:(?:\{\})|(?:\[[^\]]*\])|\\)+/ ) ) {
    Bib2HTML::General::Verbose::three( "\tadd the TeX translation for \\".$_[0].$params ) ;
    %{$TEX_HTML_COMMANDS{$_[0]}} = ( 'params' =&gt; $params,
				     'func' =&gt; $func,
				   ) ;
  }
  else {
    Bib2HTML::General::Error::syserr( "invalid syntax for the parameters of the ".
                                      "TeX command '".$_[0]."': ".$params ) ;
  }
}

=pod

=item * gettrans_cmd()

Replies the translation table from a TeX command to HTML string.

=cut
sub gettrans_cmd() {
  return \%TEX_HTML_COMMANDS ;
}

=pod

=item * __texcommand_map_to()

Makes the specified mapping of a TeX command.
Takes at least 4 args:

=over

=item * map (hash)

is the mapping associative array

=item * default (string)

is the default value return if the mapping was unavailable

=item * lineno (integer)

=item * params (array)

is the list of parameters

=back

=cut
sub __texcommand_map_to($$$) {
  my $self = shift ;
  my $lineno = $_[2] || 0 ;
  if ( ( $_[3] ) &amp;&amp;
       ( $_[3]-&gt;{'text'} ) ) {
    if ( $_[0]-&gt;{$_[3]-&gt;{'text'}} ) {
      return "&amp;".$_[0]-&gt;{$_[3]-&gt;{'text'}}.";" ;
    }
    else {
      # Patch by Norbert Preining added the 2003/03/17
	Bib2HTML::General::Error::warm( "An accentuation command was found, but the corresponding character '".
					$_[3]-&gt;{'text'}.
					"' is not supported. Assume '".
					$_[1].$_[3]-&gt;{'text'}."'.",
					$self-&gt;{'FILENAME'}, $lineno ) ;
    }
  }
  else {
    Bib2HTML::General::Error::warm( "no command name after a slash. Assume '".$_[1].$_[3]-&gt;{'text'}."'.",
				    $self-&gt;{'FILENAME'}, $lineno ) ;
  }
  # Patch by Norbert Preining added the 2003/03/17
  return "$_[1]$_[3]-&gt;{'text'}";
}

=pod

=item * __texcommand_font_series()

Apply the specified font series (Medium or Bold).
Takes at least 4 args:

=over

=item * start_balise (hash)

is the HTML balise used to start this style

=item * end_balise (hash)

is the HTML balise used to end this style

=item * fontset (string)

is the name of the font set to manage (eg, SERIES, SHAPES...)

=item * lineno (integer)

=item * params (array)

is the list of parameters

=back

=cut
sub __texcommand_font_style($$$$;@) {
  my $self = shift ;
  my $lineno = $_[2] || 0 ;
  my ($begin,$end) = ( $_[0] || '', $_[1] || '' ) ;
  my ($set,$text) = ( $_[2] || '', '' ) ;

  confess( "You must supply a valid fontset name (from ".
	   join( ', ', keys %{$self-&gt;{'FONTS'}} ).
	   ")." ) unless ( exists $self-&gt;{'FONTS'}{$set} ) ;

  my $last = ( int(@{$self-&gt;{'FONTS'}{$set}}) &gt; 0 ) ?
    $self-&gt;{'FONTS'}{$set}-&gt;[$#{$self-&gt;{'FONTS'}{$set}}] : '' ;

  my $elt = { 'begin' =&gt; $begin,
	      'end' =&gt; $end,
	    } ;
  push @{$self-&gt;{'FONTS'}{$set}}, $elt ;
  push @{$self-&gt;{'FONTS'}{'ALLS'}}, $elt ;

  if ( ( ! $last ) ||
       ( ! ishash( $last ) ) ||
       ( $last-&gt;{'begin'} ne $begin ) ) {
    $text .= ( ( $last &amp;&amp; ( ishash($last) ) ) ? $last-&gt;{'end'} : '' ).$begin ;
  }

  if ( ( $_[4] ) &amp;&amp; ( ishash( $_[4] ) ) ) {
    if ( $_[4]-&gt;{'eval'} ) {
      $text .= $self-&gt;translate( $_[4]-&gt;{'text'}, undef, $lineno ) ;
    }
    else {
      $text .= $_[4] ;
    }
  }

  if ( ( ! $last ) ||
       ( ! ishash( $last ) ) ||
       ( $last-&gt;{'begin'} ne $begin ) ) {
    $text .= $end.( ( $last &amp;&amp; ( ishash($last) ) ) ? $last-&gt;{'begin'} : '' ) ;
  }

  pop @{$self-&gt;{'FONTS'}{'ALLS'}} ;
  pop @{$self-&gt;{'FONTS'}{$set}} ;

  if ( $begin || $end ) {
    $text =~ s/\Q$begin$end\E//g ;
    $text =~ s/\Q$end$begin\E//g ;
  }

  return $text ;
}

#------------------------------------------------------
#
# TeX command callbacks
#
#------------------------------------------------------

=pod

=item * texcommand_font_medium()

Treats \textmd or \mdseries

=cut
sub texcommand_font_medium {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_font_style( '',
					 '',
					 'SERIES',
					 $lineno, @_ ) ;
}

=pod

=item * texcommand_font_mathset()

Treats \mathbb

=cut
sub texcommand_font_mathset {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_font_style( '&lt;i&gt;',
					 '&lt;/i&gt;',
					 'SERIES',
					 $lineno, @_ ) ;
}

=pod

=item * texcommand_font_bold()

Treats \bf or \textbf

=cut
sub texcommand_font_bold {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_font_style( '&lt;b&gt;',
					 '&lt;/b&gt;',
					 'SERIES',
					 $lineno, @_ ) ;
}

=pod

=item * texcommand_font_roman()

Treats \rm or \textrm

=cut
sub texcommand_font_roman {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_font_style( '',
					 '',
					 'FAMILIES',
					 $lineno, @_ ) ;
}

=pod

=item * texcommand_font_serif()

Treats \sf or \textsf

=cut
sub texcommand_font_serif {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_font_style( '&lt;font face="Sans Serif"&gt;',
					 '&lt;!-- /fontSF --&gt;&lt;/font&gt;',
					 'FAMILIES',
					 $lineno, @_ ) ;
}

=pod

=item * texcommand_font_typewriter()

Treats \tt or \texttt

=cut
sub texcommand_font_typewriter {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_font_style( '&lt;tt&gt;',
					 '&lt;/tt&gt;',
					 'FAMILIES',
					 $lineno, @_ ) ;
}

=pod

=item * texcommand_font_upright()

Treats \upshape or \textup

=cut
sub texcommand_font_upright {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_font_style( '',
					 '',
					 'SHAPES',
					 $lineno, @_ ) ;
}

=pod

=item * texcommand_font_italic()

Treats \it or \textit

=cut
sub texcommand_font_italic {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_font_style( '&lt;i&gt;',
					 '&lt;/i&gt;',
					 'SHAPES',
					 $lineno, @_ ) ;
}

=pod

=item * texcommand_font_slanted()

Treats \sl or \textsl

=cut
sub texcommand_font_slanted {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_font_style( '&lt;i&gt;&lt;tt&gt;',
					 '&lt;/tt&gt;&lt;/i&gt;',
					 'SHAPES',
					 $lineno, @_ ) ;
}

=pod

=item * texcommand_font_smallcap()

Treats \sc or \textsc

=cut
sub texcommand_font_smallcap {
  my $self = shift ;
  my $lineno = shift || 0 ;
  my $text =  $self-&gt;__texcommand_font_style( '&lt;!-- SMALL CAPS --&gt;',
					      '&lt;!-- /SMALL CAPS --&gt;',
					      'SHAPES',
					      $lineno, @_ ) ;
  my $r = '' ;
  while ( ( $text ) &amp;&amp;
	  ( $text =~ /^(.*?)&lt;!-- SMALL CAPS --&gt;(.*?)&lt;!-- \/SMALL CAPS --&gt;(.*)$/ ) ) {
    (my $prev, my $sc, $text) = ($1,$2,$3) ;
    $r .= $prev . html_sc( $sc ) ;
  }
  if ( $text ) {
    $r .= $text ;
  }
  return $r ;
}

=pod

=item * texcommand_font_normal()

Treats \textnormal or \normalfont

=cut
sub texcommand_font_normal {
  my $self = shift ;
  my $lineno = shift || 0 ;
  my ($begin,$end)=('','');
  foreach my $envs ( @{$self-&gt;{'FONTS'}{'ALLS'}} ) {
    if ( $envs ) {
      $begin .= $envs-&gt;{'begin'} ;
      $end = $envs-&gt;{'end'} . $end ;
    }
  }
  return $end.($_[0]-&gt;{'text'}||'').$begin ;
}

=pod

=item * texcommand_cedil()

Treats \c{}

=cut
sub texcommand_cedil {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_map_to( { 'C' =&gt; 'Ccedil',
				       'c' =&gt; 'ccedil',
				       'S' =&gt; '#x015e',
				       's' =&gt; '#x015f',
				       'T' =&gt; '#x0162',
				       't' =&gt; '#x0163',
				     },
				     "&amp;cedil;",
				     $lineno, @_ ) ;
}

=pod

=item * texcommand_ucircle()

Treats \u{}

=cut
sub texcommand_ucircle { # added by Tobia
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_map_to( { 'A' =&gt; '#x0102',
				       'a' =&gt; '#x0103',
				     },
				     "&amp;#x0306;",
				     $lineno, @_ ) ;
}

=pod

=item * texcommand_acute()

Treats \'{}

=cut
sub texcommand_acute {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_map_to( { 'A' =&gt; 'Aacute',
				       'E' =&gt; 'Eacute',
				       'I' =&gt; 'Iacute',
				       'O' =&gt; 'Oacute',
				       'U' =&gt; 'Uacute',
				       'Y' =&gt; 'Yacute',
				       'a' =&gt; 'aacute',
				       'e' =&gt; 'eacute',
				       'i' =&gt; 'iacute',
				       'o' =&gt; 'oacute',
				       'u' =&gt; 'uacute',
				       'y' =&gt; 'yacute',
				       '\\i' =&gt; 'iacute',
  #Patched by Gasper Jaklic &lt;gasper.jaklic@fmf.uni-lj.si&gt;
				       'C' =&gt; '#262',
				       'c' =&gt; '#263',
				     },
				     "&amp;acute;",
				     $lineno, @_ ) ;
}

=pod

=item * texcommand_grave()

Treats \'{}

=cut
sub texcommand_grave {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_map_to( { 'A' =&gt; 'Agrave',
				       'E' =&gt; 'Egrave',
				       'I' =&gt; 'Igrave',
				       'O' =&gt; 'Ograve',
				       'U' =&gt; 'Ugrave',
				       'a' =&gt; 'agrave',
				       'e' =&gt; 'egrave',
				       'i' =&gt; 'igrave',
				       'o' =&gt; 'ograve',
				       'u' =&gt; 'ugrave',
				       '\\i' =&gt; 'igrave',
				     },
				     "&amp;grave;",
				     $lineno, @_ ) ;
}

=pod

=item * texcommand_tilde()

Treats \~{}

=cut
sub texcommand_tilde {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_map_to( { 'A' =&gt; 'Atilde',
				       'N' =&gt; 'Ntilde',
				       'O' =&gt; 'Otilde',
				       'a' =&gt; 'atilde',
				       'n' =&gt; 'ntilde',
				       'o' =&gt; 'otilde',
				     },
				     "&amp;tilde;",
				     $lineno, @_ ) ;
}

=pod

=item * texcommand_uml()

Treats \"{}

=cut
sub texcommand_uml {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_map_to( { 'A' =&gt; 'Auml',
				       'E' =&gt; 'Euml',
				       'I' =&gt; 'Iuml',
				       'O' =&gt; 'Ouml',
				       'U' =&gt; 'Uuml',
				       'Y' =&gt; 'Yuml',
				       'a' =&gt; 'auml',
				       'e' =&gt; 'euml',
				       'i' =&gt; 'iuml',
				       'o' =&gt; 'ouml',
				       'u' =&gt; 'uuml',
				       'y' =&gt; 'yuml',
				       '\\i' =&gt; 'iuml',
				     },
				     "&amp;uml;",
				     $lineno, @_ ) ;
}

=pod

=item * texcommand_circ()

Treats \^{}

=cut
sub texcommand_circ {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_map_to( { 'A' =&gt; 'Acirc',
				       'E' =&gt; 'Ecirc',
				       'I' =&gt; 'Icirc',
				       'O' =&gt; 'Ocirc',
				       'U' =&gt; 'Ucirc',
				       'a' =&gt; 'acirc',
				       'e' =&gt; 'ecirc',
				       'i' =&gt; 'icirc',
				       'o' =&gt; 'ocirc',
				       'u' =&gt; 'ucirc',
				       '\\i' =&gt; 'icirc',
				     },
				     "&amp;circ;",
				     $lineno, @_ ) ;
}

=pod

=item * texcommand_caron()

Treats \v{}

=cut
sub texcommand_caron {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return $self-&gt;__texcommand_map_to( { 'S' =&gt; 'Scaron',
				       's' =&gt; 'scaron',
  #Patched by Luca Paolini &lt;paolini@di.unito.it&gt;
  #Patched by Gasper Jaklic &lt;gasper.jaklic@fmf.uni-lj.si&gt;
				       'C' =&gt; '#268',
				       'c' =&gt; '#269',
				       'D' =&gt; '#270',
				       'd' =&gt; '#271',
				       'E' =&gt; '#282',
				       'e' =&gt; '#283',
				       'L' =&gt; '#317',
				       'l' =&gt; '#318',
				       'N' =&gt; '#327',
				       'n' =&gt; '#328',
				       'R' =&gt; '#344',
				       'r' =&gt; '#345',
				       'T' =&gt; '#356',
				       't' =&gt; '#357',
				       'Z' =&gt; '#381',
				       'z' =&gt; '#382',
				     },
				     "",
				     $lineno, @_ ) ;
}

=pod

=item * texcommand_bar()

Treats \={}

=cut
sub texcommand_bar {
  my $self = shift ;
  my $lineno = shift || 0 ;
  return "&amp;macr;" unless $_[0] ;
  return $self-&gt;__texcommand_map_to( { },
				     "&amp;macr;",
				     $lineno, @_ ) ;
}

=pod

=item * texcommand_def()

Treats \def and \gdef

=cut
sub texcommand_def {
  my $self = shift ;
  my $lineno = shift || 0 ;
  Bib2HTML::General::Error::warm( "command name expected after a \\def or a \\gdef",
                                  $self-&gt;{'FILENAME'},
				  $lineno )
      unless $_[0]-&gt;{'text'} ;
  # The command definition is never evaluated
  my $trans_txt = $_[1]-&gt;{'text'} ;
  addtrans_cmd_noparam( $_[0]-&gt;{'text'}, $trans_txt, 1 ) ;
  return '' ;
}

=pod

=item * texcommand_edef()

Treats \edef and \xdef

=cut
sub texcommand_edef {
  my $self = shift ;
  my $lineno = shift || 0 ;
  Bib2HTML::General::Error::warm( "command name expected after a \\edef or a \\xdef",
                                  $self-&gt;{'FILENAME'},
				  $lineno )
      unless $_[0]-&gt;{'text'} ;
  # The command definition is always evaluated
  my $trans_txt = $self-&gt;translate( $_[1]-&gt;{'text'} || '', undef, $lineno ) ;
  addtrans_cmd_noparam( $_[0]-&gt;{'text'}, $trans_txt, 0 ) ;
  return '' ;
}

=pod

=item * texcommand_newcommand()

Treats \newcommand and \renewcommand

=cut
sub texcommand_newcommand {
  my $self = shift ;
  my $lineno = shift || 0 ;
  # Check for command name
  my $name = $_[0]-&gt;{'text'} || '' ;
  $name =~ s/^\\// ;
  if ( ! $name ) {
    Bib2HTML::General::Error::warm( "command name expected after a \\def",
				    $self-&gt;{'FILENAME'},
				    $lineno ) ;
    return '' ;
  }
  # Builds the parameter definition
  my $params = "" ;
  if ( ( $_[1]-&gt;{'text'} ) &amp;&amp; ( $_[1]-&gt;{'text'} &gt; 0 ) ) {
    my $count = $_[1]-&gt;{'text'} ;
    if ( $_[2]-&gt;{'text'} ) {
      $count -- ;
      $params .= '['.$_[2]-&gt;{'text'}.']' ;
    }
    while ( $count &gt; 0 ) {
      $count -- ;
      $params .= '{}' ;
    }
  }

  # The command definition is never evaluated
  my $trans = $_[3]-&gt;{'text'} || '' ;

  # Adds the command definition
  if ( $params ) {
    addtrans_cmd_html( $name, $params, $trans, 1 ) ;
  }
  else {
    addtrans_cmd_noparam( $name, $trans, 1 ) ;
  }
  return '' ;
}

=pod

=item * texcommand_ensuremath()

Treats \ensuremath

=cut
sub texcommand_ensuremath {
  my $self = shift ;
  my $lineno = shift || 0 ;
  my $trans = '' ;
  my $math = $self-&gt;is_math_mode() ;

  $trans = $self-&gt;start_math_mode(1) unless ( $math ) ;

  if ( $_[0]-&gt;{'eval'} ) {
    $trans .= $self-&gt;translate( $_[0]-&gt;{'text'} || '', undef, $lineno ) ;
  }
  else {
    $trans .= $_[0]-&gt;{'text'} || '' ;
  }

  $trans .= $self-&gt;stop_math_mode() unless ( $math ) ;

  return $trans ;
}

=pod

=item * texcommand_ensuretext()

Treats \text

=cut
sub texcommand_ensuretext {
  my $self = shift ;
  my $lineno = shift || 0 ;
  my $trans = '' ;
  my $math ;
  if ( $self-&gt;is_inline_math_mode() ) {
    $math = 1 ;
  }
  elsif ( $self-&gt;is_multiline_math_mode() ) {
    $math = 2 ;
  }
  else {
    $math = 0 ;
  }

  $trans = $self-&gt;stop_math_mode() if ( $math ) ;

  if ( $_[0]-&gt;{'eval'} ) {
    $trans .= $self-&gt;translate( $_[0]-&gt;{'text'} || '', undef, $lineno ) ;
  }
  else {
    $trans .= $_[0]-&gt;{'text'} || '' ;
  }

  $trans .= $self-&gt;start_math_mode( $math ) if ( $math ) ;

  return $trans ;
}

=pod

=item * texcommand_cite()

Treats \cite

=cut
sub texcommand_cite {
  my $self = shift ;
  my $lineno = shift || 0 ;
  my $key = $_[1]-&gt;{'text'} || '' ;
  my $label = $_[0]-&gt;{'text'} || '' ;
  my $cite = $label || '?' ;
  if ( ($key) &amp;&amp;
       ( ishash($self-&gt;{'DATABASE'}) ) &amp;&amp;
       ( ! isemptyhash( $self-&gt;{'DATABASE'} ) ) &amp;&amp;
       ( exists $self-&gt;{'DATABASE'}{$key} ) ) {
    $cite = "&lt;BIB2HTML action=CITE key=\"$key\"" ;
    if ( $label ) {
      my $bibtex = new Bib2HTML::Translator::BibTeXEntry() ;
      $bibtex-&gt;save_citation_label( $key, $label ) ;
      $cite .= " label=\"".addslashes( $label )."\"" ;
    }
    $cite .= "&gt;". ( $label || '?' ) . "&lt;/BIB2HTML&gt;" ;
  }
  return "[".$cite."]" ;
}

=pod

=item * texcommand_beginenv()

Treats \begin

=cut
sub texcommand_beginenv {
  my $self = shift ;
  my $lineno = shift || 0 ;
  my $env = $_[0]-&gt;{'text'} || '' ;

  if ( ! $env ) {
    Bib2HTML::General::Error::warm( "environment name not found for a command \\begin",
				    $self-&gt;{'FILENAME'},
				    $lineno ) ;
    return '' ;
  }

  # register the environment opening here to
  # prevent error during the closing
  push @{$self-&gt;{'ENVIRONMENTS'}}, $env ;

  return "\\start$env" ;
}

=pod

=item * texcommand_endenv()

Treats \end

=cut
sub texcommand_endenv {
  my $self = shift ;
  my $lineno = shift || 0 ;
  my $env = $_[0]-&gt;{'text'} || '' ;

  if ( ! $env ) {
    Bib2HTML::General::Error::warm( "environment name not found for a command \\end",
				    $self-&gt;{'FILENAME'},
				    $lineno ) ;
    return '' ;
  }

  # Pop the environment contex
  # and warm if the closed environment
  # does not match the opened
  if ( isemptyarray($self-&gt;{'ENVIRONMENTS'}) ) {
    Bib2HTML::General::Error::warm( "found \\end{$env} without \\begin{$env}",
				    $self-&gt;{'FILENAME'},
				    $lineno ) ;
    return '' ;
  }

  my $opened = $self-&gt;{'ENVIRONMENTS'}-&gt;[$#{$self-&gt;{'ENVIRONMENTS'}}] ;
  if ( ( !$opened ) ||
       ( $opened ne $env ) ) {
    Bib2HTML::General::Error::warm( "found \\end{$env} instead of \\end{$opened}",
				    $self-&gt;{'FILENAME'},
				    $lineno ) ;
    return '' ;
  }

  pop @{$self-&gt;{'ENVIRONMENTS'}} ;

  return "\\end$env" ;
}

1;
__END__

=back

=head1 COPYRIGHT

(c) Copyright 1998-09 Stéphane Galland E&lt;lt&gt;galland@arakhne.orgE&lt;gt&gt;, under GPL.

=head1 AUTHORS

=over

=item *

Conceived and initially developed by Stéphane Galland E&lt;lt&gt;galland@arakhne.orgE&lt;gt&gt;.
Some TeX commands are added by Dimitris Michail E&lt;lt&gt;michail@mpi-sb.mpg.deE&lt;gt&gt;
and Tobias Loew E&lt;lt&gt;loew@mathematik.tu-darmstadt.deE&lt;gt&gt;

=back

=head1 SEE ALSO

bib2html.pl
</pre></body></html>