#!/usr/bin/perl
#=======================================================================
# Copyright (c) 2000-2001 Daniele Giacomini daniele@swlibero.org
#
# 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; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#=======================================================================
# alml-sp2sp
#
# This separate Perl program is necessary because, if included inside
# the main program, it will take away all system resources, without
# releasing them. In practice: after the call to &sgml_post_sp_elab(),
# we are not able to run makeinfo or info2dvi. The worse thing is
# that these programs die without giving valid explanations: it seems
# that there is a mistake inside the Texinfo generated source, but
# there is none.
#=======================================================================

use POSIX;
use Locale::gettext;
setlocale (LC_MESSAGES, "");
textdomain ("alml");

#sub gettext
#{
#    return $_[0];
#}

#=======================================================================
# Global variables that should not be modifyed by hand.
#=======================================================================

# Program executable without path.
$program_executable = $0;
$program_executable =~ m{([^/]*)$};
$program_executable = $1;

# List of other temporary files that must be deleted at the end of
# elaboration.
$temp_files_list = "";

# Temporary file name prefix.
$temporary_file_name_prefix = "";

#=======================================================================
# Functions.
#=======================================================================

#-----------------------------------------------------------------------
# Define a temporary file.
#
# &temporary_file ( <prefix> )
#-----------------------------------------------------------------------
sub temporary_file
{
    local( $file_prefix ) = $_[0];
    local( $temp_dir ) = "";
    local( $random_number ) = 0;
    local( $random_file_name ) = "";

    # Check file prefix.
    if ( $file_prefix ne "" )
      {
        $file_prefix = $file_prefix . "_";
      }

    # Check for temp dir.
    if (-d $ENV{TEMPDIR}
        && -r $ENV{TEMPDIR}
        && -w $ENV{TEMPDIR}
        && -x $ENV{TEMPDIR})
      {
        # This directory is good.
        $temp_dir = $ENV{TEMPDIR};
      }
    elsif (-d "/tmp" && -r "/tmp" && -w "/tmp" && -x "/tmp")
      {
        # This other directory is good.
        $temp_dir = "/tmp";
      }
    elsif (-r "." && -w "." && -x ".")
      {
        # Current directory is good.
        $temp_dir = ".";
      }
    else
      {
        # We cannot use any temporary file!
        printf STDERR (gettext ("%s: cannot create any temporary file!\n"),
                       $program_executable);
        exit 1;
      }

    # If we are here, we have a valid temporary directory.
    # We try to find a good name for the file.
    while (1)
      {
        # Define the random number (six digits).
        $random_number = int ((rand) * 1000000);
        # Define the random file name: TF...tmp.
        $random_file_name = "$temp_dir/$file_prefix" . "TF${random_number}tmp";
        # Check if it is new.
        if (-e $random_file_name)
          {
            # The file exists already.
            next;
          }
        else
          {
            if (open (TEMP_FILE, "> $random_file_name"))
              {
                # It works.
                close( TEMP_FILE );
                last;
              }
            else
              {
                # Don't know what to do.
                printf STDERR
                  (gettext ("%s: cannot create the temporary file %s\n"),
                   $program_executable, $random_file_name);
                next;
              }

            # This point cannot be reached.
            printf STDERR
              (gettext ("%s: function %s unknown error 1\n"),
               $program_executable, "&temporary_file($file_prefix)");
          }

        # This point cannot be reached.
        printf STDERR
          (gettext ("%s: function %s unknown error 2\n"),
           $program_executable, "&temporary_file($file_prefix)");
      }         

    # Return the file name.
    return ("$random_file_name");
}

#-----------------------------------------------------------------------
# Convert a string into SP SDATA entities. That is, for example,
# "-" is converted into "\|[hyphen]\|".
#
# Some characters cannot be converted because it is difficult to
# distinguish them from escape sequence generated by SP output:
# "|", "[" and "]".
#
# &sp_text_to_sdata (TEXT)
#-----------------------------------------------------------------------
sub sp_text_to_sdata
{
    local ($line) = $_[0];

    # US-ASCII special characters for any typesetting system.
    $line =~ s/\x21/\\\|\[excl  \]\\\|/g;  # ISOnum : EXCLAMATION MARK
    $line =~ s/\x22/\\\|\[quot  \]\\\|/g;  # ISOnum : QUOTATION MARK
    $line =~ s/\x23/\\\|\[num   \]\\\|/g;  # ISOnum : NUMBER SIGN
    $line =~ s/\x24/\\\|\[dollar\]\\\|/g;  # ISOnum : dollar sign
    $line =~ s/\x25/\\\|\[percnt\]\\\|/g;  # ISOnum : percent sign
    $line =~ s/\x26/\\\|\[amp   \]\\\|/g;  # ISOnum : ampersand
    $line =~ s/\x27/\\\|\[apos  \]\\\|/g;  # ISOnum : apostrophe
    $line =~ s/\x28/\\\|\[lpar  \]\\\|/g;  # ISOnum : left parenthesis
    $line =~ s/\x29/\\\|\[rpar  \]\\\|/g;  # ISOnum : right parenthesis
    $line =~ s/\x2A/\\\|\[ast   \]\\\|/g;  # ISOnum : asterisk
    $line =~ s/\x2B/\\\|\[plus  \]\\\|/g;  # ISOnum : plus sign
    $line =~ s/\x2C/\\\|\[comma \]\\\|/g;  # ISOnum : comma
    $line =~ s/\x2D/\\\|\[hyphen\]\\\|/g;  # ISOnum : hyphen
    $line =~ s/\x2E/\\\|\[period\]\\\|/g;  # ISOnum : full stop, period
    $line =~ s/\x2F/\\\|\[sol   \]\\\|/g;  # ISOnum : solidus
    # numbers from 0 to 9 are not translated
    $line =~ s/\x3A/\\\|\[colon \]\\\|/g;  # ISOnum : colon
    $line =~ s/\x3B/\\\|\[semi  \]\\\|/g;  # ISOnum : semicolon
    $line =~ s/\x3C/\\\|\[lt    \]\\\|/g;  # ISOnum : less-than sign
    $line =~ s/\x3D/\\\|\[equals\]\\\|/g;  # ISOnum : equals sign
    $line =~ s/\x3E/\\\|\[gt    \]\\\|/g;  # ISOnum : greater-than sign
    $line =~ s/\x3F/\\\|\[quest \]\\\|/g;  # ISOnum : question mark
    $line =~ s/\x40/\\\|\[commat\]\\\|/g;  # ISOnum : commercial at
    # letters from A to Z are not translated
    #$line =~ s/\x5B/\\\|\[lsqb  \]\\\|/g;  # ISOnum : left square bracket
    $line =~ s/\x5C\x5C/\\\|\[bsol  \]\\\|/g;  # ISOnum : reverse solidus - this is special!
    #$line =~ s/\x5D/\\\|\[rsqb  \]\\\|/g;  # ISOnum : right square bracket
    $line =~ s/\x5E/\\\|\[circ  \]\\\|/g;  # ISOnum : circumflex accent
    $line =~ s/\x5F/\\\|\[lowbar\]\\\|/g;  # ISOnum : low line
    $line =~ s/\x60/\\\|\[lsquo \]\\\|/g;  # ISOnum : single quotation mark, left
    # letters from a to z are not translated
    $line =~ s/\x7B/\\\|\[lcub  \]\\\|/g;  # ISOnum : left curly bracket
    #$line =~ s/\x7C/\\\|\[verbar\]\\\|/g;  # ISOnum : vertical bar
    $line =~ s/\x7D/\\\|\[rcub  \]\\\|/g;  # ISOnum : right curly bracket
    $line =~ s/\x7E/\\\|\[tilde \]\\\|/g;  # ISOdia : tilde

    # ISO 8859-1
    $line =~ s/\xA0/\\\|\[nbsp  \]\\\|/g;  # ISOnum : NO-BREAK SPACE
    $line =~ s/\xA1/\\\|\[iexcl \]\\\|/g;  # ISOnum : INVERTED EXCLAMATION MARK
    $line =~ s/\xA2/\\\|\[cent  \]\\\|/g;  # ISOnum : CENT SIGN
    $line =~ s/\xA3/\\\|\[pound \]\\\|/g;  # ISOnum : POUND SIGN
    $line =~ s/\xA4/\\\|\[curren\]\\\|/g;  # ISOnum : CURRENCY SIGN
    $line =~ s/\xA5/\\\|\[yen   \]\\\|/g;  # ISOnum : YEN SIGN
    $line =~ s/\xA6/\\\|\[brvbar\]\\\|/g;  # ISOnum : BROKEN BAR
    $line =~ s/\xA7/\\\|\[sect  \]\\\|/g;  # ISOnum : SECTION SIGN
    $line =~ s/\xA8/\\\|\[die   \]\\\|/g;  # ISOdia : DIAERESIS
    $line =~ s/\xA9/\\\|\[copy  \]\\\|/g;  # ISOnum : COPYRIGHT SIGN
    $line =~ s/\xAA/\\\|\[ordf  \]\\\|/g;  # ISOnum : FEMININE ORDINAL INDICATOR
    $line =~ s/\xAB/\\\|\[laquo \]\\\|/g;  # ISOnum : LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
    $line =~ s/\xAC/\\\|\[not   \]\\\|/g;  # ISOnum : NOT SIGN
    $line =~ s/\xAD/\\\|\[shy   \]\\\|/g;  # ISOnum : SOFT HYPHEN
    $line =~ s/\xAE/\\\|\[reg   \]\\\|/g;  # ISOnum : REGISTERED SIGN
    $line =~ s/\xAF/\\\|\[macr  \]\\\|/g;  # ISOdia : OVERLINE (MACRON)
    $line =~ s/\xB0/\\\|\[deg   \]\\\|/g;  # ISOnum : DEGREE SIGN
    $line =~ s/\xB1/\\\|\[plusmn\]\\\|/g;  # ISOnum : PLUS-MINUS SIGN
    $line =~ s/\xB2/\\\|\[sup2  \]\\\|/g;  # ISOnum : SUPERSCRIPT TWO
    $line =~ s/\xB3/\\\|\[sup3  \]\\\|/g;  # ISOnum : SUPERSCRIPT THREE
    $line =~ s/\xB4/\\\|\[acute \]\\\|/g;  # ISOdia : ACUTE ACCENT
    $line =~ s/\xB5/\\\|\[micro \]\\\|/g;  # ISOnum : MICRO SIGN
    $line =~ s/\xB6/\\\|\[para  \]\\\|/g;  # ISOnum : PILCROW SIGN
    $line =~ s/\xB7/\\\|\[middot\]\\\|/g;  # ISOnum : MIDDLE DOT
    $line =~ s/\xB8/\\\|\[cedil \]\\\|/g;  # ISOdia : CEDILLA
    $line =~ s/\xB9/\\\|\[sup1  \]\\\|/g;  # ISOnum : SUPERSCRIPT ONE
    $line =~ s/\xBA/\\\|\[ordm  \]\\\|/g;  # ISOnum : MASCULINE ORDINAL INDICATOR
    $line =~ s/\xBB/\\\|\[raquo \]\\\|/g;  # ISOnum : RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
    $line =~ s/\xBC/\\\|\[frac14\]\\\|/g;  # ISOnum : VULGAR FRACTION ONE QUARTER
    $line =~ s/\xBD/\\\|\[frac12\]\\\|/g;  # ISOnum : VULGAR FRACTION ONE HALF
    $line =~ s/\xBE/\\\|\[frac34\]\\\|/g;  # ISOnum : VULGAR FRACTION THREE QUARTERS
    $line =~ s/\xBF/\\\|\[iquest\]\\\|/g;  # ISOnum : INVERTED QUESTION MARK
    $line =~ s/\xC0/\\\|\[Agrave\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH GRAVE
    $line =~ s/\xC1/\\\|\[Aacute\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH ACUTE
    $line =~ s/\xC2/\\\|\[Acirc \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH CIRCUMFLEX
    $line =~ s/\xC3/\\\|\[Atilde\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH TILDE
    $line =~ s/\xC4/\\\|\[Auml  \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH DIAERESIS
    $line =~ s/\xC5/\\\|\[Aring \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH RING ABOVE
    $line =~ s/\xC6/\\\|\[AElig \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER AE
    $line =~ s/\xC7/\\\|\[Ccedil\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER C WITH CEDILLA
    $line =~ s/\xC8/\\\|\[Egrave\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER E WITH GRAVE
    $line =~ s/\xC9/\\\|\[Eacute\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER E WITH ACUTE
    $line =~ s/\xCA/\\\|\[Ecirc \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER E WITH CIRCUMFLEX
    $line =~ s/\xCB/\\\|\[Euml  \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER E WITH DIAERESIS
    $line =~ s/\xCC/\\\|\[Igrave\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER I WITH GRAVE
    $line =~ s/\xCD/\\\|\[Iacute\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER I WITH ACUTE
    $line =~ s/\xCE/\\\|\[Icirc \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER I WITH CIRCUMFLEX
    $line =~ s/\xCF/\\\|\[Iuml  \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER I WITH DIAERESIS
    $line =~ s/\xD0/\\\|\[ETH   \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER ETH (Icelandic)
    $line =~ s/\xD1/\\\|\[Ntilde\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER N WITH TILDE
    $line =~ s/\xD2/\\\|\[Ograve\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH GRAVE
    $line =~ s/\xD3/\\\|\[Oacute\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH ACUTE
    $line =~ s/\xD4/\\\|\[Ocirc \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH CIRCUMFLEX
    $line =~ s/\xD5/\\\|\[Otilde\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH TILDE
    $line =~ s/\xD6/\\\|\[Ouml  \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH DIAERESIS
    $line =~ s/\xD7/\\\|\[times \]\\\|/g;  # ISOnum : MULTIPLICATION SIGN
    $line =~ s/\xD8/\\\|\[Oslash\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH STROKE
    $line =~ s/\xD9/\\\|\[Ugrave\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER U WITH GRAVE
    $line =~ s/\xDA/\\\|\[Uacute\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER U WITH ACUTE
    $line =~ s/\xDB/\\\|\[Ucirc \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER U WITH CIRCUMFLEX
    $line =~ s/\xDC/\\\|\[Uuml  \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER U WITH DIAERESIS
    $line =~ s/\xDD/\\\|\[Yacute\]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER Y WITH ACUTE
    $line =~ s/\xDE/\\\|\[THORN \]\\\|/g;  # ISOlat1: LATIN CAPITAL LETTER THORN (Icelandic)
    $line =~ s/\xDF/\\\|\[szlig \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER SHARP S (German)
    $line =~ s/\xE0/\\\|\[agrave\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER A WITH GRAVE
    $line =~ s/\xE1/\\\|\[aacute\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER A WITH ACUTE
    $line =~ s/\xE2/\\\|\[acirc \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER A WITH CIRCUMFLEX
    $line =~ s/\xE3/\\\|\[atilde\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER A WITH TILDE
    $line =~ s/\xE4/\\\|\[auml  \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER A WITH DIAERESIS
    $line =~ s/\xE5/\\\|\[aring \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER A WITH RING ABOVE
    $line =~ s/\xE6/\\\|\[aelig \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER AE
    $line =~ s/\xE7/\\\|\[ccedil\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER C WITH CEDILLA
    $line =~ s/\xE8/\\\|\[egrave\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER E WITH GRAVE
    $line =~ s/\xE9/\\\|\[eacute\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER E WITH ACUTE
    $line =~ s/\xEA/\\\|\[ecirc \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER E WITH CIRCUMFLEX
    $line =~ s/\xEB/\\\|\[euml  \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER E WITH DIAERESIS
    $line =~ s/\xEC/\\\|\[igrave\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER I WITH GRAVE
    $line =~ s/\xED/\\\|\[iacute\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER I WITH ACUTE
    $line =~ s/\xEE/\\\|\[icirc \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER I WITH CIRCUMFLEX
    $line =~ s/\xEF/\\\|\[iuml  \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER I WITH DIAERESIS
    $line =~ s/\xF0/\\\|\[eth   \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER ETH (Icelandic)
    $line =~ s/\xF1/\\\|\[ntilde\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER N WITH TILDE
    $line =~ s/\xF2/\\\|\[ograve\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER O WITH GRAVE
    $line =~ s/\xF3/\\\|\[oacute\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER O WITH ACUTE
    $line =~ s/\xF4/\\\|\[ocirc \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER O WITH CIRCUMFLEX
    $line =~ s/\xF5/\\\|\[otilde\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER O WITH TILDE
    $line =~ s/\xF6/\\\|\[ouml  \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER O WITH DIAERESIS
    $line =~ s/\xF7/\\\|\[divide\]\\\|/g;  # ISOnum : DIVISION SIGN
    $line =~ s/\xF8/\\\|\[oslash\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER O WITH STROKE
    $line =~ s/\xF9/\\\|\[ugrave\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER U WITH GRAVE
    $line =~ s/\xFA/\\\|\[uacute\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER U WITH ACUTE
    $line =~ s/\xFB/\\\|\[ucirc \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER U WITH CIRCUMFLEX
    $line =~ s/\xFC/\\\|\[uuml  \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER U WITH DIAERESIS
    $line =~ s/\xFD/\\\|\[yacute\]\\\|/g;  # ISOlat1: LATIN SMALL LETTER Y WITH ACUTE
    $line =~ s/\xFE/\\\|\[thorn \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER THORN (Icelandic)
    $line =~ s/\xFF/\\\|\[yuml  \]\\\|/g;  # ISOlat1: LATIN SMALL LETTER Y WITH DIAERESIS

    return ($line);
}

#-----------------------------------------------------------------------
# Convert an SP SDATA string into LaTeX back-end code.
# That is, for example, "\|[circ  ]\|" is converted into "\\^{}".
#
# &sp_sdata_text_to_sp_latex (TEXT)
#-----------------------------------------------------------------------
sub sp_sdata_text_to_sp_latex
{
    local ($line) = $_[0];

    # US-ASCII special characters for any typesetting system.
    $line =~ s/\\\|\[excl  \]\\\|/\x21/g;    # ISOnum : EXCLAMATION MARK
    #$line =~ s/\\\|\[quot  \]\\\|/\x22/g;    # ISOnum : QUOTATION MARK
    $line =~ s/\\\|\[quot  \]\\\|/\\\\\symbol\{34\}/g;    # ISOnum : QUOTATION MARK
    $line =~ s/\\\|\[num   \]\\\|/\\\\\#/g;  # ISOnum : NUMBER SIGN
    $line =~ s/\\\|\[dollar\]\\\|/\\\\\$/g;  # ISOnum : dollar sign
    $line =~ s/\\\|\[percnt\]\\\|/\\\\\%/g;  # ISOnum : percent sign
    $line =~ s/\\\|\[amp   \]\\\|/\\\\\&/g;  # ISOnum : ampersand
    $line =~ s/\\\|\[apos  \]\\\|/\x27/g;    # ISOnum : apostrophe
    $line =~ s/\\\|\[rsquo \]\\\|/\x27/g;    # ISOnum : single quotation mark right
    $line =~ s/\\\|\[lpar  \]\\\|/\x28/g;    # ISOnum : left parenthesis
    $line =~ s/\\\|\[rpar  \]\\\|/\x29/g;    # ISOnum : right parenthesis
    $line =~ s/\\\|\[ast   \]\\\|/\x2A/g;    # ISOnum : asterisk
    $line =~ s/\\\|\[plus  \]\\\|/\x2B/g;    # ISOnum : plus sign
    $line =~ s/\\\|\[comma \]\\\|/\x2C/g;    # ISOnum : comma
    $line =~ s/\\\|\[hyphen\]\\\|/\x2D/g;    # ISOnum : hyphen
    $line =~ s/\\\|\[period\]\\\|/\x2E/g;    # ISOnum : full stop, period
    $line =~ s/\\\|\[sol   \]\\\|/\x2F/g;    # ISOnum : solidus

    # numbers from 0 to 9 are not translated
    $line =~ s/\\\|\[colon \]\\\|/\x3A/g;    # ISOnum : colon
    $line =~ s/\\\|\[semi  \]\\\|/\x3B/g;    # ISOnum : semicolon
    $line =~ s/\\\|\[lt    \]\\\|/\x3C{}/g;  # ISOnum : less-than sign
    $line =~ s/\\\|\[equals\]\\\|/\x3D/g;    # ISOnum : equals sign
    $line =~ s/\\\|\[gt    \]\\\|/\x3E{}/g;  # ISOnum : greater-than sign
    $line =~ s/\\\|\[quest \]\\\|/\x3F/g;    # ISOnum : question mark
    $line =~ s/\\\|\[commat\]\\\|/\x40/g;    # ISOnum : commercial at
    # letters from A to Z are not translated
    $line =~ s/\\\|\[lsqb  \]\\\|/\x5B/g;                # ISOnum : left square bracket
    $line =~ s/\\\|\[bsol  \]\\\|/\\textbackslash\{\}/g; # ISOnum : reverse solidus - this is special!
    $line =~ s/\\\|\[rsqb  \]\\\|/\x5D/g;                # ISOnum : right square bracket
    $line =~ s/\\\|\[circ  \]\\\|/\\\\\symbol\{94\}/g;   # ISOnum : circumflex accent
    $line =~ s/\\\|\[lowbar\]\\\|/\\\\\_/g;              # ISOnum : low line
    $line =~ s/\\\|\[lsquo \]\\\|/\x60/g;                # ISOnum : single quotation mark, left
    # letters from a to z are not translated
    $line =~ s/\\\|\[lcub  \]\\\|/\$\\\\\{\$/g;  # ISOnum : left curly bracket
    $line =~ s/\\\|\[verbar\]\\\|/\x7C/g;        # ISOnum : vertical bar
    $line =~ s/\\\|\[rcub  \]\\\|/\$\\\\\}\$/g;  # ISOnum : right curly bracket
    $line =~ s/\\\|\[tilde \]\\\|/\\\\\symbol\{126\}/g;       # ISOdia : tilde

    # ISO 8859-1
    $line =~ s/\\\|\[nbsp  \]\\\|/\~/g;    # ISOnum : NO-BREAK SPACE
    $line =~ s/\\\|\[iexcl \]\\\|/\xA1/g;  # ISOnum : INVERTED EXCLAMATION MARK
    $line =~ s/\\\|\[cent  \]\\\|/\xA2/g;  # ISOnum : CENT SIGN
    $line =~ s/\\\|\[pound \]\\\|/\xA3/g;  # ISOnum : POUND SIGN
    $line =~ s/\\\|\[curren\]\\\|/\xA4/g;  # ISOnum : CURRENCY SIGN
    $line =~ s/\\\|\[yen   \]\\\|/\xA5/g;  # ISOnum : YEN SIGN
    $line =~ s/\\\|\[brvbar\]\\\|/\xA6/g;  # ISOnum : BROKEN BAR
    $line =~ s/\\\|\[sect  \]\\\|/\xA7/g;  # ISOnum : SECTION SIGN
    $line =~ s/\\\|\[die   \]\\\|/\xA8/g;  # ISOdia : DIAERESIS
    $line =~ s/\\\|\[copy  \]\\\|/\xA9/g;  # ISOnum : COPYRIGHT SIGN
    $line =~ s/\\\|\[ordf  \]\\\|/\xAA/g;  # ISOnum : FEMININE ORDINAL INDICATOR
    $line =~ s/\\\|\[laquo \]\\\|/\\\\guillemotleft\{\}/g;  # ISOnum : LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
    $line =~ s/\\\|\[not   \]\\\|/\$\xAC\$/g;  # ISOnum : NOT SIGN
    $line =~ s/\\\|\[shy   \]\\\|/\xAD/g;  # ISOnum : SOFT HYPHEN
    $line =~ s/\\\|\[reg   \]\\\|/\xAE/g;  # ISOnum : REGISTERED SIGN
    $line =~ s/\\\|\[macr  \]\\\|/\xAF/g;  # ISOdia : OVERLINE (MACRON)
    $line =~ s/\\\|\[deg   \]\\\|/\xB0/g;  # ISOnum : DEGREE SIGN
    $line =~ s/\\\|\[plusmn\]\\\|/\$\xB1\$/g;  # ISOnum : PLUS-MINUS SIGN
    $line =~ s/\\\|\[sup2  \]\\\|/{\\raise.75ex\\hbox{\\fontsize{0.6em}{1em}\\selectfont{2}}}/g;  # ISOnum : SUPERSCRIPT TWO
    $line =~ s/\\\|\[sup3  \]\\\|/{\\raise.75ex\\hbox{\\fontsize{0.6em}{1em}\\selectfont{3}}}/g;  # ISOnum : SUPERSCRIPT THREE
    $line =~ s/\\\|\[acute \]\\\|/\xB4/g;  # ISOdia : ACUTE ACCENT
    $line =~ s/\\\|\[micro \]\\\|/\$\\$/g;  # ISOnum : MICRO SIGN
    $line =~ s/\\\|\[para  \]\\\|/\xB6/g;  # ISOnum : PILCROW SIGN
    $line =~ s/\\\|\[middot\]\\\|/\\\\raise.5ex\\\\hbox{.}/g;  # ISOnum : MIDDLE DOT
    $line =~ s/\\\|\[cedil \]\\\|/\xB8/g;  # ISOdia : CEDILLA
    $line =~ s/\\\|\[sup1  \]\\\|/{\\raise.75ex\\hbox{\\fontsize{0.6em}{1em}\\selectfont{1}}}/g;  # ISOnum : SUPERSCRIPT ONE
    $line =~ s/\\\|\[ordm  \]\\\|/\xBA/g;  # ISOnum : MASCULINE ORDINAL INDICATOR
    $line =~ s/\\\|\[raquo \]\\\|/\\\\guillemotright\{\}/g;  # ISOnum : RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
    $line =~ s/\\\|\[frac14\]\\\|/\xBC/g;  # ISOnum : VULGAR FRACTION ONE QUARTER
    $line =~ s/\\\|\[half  \]\\\|/\xBD/g;  # ISOnum : VULGAR FRACTION ONE HALF
    $line =~ s/\\\|\[frac12\]\\\|/\xBD/g;  # ISOnum : VULGAR FRACTION ONE HALF
    $line =~ s/\\\|\[frac34\]\\\|/\xBE/g;  # ISOnum : VULGAR FRACTION THREE QUARTERS
    $line =~ s/\\\|\[iquest\]\\\|/\xBF/g;  # ISOnum : INVERTED QUESTION MARK
    $line =~ s/\\\|\[Agrave\]\\\|/\xC0/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH GRAVE
    $line =~ s/\\\|\[Aacute\]\\\|/\xC1/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH ACUTE
    $line =~ s/\\\|\[Acirc \]\\\|/\xC2/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH CIRCUMFLEX
    $line =~ s/\\\|\[Atilde\]\\\|/\xC3/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH TILDE
    $line =~ s/\\\|\[Auml  \]\\\|/\xC4/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH DIAERESIS
    $line =~ s/\\\|\[Aring \]\\\|/\xC5/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH RING ABOVE
    $line =~ s/\\\|\[AElig \]\\\|/\xC6/g;  # ISOlat1: LATIN CAPITAL LETTER AE
    $line =~ s/\\\|\[Ccedil\]\\\|/\xC7/g;  # ISOlat1: LATIN CAPITAL LETTER C WITH CEDILLA
    $line =~ s/\\\|\[Egrave\]\\\|/\xC8/g;  # ISOlat1: LATIN CAPITAL LETTER E WITH GRAVE
    $line =~ s/\\\|\[Eacute\]\\\|/\xC9/g;  # ISOlat1: LATIN CAPITAL LETTER E WITH ACUTE
    $line =~ s/\\\|\[Ecirc \]\\\|/\xCA/g;  # ISOlat1: LATIN CAPITAL LETTER E WITH CIRCUMFLEX
    $line =~ s/\\\|\[Euml  \]\\\|/\xCB/g;  # ISOlat1: LATIN CAPITAL LETTER E WITH DIAERESIS
    $line =~ s/\\\|\[Igrave\]\\\|/\xCC/g;  # ISOlat1: LATIN CAPITAL LETTER I WITH GRAVE
    $line =~ s/\\\|\[Iacute\]\\\|/\xCD/g;  # ISOlat1: LATIN CAPITAL LETTER I WITH ACUTE
    $line =~ s/\\\|\[Icirc \]\\\|/\xCE/g;  # ISOlat1: LATIN CAPITAL LETTER I WITH CIRCUMFLEX
    $line =~ s/\\\|\[Iuml  \]\\\|/\xCF/g;  # ISOlat1: LATIN CAPITAL LETTER I WITH DIAERESIS
    $line =~ s/\\\|\[ETH   \]\\\|/\xD0/g;  # ISOlat1: LATIN CAPITAL LETTER ETH (Icelandic)
    $line =~ s/\\\|\[Ntilde\]\\\|/\xD1/g;  # ISOlat1: LATIN CAPITAL LETTER N WITH TILDE
    $line =~ s/\\\|\[Ograve\]\\\|/\xD2/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH GRAVE
    $line =~ s/\\\|\[Oacute\]\\\|/\xD3/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH ACUTE
    $line =~ s/\\\|\[Ocirc \]\\\|/\xD4/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH CIRCUMFLEX
    $line =~ s/\\\|\[Otilde\]\\\|/\xD5/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH TILDE
    $line =~ s/\\\|\[Ouml  \]\\\|/\xD6/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH DIAERESIS
    $line =~ s/\\\|\[times \]\\\|/\$\xD7\$/g;  # ISOnum : MULTIPLICATION SIGN
    $line =~ s/\\\|\[Oslash\]\\\|/\xD8/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH STROKE
    $line =~ s/\\\|\[Ugrave\]\\\|/\xD9/g;  # ISOlat1: LATIN CAPITAL LETTER U WITH GRAVE
    $line =~ s/\\\|\[Uacute\]\\\|/\xDA/g;  # ISOlat1: LATIN CAPITAL LETTER U WITH ACUTE
    $line =~ s/\\\|\[Ucirc \]\\\|/\xDB/g;  # ISOlat1: LATIN CAPITAL LETTER U WITH CIRCUMFLEX
    $line =~ s/\\\|\[Uuml  \]\\\|/\xDC/g;  # ISOlat1: LATIN CAPITAL LETTER U WITH DIAERESIS
    $line =~ s/\\\|\[Yacute\]\\\|/\xDD/g;  # ISOlat1: LATIN CAPITAL LETTER Y WITH ACUTE
    $line =~ s/\\\|\[THORN \]\\\|/\xDE/g;  # ISOlat1: LATIN CAPITAL LETTER THORN (Icelandic)
    $line =~ s/\\\|\[szlig \]\\\|/\xDF/g;  # ISOlat1: LATIN SMALL LETTER SHARP S (German)
    $line =~ s/\\\|\[agrave\]\\\|/\xE0/g;  # ISOlat1: LATIN SMALL LETTER A WITH GRAVE
    $line =~ s/\\\|\[aacute\]\\\|/\xE1/g;  # ISOlat1: LATIN SMALL LETTER A WITH ACUTE
    $line =~ s/\\\|\[acirc \]\\\|/\xE2/g;  # ISOlat1: LATIN SMALL LETTER A WITH CIRCUMFLEX
    $line =~ s/\\\|\[atilde\]\\\|/\xE3/g;  # ISOlat1: LATIN SMALL LETTER A WITH TILDE
    $line =~ s/\\\|\[auml  \]\\\|/\xE4/g;  # ISOlat1: LATIN SMALL LETTER A WITH DIAERESIS
    $line =~ s/\\\|\[aring \]\\\|/\xE5/g;  # ISOlat1: LATIN SMALL LETTER A WITH RING ABOVE
    $line =~ s/\\\|\[aelig \]\\\|/\xE6/g;  # ISOlat1: LATIN SMALL LETTER AE
    $line =~ s/\\\|\[ccedil\]\\\|/\xE7/g;  # ISOlat1: LATIN SMALL LETTER C WITH CEDILLA
    $line =~ s/\\\|\[egrave\]\\\|/\xE8/g;  # ISOlat1: LATIN SMALL LETTER E WITH GRAVE
    $line =~ s/\\\|\[eacute\]\\\|/\xE9/g;  # ISOlat1: LATIN SMALL LETTER E WITH ACUTE
    $line =~ s/\\\|\[ecirc \]\\\|/\xEA/g;  # ISOlat1: LATIN SMALL LETTER E WITH CIRCUMFLEX
    $line =~ s/\\\|\[euml  \]\\\|/\xEB/g;  # ISOlat1: LATIN SMALL LETTER E WITH DIAERESIS
    $line =~ s/\\\|\[igrave\]\\\|/\xEC/g;  # ISOlat1: LATIN SMALL LETTER I WITH GRAVE
    $line =~ s/\\\|\[iacute\]\\\|/\xED/g;  # ISOlat1: LATIN SMALL LETTER I WITH ACUTE
    $line =~ s/\\\|\[icirc \]\\\|/\xEE/g;  # ISOlat1: LATIN SMALL LETTER I WITH CIRCUMFLEX
    $line =~ s/\\\|\[iuml  \]\\\|/\xEF/g;  # ISOlat1: LATIN SMALL LETTER I WITH DIAERESIS
    $line =~ s/\\\|\[eth   \]\\\|/\xF0/g;  # ISOlat1: LATIN SMALL LETTER ETH (Icelandic)
    $line =~ s/\\\|\[ntilde\]\\\|/\xF1/g;  # ISOlat1: LATIN SMALL LETTER N WITH TILDE
    $line =~ s/\\\|\[ograve\]\\\|/\xF2/g;  # ISOlat1: LATIN SMALL LETTER O WITH GRAVE
    $line =~ s/\\\|\[oacute\]\\\|/\xF3/g;  # ISOlat1: LATIN SMALL LETTER O WITH ACUTE
    $line =~ s/\\\|\[ocirc \]\\\|/\xF4/g;  # ISOlat1: LATIN SMALL LETTER O WITH CIRCUMFLEX
    $line =~ s/\\\|\[otilde\]\\\|/\xF5/g;  # ISOlat1: LATIN SMALL LETTER O WITH TILDE
    $line =~ s/\\\|\[ouml  \]\\\|/\xF6/g;  # ISOlat1: LATIN SMALL LETTER O WITH DIAERESIS
    $line =~ s/\\\|\[divide\]\\\|/\$\xF7\$/g;  # ISOnum : DIVISION SIGN
    $line =~ s/\\\|\[oslash\]\\\|/\xF8/g;  # ISOlat1: LATIN SMALL LETTER O WITH STROKE
    $line =~ s/\\\|\[ugrave\]\\\|/\xF9/g;  # ISOlat1: LATIN SMALL LETTER U WITH GRAVE
    $line =~ s/\\\|\[uacute\]\\\|/\xFA/g;  # ISOlat1: LATIN SMALL LETTER U WITH ACUTE
    $line =~ s/\\\|\[ucirc \]\\\|/\xFB/g;  # ISOlat1: LATIN SMALL LETTER U WITH CIRCUMFLEX
    $line =~ s/\\\|\[uuml  \]\\\|/\xFC/g;  # ISOlat1: LATIN SMALL LETTER U WITH DIAERESIS
    $line =~ s/\\\|\[yacute\]\\\|/\xFD/g;  # ISOlat1: LATIN SMALL LETTER Y WITH ACUTE
    $line =~ s/\\\|\[thorn \]\\\|/\xFE/g;  # ISOlat1: LATIN SMALL LETTER THORN (Icelandic)
    $line =~ s/\\\|\[yuml  \]\\\|/\\\\\"y/g;  # ISOlat1: LATIN SMALL LETTER Y WITH DIAERESIS

    # Extra
    $line =~ s/\\\|\[minus \]\\\|/\\\\AlmlMinus{}/g;  # ISOtech: MINUS SIGN
    $line =~ s/\\\|\[ge    \]\\\|/\$\\geq\$/g;        # ISOtech: GREATER THAN OR EQUAL
    $line =~ s/\\\|\[le    \]\\\|/\$\\leq\$/g;        # ISOtech: LESS THAN OR EQUAL

    # Extra ISO standard
    $line =~ s/\\\|\[euro  \]\\\|/\\euro{}/g;        # Euro sign

    return ($line);
}

#-----------------------------------------------------------------------
# Convert an SP SDATA string into HTML back-end code.
# That is, for example, "\|[circ  ]\|" is converted into "&circ;".
#
# Some standard entities doesn't work on HTML. See &apos; for example.
#
# &sp_sdata_text_to_sp_html (TEXT)
#-----------------------------------------------------------------------
sub sp_sdata_text_to_sp_html
{
    local ($line) = $_[0];

    # US-ASCII special characters for any typesetting system.
    $line =~ s/\\\|\[excl  \]\\\|/!/g;        # ISOnum : EXCLAMATION MARK
    $line =~ s/\\\|\[quot  \]\\\|/\"/g;       # ISOnum : QUOTATION MARK
    $line =~ s/\\\|\[num   \]\\\|/#/g;        # ISOnum : NUMBER SIGN
    $line =~ s/\\\|\[dollar\]\\\|/\$/g;       # ISOnum : dollar sign
    $line =~ s/\\\|\[percnt\]\\\|/\%/g;       # ISOnum : percent sign
    $line =~ s/\\\|\[amp   \]\\\|/&amp;/g;    # ISOnum : ampersand
    $line =~ s/\\\|\[apos  \]\\\|/'/g;        # ISOnum : apostrophe
    $line =~ s/\\\|\[rsquo \]\\\|/'/g;        # ISOnum : single quotation mark right
    $line =~ s/\\\|\[lpar  \]\\\|/\(/g;       # ISOnum : left parenthesis
    $line =~ s/\\\|\[rpar  \]\\\|/\)/g;       # ISOnum : right parenthesis
    $line =~ s/\\\|\[ast   \]\\\|/*/g;        # ISOnum : asterisk
    $line =~ s/\\\|\[plus  \]\\\|/+/g;        # ISOnum : plus sign
    $line =~ s/\\\|\[comma \]\\\|/,/g;        # ISOnum : comma
    $line =~ s/\\\|\[hyphen\]\\\|/-/g;        # ISOnum : hyphen
    $line =~ s/\\\|\[period\]\\\|/./g;        # ISOnum : full stop, period
    $line =~ s/\\\|\[sol   \]\\\|/\//g;       # ISOnum : solidus

    # numbers from 0 to 9 are not translated
    $line =~ s/\\\|\[colon \]\\\|/:/g;        # ISOnum : colon
    $line =~ s/\\\|\[semi  \]\\\|/;/g;        # ISOnum : semicolon
    $line =~ s/\\\|\[lt    \]\\\|/&lt;/g;     # ISOnum : less-than sign
    $line =~ s/\\\|\[equals\]\\\|/=/g;        # ISOnum : equals sign
    $line =~ s/\\\|\[gt    \]\\\|/&gt;/g;     # ISOnum : greater-than sign
    $line =~ s/\\\|\[quest \]\\\|/?/g;        # ISOnum : question mark
    $line =~ s/\\\|\[commat\]\\\|/\@/g;       # ISOnum : commercial at
    # letters from A to Z are not translated
    $line =~ s/\\\|\[lsqb  \]\\\|/[/g;        # ISOnum : left square bracket
    $line =~ s/\\\|\[bsol  \]\\\|/\x5C\x5C/g;    # ISOnum : reverse solidus - this is special!
    $line =~ s/\\\|\[rsqb  \]\\\|/]/g;        # ISOnum : right square bracket
    $line =~ s/\\\|\[circ  \]\\\|/^/g;        # ISOnum : circumflex accent
    $line =~ s/\\\|\[lowbar\]\\\|/_/g;        # ISOnum : low line
    $line =~ s/\\\|\[lsquo \]\\\|/\x60/g;        # ISOnum : single quotation mark, left
    # letters from a to z are not translated
    $line =~ s/\\\|\[lcub  \]\\\|/{/g;        # ISOnum : left curly bracket
    $line =~ s/\\\|\[verbar\]\\\|/|/g;        # ISOnum : vertical bar
    $line =~ s/\\\|\[rcub  \]\\\|/}/g;        # ISOnum : right curly bracket
    $line =~ s/\\\|\[tilde \]\\\|/~/g;        # ISOdia : tilde

    # ISO 8859-1
    $line =~ s/\\\|\[nbsp  \]\\\|/&nbsp;/g;   # ISOnum : NO-BREAK SPACE
    $line =~ s/\\\|\[iexcl \]\\\|/&iexcl;/g;  # ISOnum : INVERTED EXCLAMATION MARK
    $line =~ s/\\\|\[cent  \]\\\|/&cent;/g;   # ISOnum : CENT SIGN
    $line =~ s/\\\|\[pound \]\\\|/&pound;/g;  # ISOnum : POUND SIGN
    $line =~ s/\\\|\[curren\]\\\|/&curren;/g; # ISOnum : CURRENCY SIGN
    $line =~ s/\\\|\[yen   \]\\\|/&yen;/g;    # ISOnum : YEN SIGN
    $line =~ s/\\\|\[brvbar\]\\\|/&brvbar;/g; # ISOnum : BROKEN BAR
    $line =~ s/\\\|\[sect  \]\\\|/&sect;/g;   # ISOnum : SECTION SIGN
    $line =~ s/\\\|\[die   \]\\\|/&die;/g;    # ISOdia : DIAERESIS
    $line =~ s/\\\|\[copy  \]\\\|/&copy;/g;   # ISOnum : COPYRIGHT SIGN
    $line =~ s/\\\|\[ordf  \]\\\|/&ordf;/g;   # ISOnum : FEMININE ORDINAL INDICATOR
    $line =~ s/\\\|\[laquo \]\\\|/&laquo;/g;  # ISOnum : LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
    $line =~ s/\\\|\[not   \]\\\|/&not;/g;    # ISOnum : NOT SIGN
    $line =~ s/\\\|\[shy   \]\\\|/&shy;/g;    # ISOnum : SOFT HYPHEN
    $line =~ s/\\\|\[reg   \]\\\|/&reg;/g;    # ISOnum : REGISTERED SIGN
    $line =~ s/\\\|\[macr  \]\\\|/&macr;/g;   # ISOdia : OVERLINE (MACRON)
    $line =~ s/\\\|\[deg   \]\\\|/&deg;/g;    # ISOnum : DEGREE SIGN
    $line =~ s/\\\|\[plusmn\]\\\|/&plusmn;/g; # ISOnum : PLUS-MINUS SIGN
    $line =~ s/\\\|\[sup2  \]\\\|/&sup2;/g;   # ISOnum : SUPERSCRIPT TWO
    $line =~ s/\\\|\[sup3  \]\\\|/&sup3;/g;   # ISOnum : SUPERSCRIPT THREE
    $line =~ s/\\\|\[acute \]\\\|/&acute;/g;  # ISOdia : ACUTE ACCENT
    $line =~ s/\\\|\[micro \]\\\|/&micro;/g;  # ISOnum : MICRO SIGN
    $line =~ s/\\\|\[para  \]\\\|/&para;/g;   # ISOnum : PILCROW SIGN
    $line =~ s/\\\|\[middot\]\\\|/&middot;/g; # ISOnum : MIDDLE DOT
    $line =~ s/\\\|\[cedil \]\\\|/&cedil;/g;  # ISOdia : CEDILLA
    $line =~ s/\\\|\[sup1  \]\\\|/&sup1;/g;   # ISOnum : SUPERSCRIPT ONE
    $line =~ s/\\\|\[ordm  \]\\\|/&ordm;/g;   # ISOnum : MASCULINE ORDINAL INDICATOR
    $line =~ s/\\\|\[raquo \]\\\|/&raquo;/g;  # ISOnum : RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
    $line =~ s/\\\|\[frac14\]\\\|/&frac14;/g; # ISOnum : VULGAR FRACTION ONE QUARTER
    $line =~ s/\\\|\[frac12\]\\\|/&frac12;/g; # ISOnum : VULGAR FRACTION ONE HALF
    $line =~ s/\\\|\[frac34\]\\\|/&frac34;/g; # ISOnum : VULGAR FRACTION THREE QUARTERS
    $line =~ s/\\\|\[iquest\]\\\|/&iquest;/g; # ISOnum : INVERTED QUESTION MARK
    $line =~ s/\\\|\[Agrave\]\\\|/&Agrave;/g; # ISOlat1: LATIN CAPITAL LETTER A WITH GRAVE
    $line =~ s/\\\|\[Aacute\]\\\|/&Aacute;/g; # ISOlat1: LATIN CAPITAL LETTER A WITH ACUTE
    $line =~ s/\\\|\[Acirc \]\\\|/&Acirc;/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH CIRCUMFLEX
    $line =~ s/\\\|\[Atilde\]\\\|/&Atilde;/g; # ISOlat1: LATIN CAPITAL LETTER A WITH TILDE
    $line =~ s/\\\|\[Auml  \]\\\|/&Auml;/g;   # ISOlat1: LATIN CAPITAL LETTER A WITH DIAERESIS
    $line =~ s/\\\|\[Aring \]\\\|/&Aring;/g;  # ISOlat1: LATIN CAPITAL LETTER A WITH RING ABOVE
    $line =~ s/\\\|\[AElig \]\\\|/&AElig;/g;  # ISOlat1: LATIN CAPITAL LETTER AE
    $line =~ s/\\\|\[Ccedil\]\\\|/&Ccedil;/g; # ISOlat1: LATIN CAPITAL LETTER C WITH CEDILLA
    $line =~ s/\\\|\[Egrave\]\\\|/&Egrave;/g; # ISOlat1: LATIN CAPITAL LETTER E WITH GRAVE
    $line =~ s/\\\|\[Eacute\]\\\|/&Eacute;/g; # ISOlat1: LATIN CAPITAL LETTER E WITH ACUTE
    $line =~ s/\\\|\[Ecirc \]\\\|/&Ecirc;/g;  # ISOlat1: LATIN CAPITAL LETTER E WITH CIRCUMFLEX
    $line =~ s/\\\|\[Euml  \]\\\|/&Euml;/g;   # ISOlat1: LATIN CAPITAL LETTER E WITH DIAERESIS
    $line =~ s/\\\|\[Igrave\]\\\|/&Igrave;/g; # ISOlat1: LATIN CAPITAL LETTER I WITH GRAVE
    $line =~ s/\\\|\[Iacute\]\\\|/&Iacute;/g; # ISOlat1: LATIN CAPITAL LETTER I WITH ACUTE
    $line =~ s/\\\|\[Icirc \]\\\|/&Icirc;/g;  # ISOlat1: LATIN CAPITAL LETTER I WITH CIRCUMFLEX
    $line =~ s/\\\|\[Iuml  \]\\\|/&Iuml;/g;   # ISOlat1: LATIN CAPITAL LETTER I WITH DIAERESIS
    $line =~ s/\\\|\[ETH   \]\\\|/&ETH;/g;    # ISOlat1: LATIN CAPITAL LETTER ETH (Icelandic)
    $line =~ s/\\\|\[Ntilde\]\\\|/&Ntilde;/g; # ISOlat1: LATIN CAPITAL LETTER N WITH TILDE
    $line =~ s/\\\|\[Ograve\]\\\|/&Ograve;/g; # ISOlat1: LATIN CAPITAL LETTER O WITH GRAVE
    $line =~ s/\\\|\[Oacute\]\\\|/&Oacute;/g; # ISOlat1: LATIN CAPITAL LETTER O WITH ACUTE
    $line =~ s/\\\|\[Ocirc \]\\\|/&Ocirc;/g;  # ISOlat1: LATIN CAPITAL LETTER O WITH CIRCUMFLEX
    $line =~ s/\\\|\[Otilde\]\\\|/&Otilde;/g; # ISOlat1: LATIN CAPITAL LETTER O WITH TILDE
    $line =~ s/\\\|\[Ouml  \]\\\|/&Ouml;/g;   # ISOlat1: LATIN CAPITAL LETTER O WITH DIAERESIS
    $line =~ s/\\\|\[times \]\\\|/&times;/g;  # ISOnum : MULTIPLICATION SIGN
    $line =~ s/\\\|\[Oslash\]\\\|/&Oslash;/g; # ISOlat1: LATIN CAPITAL LETTER O WITH STROKE
    $line =~ s/\\\|\[Ugrave\]\\\|/&Ugrave;/g; # ISOlat1: LATIN CAPITAL LETTER U WITH GRAVE
    $line =~ s/\\\|\[Uacute\]\\\|/&Uacute;/g; # ISOlat1: LATIN CAPITAL LETTER U WITH ACUTE
    $line =~ s/\\\|\[Ucirc \]\\\|/&Ucirc;/g;  # ISOlat1: LATIN CAPITAL LETTER U WITH CIRCUMFLEX
    $line =~ s/\\\|\[Uuml  \]\\\|/&Uuml;/g;   # ISOlat1: LATIN CAPITAL LETTER U WITH DIAERESIS
    $line =~ s/\\\|\[Yacute\]\\\|/&Yacute;/g; # ISOlat1: LATIN CAPITAL LETTER Y WITH ACUTE
    $line =~ s/\\\|\[THORN \]\\\|/&THORN;/g;  # ISOlat1: LATIN CAPITAL LETTER THORN (Icelandic)
    $line =~ s/\\\|\[szlig \]\\\|/&szlig;/g;  # ISOlat1: LATIN SMALL LETTER SHARP S (German)
    $line =~ s/\\\|\[agrave\]\\\|/&agrave;/g; # ISOlat1: LATIN SMALL LETTER A WITH GRAVE
    $line =~ s/\\\|\[aacute\]\\\|/&aacute;/g; # ISOlat1: LATIN SMALL LETTER A WITH ACUTE
    $line =~ s/\\\|\[acirc \]\\\|/&acirc;/g;  # ISOlat1: LATIN SMALL LETTER A WITH CIRCUMFLEX
    $line =~ s/\\\|\[atilde\]\\\|/&atilde;/g; # ISOlat1: LATIN SMALL LETTER A WITH TILDE
    $line =~ s/\\\|\[auml  \]\\\|/&auml;/g;   # ISOlat1: LATIN SMALL LETTER A WITH DIAERESIS
    $line =~ s/\\\|\[aring \]\\\|/&aring;/g;  # ISOlat1: LATIN SMALL LETTER A WITH RING ABOVE
    $line =~ s/\\\|\[aelig \]\\\|/&aelig;/g;  # ISOlat1: LATIN SMALL LETTER AE
    $line =~ s/\\\|\[ccedil\]\\\|/&ccedil;/g; # ISOlat1: LATIN SMALL LETTER C WITH CEDILLA
    $line =~ s/\\\|\[egrave\]\\\|/&egrave;/g; # ISOlat1: LATIN SMALL LETTER E WITH GRAVE
    $line =~ s/\\\|\[eacute\]\\\|/&eacute;/g; # ISOlat1: LATIN SMALL LETTER E WITH ACUTE
    $line =~ s/\\\|\[ecirc \]\\\|/&ecirc;/g;  # ISOlat1: LATIN SMALL LETTER E WITH CIRCUMFLEX
    $line =~ s/\\\|\[euml  \]\\\|/&euml;/g;   # ISOlat1: LATIN SMALL LETTER E WITH DIAERESIS
    $line =~ s/\\\|\[igrave\]\\\|/&igrave;/g; # ISOlat1: LATIN SMALL LETTER I WITH GRAVE
    $line =~ s/\\\|\[iacute\]\\\|/&iacute;/g; # ISOlat1: LATIN SMALL LETTER I WITH ACUTE
    $line =~ s/\\\|\[icirc \]\\\|/&icirc;/g;  # ISOlat1: LATIN SMALL LETTER I WITH CIRCUMFLEX
    $line =~ s/\\\|\[iuml  \]\\\|/&iuml;/g;   # ISOlat1: LATIN SMALL LETTER I WITH DIAERESIS
    $line =~ s/\\\|\[eth   \]\\\|/&eth;/g;    # ISOlat1: LATIN SMALL LETTER ETH (Icelandic)
    $line =~ s/\\\|\[ntilde\]\\\|/&ntilde;/g; # ISOlat1: LATIN SMALL LETTER N WITH TILDE
    $line =~ s/\\\|\[ograve\]\\\|/&ograve;/g; # ISOlat1: LATIN SMALL LETTER O WITH GRAVE
    $line =~ s/\\\|\[oacute\]\\\|/&oacute;/g; # ISOlat1: LATIN SMALL LETTER O WITH ACUTE
    $line =~ s/\\\|\[ocirc \]\\\|/&ocirc;/g;  # ISOlat1: LATIN SMALL LETTER O WITH CIRCUMFLEX
    $line =~ s/\\\|\[otilde\]\\\|/&otilde;/g; # ISOlat1: LATIN SMALL LETTER O WITH TILDE
    $line =~ s/\\\|\[ouml  \]\\\|/&ouml;/g;   # ISOlat1: LATIN SMALL LETTER O WITH DIAERESIS
    $line =~ s/\\\|\[divide\]\\\|/&divide;/g; # ISOnum : DIVISION SIGN
    $line =~ s/\\\|\[oslash\]\\\|/&oslash;/g; # ISOlat1: LATIN SMALL LETTER O WITH STROKE
    $line =~ s/\\\|\[ugrave\]\\\|/&ugrave;/g; # ISOlat1: LATIN SMALL LETTER U WITH GRAVE
    $line =~ s/\\\|\[uacute\]\\\|/&uacute;/g; # ISOlat1: LATIN SMALL LETTER U WITH ACUTE
    $line =~ s/\\\|\[ucirc \]\\\|/&ucirc;/g;  # ISOlat1: LATIN SMALL LETTER U WITH CIRCUMFLEX
    $line =~ s/\\\|\[uuml  \]\\\|/&uuml;/g;   # ISOlat1: LATIN SMALL LETTER U WITH DIAERESIS
    $line =~ s/\\\|\[yacute\]\\\|/&yacute;/g; # ISOlat1: LATIN SMALL LETTER Y WITH ACUTE
    $line =~ s/\\\|\[thorn \]\\\|/&thorn;/g;  # ISOlat1: LATIN SMALL LETTER THORN (Icelandic)
    $line =~ s/\\\|\[yuml  \]\\\|/&yuml;/g;   # ISOlat1: LATIN SMALL LETTER Y WITH DIAERESIS

    # Extra
    $line =~ s/\\\|\[minus \]\\\|/-/g;        # ISOtech: MINUS SIGN
    $line =~ s/\\\|\[ge    \]\\\|/&ge;/g;     # ISOtech: GREATER THAN OR EQUAL
    $line =~ s/\\\|\[le    \]\\\|/&le;/g;     # ISOtech: LESS THAN OR EQUAL

    # Extra ISO standard
    $line =~ s/\\\|\[euro  \]\\\|/&#8364;/g;  # Euro sign

    return ($line);
}

#-----------------------------------------------------------------------
# Jump a %block; element that starts on its own line, and that
# terminates on a line by itself.
# This %block; element is meant in the way that it cannot contain
# itself recusively.
#
sub jump_block
{
    local ($input_stream)   = $_[0];
    local ($output_stream)  = $_[1];
    local ($line)           = $_[2];
    local ($termination_re) = $_[3];

    # Try to jump the block.
    while ($line !~ m/$termination_re/i)
      {
	# Print the line and read the next.
	print $output_stream "$line";
	$line = <$input_stream>;
      }
    # Print the last line.
    print $output_stream "$line";
}    

#-----------------------------------------------------------------------
# Diagnostic output; it depends on the following global variables:
#   $verbose
#   $root_file_name
#
sub diag_output
{
    local ($string)    = $_[0];

    # Append to the diagnostic file.
    open (DIAG, ">> $root_file_name.diag");
    
    if ($verbose)
      {
        print STDOUT ($string);
      }
    # In any case, print it on the DIAG file
    print DIAG ($string);

    # Close the file.
    close (DIAG);

}

#-----------------------------------------------------------------------
# Fourth step filter.
#
# Transform SP output for some special character, depending on the
# back-end system limitations.
#
# &step_4_filter (INPUT_FILE, TYPESETTING,
#                 ORIGINAL_FILE_NAME) --> OUTPUT_FILE
#
sub step_4_filter
{
    local ($input_file) = $_[0];
    local ($typesetting) = $_[1];
    local ($original_file_name) = $_[2];
    local ($output_file) = &temporary_file ($temporary_file_name_prefix);
    chomp ($output_file);
    local ($line) = "";

    local ($line_prefix) = "";
    local ($line_content) = "";

    # Tell what we are doing.
    &diag_output (sprintf (gettext ("%s:%s:%s: step 4: "),
                           $program_executable, $original_file_name, $input_file));
    &diag_output (sprintf (gettext ("post-SP re-elaborations\n")));

    # Here there is no need to use references for file handler names,
    # but this way we use uniform code.
    # See &step_1_filter() for explanation.
    local ($input_stream) = "$input_file";
    local ($output_stream) = "$output_file";


    #-------------------------------------------------------------------
    # Jump_sp_element.
    #
    # &jump_sp_element (INPUT_STREAM, OUTPUT_STREAM, LINE,
    #                   CONCLUSION_STRING)
    #
    sub jump_sp_element
    {
        local ($input_stream) = $_[0];
        local ($output_stream) = $_[1];
        local ($line) = $_[2];
        local ($conclusion) = $_[3];

        local ($line_prefix) = "";
        local ($line_content) = "";

        # Try to jump.
        while ($line !~ m/^$conclusion$/i)
          {
            # Tranfer the line, read the next and increase the counter.
            print $output_stream ("$line");
            $line = <$input_stream>;
          }

        # Last line (the one with the end string) must be transfered.
        print $output_stream ("$line");

    } # jump_sp_element

    #-------------------------------------------------------------------
    # Start of &step_4_filter()
    #-------------------------------------------------------------------

    # Open input and output files.
    open ($input_stream, "< $input_file");
    open ($output_stream, "> $output_file");

    # Do what is required
    while ($line = <$input_stream>)
      {
        # Literal text is jumped.
        if ($line =~ m/^\(NUM$/i)
          {
            &jump_sp_element ($input_stream, $output_stream, $line,
                              "\\)NUM\$");
          }
        elsif ($line =~ m/^\(TEX$/i)
          {
            &jump_sp_element ($input_stream, $output_stream, $line,
                              "\\)TEX\$");
          }
        elsif ($line =~ m/^\(HTML$/i)
          {
            &jump_sp_element ($input_stream, $output_stream, $line,
                              "\\)HTML\$");
          }
        elsif ($line =~ m/^\(EPSIMG$/i)
          {
            &jump_sp_element ($input_stream, $output_stream, $line,
                              "\\)EPSIMG\$");
          }
        elsif ($line =~ m/^\(EPSIMAGE$/i)
          {
            &jump_sp_element ($input_stream, $output_stream, $line,
                              "\\)EPSIMAGE\$");
          }
        elsif ($line =~ m/^\(TEXIMG$/i)
          {
            &jump_sp_element ($input_stream, $output_stream, $line,
                              "\\)TEXIMG\$");
          }
        elsif ($line =~ m/^\(TEXIMAGE$/i)
          {
            &jump_sp_element ($input_stream, $output_stream, $line,
                              "\\)TEXIMAGE\$");
          }
        elsif ($line =~ m/^\(EMBIMG$/i)
          {
            &jump_sp_element ($input_stream, $output_stream, $line,
                              "\\)EMBIMG\$");
          }
        elsif ($line =~ m/^\(EMBIMAGE$/i)
          {
            &jump_sp_element ($input_stream, $output_stream, $line,
                              "\\)EMBIMAGE\$");
          }
	elsif ($line =~ m/^A.* CDATA/i)
          {
            # All attribute are verbatim.
    	    # The line is transfered.
    	    print $output_stream ($line);
          }
        # Text lines that start with a "-" must be re-elaborated.
        elsif ($line =~ m/^(-)(.*)$/)
          {
            # The line contains text and must be re-elaborated for SGML
            # macros.
            
            $line_prefix = $1;
            $line_content = $2;

            #-----------------------------------------------------------
            # Start converting special character into SDATA entities.
            #-----------------------------------------------------------

            $line_content = &sp_text_to_sdata ($line_content);

            #-----------------------------------------------------------
            # Some special symbols for this transformation
            # are declared as SDATA entities, with the
            # form "[name  ]".
            # When SP insert these SDATA entities, they became
            # "\|[name  ]\|".
            # This enshure that the substitution mechanism
            # doesn't do mistakes.
            # Some special characters must be transformed
            # before into "\|[name  ]\|", then they are
            # translated back into the right way.
            # This way, characters that require a special
            # form when use with some programs, may be
            # inserted literally, as long that this
            # can be done for SGML, and also as SGML entities.
            #-----------------------------------------------------------

            if ($typesetting eq "LATEX")
              {
                $line_content = &sp_sdata_text_to_sp_latex ($line_content);
              }
            elsif ($typesetting eq "HTML")
              {
                $line_content = &sp_sdata_text_to_sp_html ($line_content);
              }
              
            # Rejoin the line.  
            $line = $line_prefix . $line_content . "\n";
    	    # The line is transfered.
    	    print $output_stream ($line);
          }
	else
	  {
    	    # The line is transfered.
    	    print $output_stream ($line);
	  }
      }

    # Close files.
    close ($input_stream);
    close ($output_stream);

    # Return the temporary file name.
    return ($output_file);

} # step_4_filter

#======================================================================
# Start of SP to SP translation.
#----------------------------------------------------------------------

local ($step_3_temp_file)   = $ARGV[0];
local ($typesetting)        = $ARGV[1];
local ($source_file_name)   = $ARGV[2];
local ($step_4_temp_file)   = "";

# Define temporary file name prefix.
$temporary_file_name_prefix = $program_executable . "_" . $root_file_name;

# Now we have to modify the SP output.
$step_4_temp_file = &step_4_filter ($step_3_temp_file,
                                        $typesetting, $source_file_name);

system ("mv -f $step_4_temp_file $step_3_temp_file-step4");

1;

#======================================================================

