#!/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 OPTION... SGML_SOURCE
#
# Front-end for the Alml system.
#=======================================================================

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

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

# Program version.
$VERSION = "2002.03.04";

# Configuration files.
$CATALOG         = "/usr/share/alml/alml.cat";
$HTML_CATALOG    = "/usr/share/alml/html/html.cat";
$HTML401_CATALOG = "/usr/share/alml/html/html401.cat";
$HTML320_CATALOG = "/usr/share/alml/html/html320.cat";
$XML_CATALOG     = "/usr/share/alml/xml/xml.cat";

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

# Program name.
$program_canonical_name = "Alml";

# 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.
#=======================================================================

#-----------------------------------------------------------------------
# Show the right syntax for the use of this program.
#
# &help_syntax ()
#
sub help_syntax
{
    printf STDOUT (gettext ("\
Usage: %s OPTIONS... SGML_SOURCE\
       %s --help\
       %s --version\
\
Front-end for the Alml system.\
\
Options:\
--help        display this help and exit.\
--version     display version information and exit.\
--paper=PAPER_NAME\
              the paper size name (a4 and letter).\
--paper-orientation=[normal|inverted]\
              paper orientation.\
--draft       draft typesetting if available.\
--compact     compact typesetting if available.\
--halfcompact halfcompact typesetting if available.\
--long        long pages, two columns, portrait, only for\
                PostScript typesetting (it uses PSUtils for\
                PostScript readaptation).\
--extralong   very long pages, three columns, portrait, only for\
                PostScript typesetting (it uses PSUtils for\
                PostScript readaptation).\
--large       large pages, three columns, landscape, only for\
                PostScript typesetting (it uses PSUtils for\
                PostScript readaptation).\
--extralarge  large pages, four columns, landscape, only for\
                PostScript typesetting (it uses PSUtils for\
                PostScript readaptation).\
--thin        long pages, one column, portrait, only for\
                PostScript typesetting (it uses PSUtils for\
                PostScript readaptation).\
--clean       remove stale files associated with the source name.\
--verbose     show more messages.\
--derivation=DERIVATION\
              define the derivation name.\
--sgml-include=PARAMETER_ENTITY\
              assign \"INCLUDE\" to an SGML parameter entity.\
--replace-char=SOURCE,DEST\
              define a replacement for the SOURCE character with the\
                DEST string.\
--page-numbering={plain|default}\
              define the page numbering way: plain request for\
                a plain numbering from 1 to n-th absolute page;\
                default distinguish the numbering.\
--sgml-syntax, --sgml-check\
              check SGML syntax and report errors.\
--sp          SP output for debugging purpose.\
--tex, --latex\
              LaTeX output for debugging purpose.\
--dvi         generate a DVI output.\
--ps, --postscript\
              generate a PostScript output.\
--pdf         generate a PDF output.\
--html        generate standard HTML output.\
--html-text   generate single HTML output for text browsers.\
--html-check, --html401-check\
              check HTML 4.01 syntax and report errors.\
--html320-check\
              check HTML 3.2 syntax and report errors.\
--xml-check\
              check XML syntax and report errors (the argument\
            is an XML file with known DTD).\
\
Arguments:\
SGML_SOURCE   the SGML input file.\
\
Report bugs to <daniele\@swlibero.org>"),
        $program_executable, $program_executable, $program_executable);
}

#-----------------------------------------------------------------------
# Show version information.
#
# &version_info ()
#-----------------------------------------------------------------------
sub version_info
{
    printf STDOUT (gettext ("\
%s %s\
\
Copyright (c) 2000-2001 Daniele giacomini <daniele\@swlibero.org>\
This is free software; see the source for copying conditions.\
There is NO warranty; not even for MERCHANTABILITY or FITNESS\
FOR A PARTICULAR PURPOSE."),
	$program_canonical_name,
	$VERSION);
}

#-----------------------------------------------------------------------
# Scan a PostScript file and substitute the page definition.
#
# &ps_new_bounding_box ( <file>, "%%BoundingBox 0 0 n m" )
#
sub ps_new_bounding_box
{
    local( $file_name ) = $_[0];
    local( $new_bounding_box ) = $_[1];
    local ($original_file_name) = $file_name . "~";
    local ($previous_line) = "";

    system ("mv $file_name $original_file_name");
    open (ORIGINAL, "< $original_file_name");
    open (NEW, "> $file_name");

    while ($line = <ORIGINAL>)
      {
	if ($line =~ m/^\%\%BoundingBox:\s/
	    || $line =~ m/^\%\%DocumentPaperSizes:\s/)
	  {
	    $previous_line = $line;
	    chomp ($previous_line);
	    $line = "$new_bounding_box\n";
	    &diag_output (sprintf (gettext ("%s:%s: $previous_line --> $line"),
                                   $program_executable, $file_name));
	  }
	print NEW ($line);
      }

    close (NEW);
    close (ORIGINAL);
}


#-----------------------------------------------------------------------
# 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");
}

#-----------------------------------------------------------------------
# Determinate the file name without extension.
#
# &root_name (FILE_NAME, EXTENSION)
#
sub root_name
{
    local( $file_name ) = $_[0];
    local( $extension_name ) = $_[1];
    local( $root_name ) = "";
    
    $file_name =~ m/^(.*)$extension_name$/;
    $root_name = $1;
    if ($root_name eq "")
      {
        # The extension is not the same.
        $root_name = $file_name;
      }
    return ("$root_name");
} # &root_name

#-----------------------------------------------------------------------
# Translate a positive integer into an alphabet sequence:
# from A to CZ.
#
# &integer_to_alphabet (INTEGER)
#
sub integer_to_alphabet
{
    local ($n) = $_[0];

    #-------------------------------------------------------------------
    # Generate an alphabet digit.
    # 1 -> A, 2 -> B,... 26 -> Z
    #
    # &aphabet_digit (1-26)
    #
    sub alphabet_digit
    {
        local ($digit) = $_[0];

        if ($digit == 0)
          {
            return ("");
          }
        elsif ($digit == 1){
            return ("A");
          }
        elsif ($digit == 2)
          {
            return ("B");
          }
        elsif ($digit == 3)
          {
            return ("C");
          }
        elsif ($digit == 4)
          {
            return ("D");
          }
        elsif ($digit == 5)
          {
            return ("E");
          }
        elsif ($digit == 6)
          {
            return ("F");
          }
        elsif ($digit == 7)
          {
            return ("G");
          }
        elsif ($digit == 8)
          {
            return ("H");
          }
        elsif ($digit == 9)
          {
            return ("I");
          }
        elsif ($digit == 10)
          {
            return ("J");
          }
        elsif ($digit == 11)
          {
            return ("K");
          }
        elsif ($digit == 12)
          {
            return ("L");
          }
        elsif ($digit == 13)
          {
            return ("M");
          }
        elsif ($digit == 14)
          {
            return ("N");
          }
        elsif ($digit == 15)
          {
            return ("O");
          }
        elsif ($digit == 16)
          {
            return ("P");
          }
        elsif ($digit == 17)
          {
            return ("Q");
          }
        elsif ($digit == 18)
          {
            return ("R");
          }
        elsif ($digit == 19)
          {
            return ("S");
          }
        elsif ($digit == 20)
          {
            return ("T");
          }
        elsif ($digit == 21)
          {
            return ("U");
          }
        elsif ($digit == 22)
          {
            return ("V");
          }
        elsif ($digit == 23)
          {
            return ("W");
          }
        elsif ($digit == 24)
          {
            return ("X");
          }
        elsif ($digit == 25)
          {
            return ("Y");
          }
        elsif ($digit == 26)
          {
            return ("Z");
          }
    }

    # Analyse the number.
    if ($n <= 0)
      {
        # We cannot translate zero or negative numbers.
        $return = "##<A##";
      }
    elsif ($n <= 26)
      {
        # We have only one letter.
        $return = &alphabet_digit($n);
      }
    elsif ($n <= 52)
      {
        # We have two letters: Ax.
        $n = $n - 26;
        $return = "A" . &alphabet_digit($n);
      }
    elsif ($n <= 78)
      {
        # We have two letters: Bx.
        $n = $n - 52;
        $return = "B" . &alphabet_digit($n);

      }
    elsif ($n <= 104)
      {
        # We have two letters: Cx.
        $n = $n - 78;
        $return = "C" . &alphabet_digit($n);
      }
    else
      {
        # The number is too big.
        $return = "##>CZ##";
      }
} # &integer_to_alphabet

#-----------------------------------------------------------------------
# Translate a positive integer into a roman string.
#
# &integer_to_roman (INTEGER)
#
sub integer_to_roman
{
    local ( $n ) = $_[0];
    local ( $digit_1 ) = 0;
    local ( $digit_2 ) = 0;
    local ( $digit_3 ) = 0;
    local ( $digit_4 ) = 0;

    #-------------------------------------------------------------------
    # First digit into roman: 1-9
    #
    sub digit_1_to_roman
    {
        local ( $digit ) = $_[0];

        if ($digit == 0)
          {
            return ("");
          }
        elsif ($digit == 1)
          {
            return ("I");
          }
        elsif ($digit == 2)
          {
            return ("II");
          }
        elsif ($digit == 3)
          {
            return ("III");
          }
        elsif ($digit == 4)
          {
            return ("IV");
          }
        elsif ($digit == 5)
          {
            return ("V");
          }
        elsif ($digit == 6)
          {
            return ("VI");
          }
        elsif ($digit == 7)
          {
            return ("VII");
          }
        elsif ($digit == 8)
          {
            return ("VIII");
          }
        elsif ($digit == 9)
          {
            return ("IX");
          }
    }

    #-------------------------------------------------------------------
    # Second digit into roman: 10-90
    #
    sub digit_2_to_roman
    {
        local ($digit) = $_[0];

        if ($digit == 0)
          {
            return ("");
          }
        elsif ($digit == 1)
          {
            return ("X");
          }
        elsif ($digit == 2)
          {
            return ("XX");
          }
        elsif ($digit == 3)
          {
            return ("XXX");
          }
        elsif ($digit == 4)
          {
            return ("XL");
          }
        elsif ($digit == 5)
          {
            return ("L");
          }
        elsif ($digit == 6)
          {
            return ("LX");
          }
        elsif ($digit == 7)
          {
            return ("LXX");
          }
        elsif ($digit == 8)
          {
            return ("LXXX");
          }
        elsif ($digit == 9)
          {
            return ("XC");
          }
    }

    #-------------------------------------------------------------------
    # Third digit into roman: 100-900
    #
    sub digit_3_to_roman
    {
        local ($digit) = $_[0];

        if ($digit == 0)
          {
            return ("");
          }
        elsif ($digit == 1)
          {
            return ("C");
          }
        elsif ($digit == 2)
          {
            return ("CC");
          }
        elsif ($digit == 3)
          {
            return ("CCC");
          }
        elsif ($digit == 4)
          {
            return ("CD");
          }
        elsif ($digit == 5)
          {
            return ("D");
          }
        elsif ($digit == 6)
          {
            return ("DC");
          }
        elsif ($digit == 7)
          {
            return ("DCC");
          }
        elsif ($digit == 8)
          {
            return ("DCCC");
          }
        elsif ($digit == 9)
          {
            return ("CM");
          }
    }

    #-------------------------------------------------------------------
    # Fourth digit into roman: 1000-9000
    #
    sub digit_4_to_roman
    {
        local ($digit) = $_[0];

        if ($digit == 0)
          {
            return ("");
          }
        elsif ($digit == 1)
          {
            return ("M");
          }
        elsif ($digit == 2)
          {
            return ("MM");
          }
        elsif ($digit == 3)
          {
            return ("MMM");
          }
        elsif ($digit == 4)
          {
            return ("MMMM");
          }
        elsif ($digit == 5)
          {
            return ("MMMMM");
          }
        elsif ($digit == 6)
          {
            return ("MMMMMM");
          }
        elsif ($digit == 7)
          {
            return ("MMMMMMM");
          }
        elsif ($digit == 8)
          {
            return ("MMMMMMMM");
          }
        elsif ($digit == 9)
          {
            return ("MMMMMMMMM");
          }
    }

    # Start the work.
    $digit_4 = int( $n / 1000 );
    $n = ($n - $digit_4*1000);
    $digit_3 = int( $n / 100 );
    $n = ($n - $digit_3*100);
    $digit_2 = int( $n / 10 );
    $n = ($n - $digit_2*10);
    $digit_1 = $n;

    return (&digit_4_to_roman($digit_4)
            . &digit_3_to_roman($digit_3)
            . &digit_2_to_roman($digit_2)
            . &digit_1_to_roman($digit_1));
} # &integer_to_roman

#-----------------------------------------------------------------------
# Return page width and height from page name.
#
# &paper_size (PAGE_NAME, ORIENTATION, EXTENSION)
#   --> (PAGE_WIDTH, PAGE_HEIGHT)
#-----------------------------------------------------------------------
sub paper_size
{
    local ($page_name) = lc ($_[0]);
    local ($orientation) = $_[1];
    local ($extension) = $_[2];
    local ($x) = 0;
    local ($y) = 0;
    local ($swap) = 0;

    if ($page_name eq "a4")
      {
        if ($extension eq "")
	  {
	    $x = "210mm";
	    $y = "297mm";
	  }
	elsif ($extension eq "long")
	  {
    	    $x = "210mm";
	    $y = "594mm";
	  }
	elsif ($extension eq "thin")
	  {
    	    $x = "210mm";
	    $y = "594mm";
	  }
	elsif ($extension eq "extralong")
	  {
    	    $x = "210mm";
	    $y = "891mm";
	  }
	elsif ($extension eq "large")
	  {
    	    $x = "210mm";
	    $y = "445.5mm";
	  }
	elsif ($extension eq "extralarge")
	  {
    	    $x = "210mm";
	    $y = "594mm";
	  }
        else
	  {
	    #-----------------------------------------------------------
    	    # Unimplemented extension.
	    #-----------------------------------------------------------
    	    printf STDERR (gettext ("%s: cannot use %s paper extension with %s paper size!\n"),
                           $program_executable,
                           $extension,
                           $page_name);
            exit 1;
	  }
      }
    elsif ($page_name eq "letter")
      {
        if ($extension eq "")
	  {
    	    $x = "8.5in";
	    $y = "11in";
	  }
        else
	  {
	    #-----------------------------------------------------------
    	    # Unimplemented extension.
	    #-----------------------------------------------------------
    	    printf STDERR (gettext ("%s: cannot use %s paper extension with %s paper size!\n"),
                           $program_executable,
                           $extension,
                           $page_name);
            exit 1;
	  }
      }
    else
      {
        #---------------------------------------------------------------
	# Unimplemented page size.
	#-----------------------------------------------------------
    	printf STDERR (gettext ("%s: do not know %s paper size!\n"),
                       $program_executable,
                       $page_name);
        exit 1;
      }

    if ($orientation eq "normal")
      {
        # OK
	;
      }
    elsif ($orientation eq "inverted")
      {
        # swap
	$swap = $x;
	$x = $y;
	$y = $swap;
      }

    return ($x, $y);

} # &paper_size

#-----------------------------------------------------------------------
# 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);

}

#-----------------------------------------------------------------------
# First step filter.
#
# 1.1 Transform some characters.
#     Also <Tab> characters are expanded.
#
# 1.2 Filter only one derivation.
#     The "MAIN" derivation is implied.
#
#     Inside the main source, SGML comments like these,
#     <!-- START FOO -->
#     <!-- STOP FOO -->
#     delimit the "FOO" derivation.
#
# 1.3 Find SYSTEM inclusions.
#     These files must be prepared in the same way as the
#     the main source, and the temporary source must point to
#     the transformed files.
#
# &step_1_filter (INPUT_FILE,
#                 TYPESETTING,
#                 DERIVATION_NAME,
#                 @SUBSTITUTIONS)
#
sub step_1_filter
{
    local ($input_file)    = $_[0];
    local ($typesetting)   = $_[1];
    local ($derivation)    = $_[2];
    local (*substitutions) = $_[3]; # array
    local ($n) = 0; # generic counter.
    local ($output_file) = &temporary_file ($temporary_file_name_prefix);
    chomp ($output_file);
    local ($line) = "";
    local ($include) = 0;
    local ($external_system_file) = "";
    local ($before_name) = "";
    local ($after_name) = "";
    local ($step_1_system_file) = "";

    # Tell what we are doing.
    &diag_output (sprintf (gettext ("%s:%s: step 1: "),
                           $program_executable, $input_file));
    &diag_output (sprintf (gettext ("character transformation and derivation filtering\n")));

    # We need to define a reference for input and output stream.
    # The choiche to use the same file names is just one way to
    # be shure to have ever different names.
    # We could use a random number, maybe.
    # This use of reference are necessary because we want to
    # make this subroutine recoursive. Using plain handlare names
    # is not possible: when we open again with the same handlear
    # name, the previous file is closed!
    local ($input_stream) = "$input_file";
    local ($output_stream) = "$output_file";

    # If the derivation is "MAIN", we suppose that the start
    # comment was already reached.
    if ("$derivation" eq "MAIN")
      {
        $include = 1;
      }
    
    # Open input and output files.
    # Tab characters are expanded.
    open ($input_stream, " expand $input_file |");
    open ($output_stream, "> $output_file");

    # Do what is required
    while ($line = <$input_stream>)
      {
        # The line break is not removed.

        #---------------------------------------------------------------
	# Check if it is the beguinning of a verbatim element
	# where nothing is to be done.
        #---------------------------------------------------------------

        if ($line =~ m/<!--\s+START\s+\S+\s+-->/i
	    || $line =~ m/<!--\s+STOP\s+\S+\s+-->/i)
	  {
	    # Don't touch this line
	  }
	else
	  {
	    # Eliminate inline comments.
	    $line =~ s/<!--(.*?)-->//gi;
	  }

        if ($line =~ m/<!--\s+START\s+\S+\s+-->/i
	    || $line =~ m/<!--\s+STOP\s+\S+\s+-->/i)
	  {
	    # Don't touch this line again.
	    ;
	  }
	elsif ($line =~ m/^\s*<!--.*$/)
	  {
	    # As it cannot be an in-line comment an cannot be a special
	    # command, it seems the beguinning of a block comment.
	    # Jump it.
	    # We hope that there is nothing on the same
	    # line after the comment termination.
	    &jump_block ($input_stream,
                          $output_stream,
			  $line,
			  "-->");
	    # Need to restart the loop;
	    next;
	  }
	elsif ($line =~ m/^<verbatimpre *[a-zA-Z]*=?"?[0-9]*"? *>/i)
	  {
	    # It seems the beguinning of a verbatim preformatted
	    # element. It must be jumped.
	    &jump_block ($input_stream,
                          $output_stream,
			  $line,
			  "</\verbatimpre>");
	    # Need to restart the loop;
	    next;
	  }

        #---------------------------------------------------------------
        # Step 1.1
        # Transform some characters if required.
        # ${$substitutions}[$n][0] is the charcter to be replaced;
        # ${$substitutions}[$n][1] is the replace string.
        #---------------------------------------------------------------

        for ($n = 0; $n <= $#substitutions; $n++)
          {
            $line =~ s/$substitutions[$n][0]/$substitutions[$n][1]/g;
          }

        #---------------------------------------------------------------
        # Step 1.2
        # Filter only one derivation.
        #---------------------------------------------------------------

        # Check if it is an inclusion comand.
        if ($line =~ m/<!--\s+START\s+$derivation\s+-->/i)
          {
            # The following lines must be included.
            $include = 1;
            # The directive is not removed fromoutput.
          }
        elsif ($line =~ m/<!--\s+STOP\s+$derivation\s+-->/i)
          {
            # The following lines must not be included.
            $include = 0;
            # The directive is not removed from output.
          }
        else
          {
            # It is a normal line. We have to decide what to do.
            if ($include)
              {
                # The line must not be removed.
                ;
              }
            else
              {
                # An empty line is transfered.
                #
                # It is important that the resulting file has text
                # exactly in the same line number as the original
                # source. This permits to understand SGML errors.
                $line = "\n";
              }
          }
    
        #---------------------------------------------------------------
        # Step 1.3
        # Find SYSTEM inclusions.
        # These files must be prepared in the same way as the
        # the main source, and the temporary source must point to
        # the transformed files.
        #---------------------------------------------------------------

        #-----------------------------------------------------------
        # Try to find SGML declarations for external files, like:
        # <!ENTITY COPYPARTE  SYSTEM "formalita/COPYPARTE.sgml">
        #
	# Notice that this regexp is very delicate; in particular,
	# it must not match for empty string like this,
        # <!ENTITY COPYPARTE  SYSTEM "">
	# although it is not valid, as it should be like this:
        # <!ENTITY COPYPARTE  "">
	#	
	if ($line =~ m/^(.*<!\s*ENTITY\s+.+\s+SYSTEM\s+\")(.+)(\"\s*>$)/i)
          {
            # Decompose the peaces of text.
            $before_name = $1;
            $external_system_file = $2;
            $after_name = $3;

            # Prepare this file with first step filter.
            # Recursive call!
            #
            # &step_1_filter (INPUT_FILE, TYPESETTING, DERIVATION_NAME)
            #
            $step_1_system_file
              = &step_1_filter ($external_system_file,
                                $typesetting,
                                $derivation);

            # Prepare this file with second step filter.
            # Recursive call!
            #
            # &step_2_filter (INPUT_FILE,
            #                 TYPESETTING,
            #                 ORIGINAL_FILE_NAME)
            #
            $step_2_system_file
              = &step_2_filter ($step_1_system_file,
                                $typesetting,
                                $external_system_file);

            # Delete previous temporary file.
            unlink ($step_1_system_file);

            # Save last temporary file names into the list.
            # These files will be deleted after the SGML parse.
            $temp_files_list
              = "$temp_files_list" . " $step_2_system_file";

            # Modify the SYSTEM inclusion instruction.
            $line = "$before_name"
                    . "$step_2_system_file"
                    . "$after_name\n";
             }

        #---------------------------------------------------------------
        # All sub steps are terminated.
        #---------------------------------------------------------------

        # Print current re-elaborated line to the output file.
        print $output_stream ("$line");

        # Continue the cicle until the last main source line.
      } 

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

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

}

#-----------------------------------------------------------------------
# Second step filter.
#
# Transform verbatim environments to the right way for SGML.
#
# &step_2_filter (INPUT_FILE, TYPESETTING, ORIGINAL_FILE_NAME)
#
sub step_2_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 ($nline) = 0;

    # Tell what we are doing.
    &diag_output (sprintf (gettext ("%s:%s:%s: step 2: "),
                           $program_executable, $original_file_name, $input_file));
    &diag_output (sprintf (gettext ("transform verbatim environments to the right way for SGML\n")));

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

    #-------------------------------------------------------------------
    # Jump_element.
    #
    # &jump_element (INPUT_STREAM, OUTPUT_STREAM, LINE, NLINE,
    #                CONCLUSION_STRING ) --> NLINE
    sub jump_element
    {
        local ($input_stream) = $_[0];
        local ($output_stream) = $_[1];
        local ($line) = $_[2];
        local ($nline) = $_[3];
        local ($conclusion) = $_[4];
    
        # 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>;
            $nline++;
          }

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

        # Return the line number.
        return ($nline);

    } # &jump_element

    #-------------------------------------------------------------------
    # Verbatim entity substitution.
    #
    # &verbatim_pre (INPUT_STREAM, OUTPUT_STREAM,
    #                LINE, NLINE,
    #                OPENING_TAG, CONCLUSION_TAG,
    #                TYPESETTING, ORIGINAL_FILE_NAME ) --> NLINE
    #
    sub verbatim_pre
    {
        local ($input_stream) = $_[0];
        local ($output_stream) = $_[1];
        local ($line) = $_[2];
        local ($nline) = $_[3];
        local ($opening) = $_[4];
        local ($conclusion) = $_[5];
        local ($typesetting) = $_[6];
        local ($original_file_name) = $_[7];

        # We presume that the ending tag cannot be on the same
        # line as the opening one.
        # So, we transfer the line read before this call.
        # Also the line counter is incremented.
        print $output_stream ($line);
        $line = <$input_stream>;
        $nline++;

        # Try to elaborate the SGML block, until the end tag.
        # We assume that the end tag uses a whole line.
        while ($line !~ m/$conclusion/i)
          {
            # We have to verify if there is another opening tag:
            # this is not allowed and the SGML cannot find the
            # mistake.
            if ($line =~ m/$opening/i)
              {
                # There is a mistake because we have another
                # opening tag!
                printf STDERR (gettext ("%s:%s: "),
                               $program_executable, $original_file_name);
                printf STDERR (gettext ("tag %s is not allowed here, at line %s\n"),
                               $opening, $nline);

                # To avoid troubles, we consider it as a closing tag
                # and we terminate the transformation.
                # But we don't change it, so the SGML parser will find
                # it too.
                last;
              }

            # Change "&" with "&amp;" for all occurrences.
            $line =~ s/&/&amp\;/g;

            # Change "<" with "&lt;" for all occurrences.
            $line =~ s/</&lt\;/g;

            # Change ">" with "&gt;" for all occurrences.
            $line =~ s/>/&gt\;/g;

            # Print current re-elaborated line to the output file.
            # Read next line and increment the counter.
            print $output_stream ("$line");
            $line = <$input_stream>;
            $nline++;
            
          }

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

        # Return the line number.
        return ($nline);

    } # &verbatim_pre

    #-------------------------------------------------------------------
    # Start of &step_2_filter()
    #-------------------------------------------------------------------

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

    # Do what is required
    while ($line = <$input_stream>)
      {
        # Increment line conuter.
        $nline++;

        # Now start the text analysis.
        if ($line =~ m/<!\s*--/)
          {
            # SGML comments must be jumped.
            #
            # &jump_element (INPUT_STREAM, OUTPUT_STREAM, LINE, NLINE,
            #                CONCLUSION_STRING) --> NLINE
            #
            $nline
              = &jump_element ($input_stream, $output_stream,
                               "$line", $nline, "--\s*>");

          }
	elsif ($line =~ m/^<verbatimpre *[a-zA-Z]*=?"?[0-9]*"? *>/i)
          {
            # Verbatim preformatted text is a real verbatim text that
            # must be scanned before the SGML elaboration: "&", "<"
	    # and ">" must be substitued.
	    #
            # &verbatim_pre (INPUT_STREAM,
	    #                OUTPUT_STREAM,
            #                LINE,
	    #                NLINE,
            #                OPENING_TAG,
	    #                CONCLUSION_TAG,
            #                TYPESETTING,
	    #                ORIGINAL_FILE_NAME) --> NLINE
            #-----------------------------------------------------------
            $nline
	      = &verbatim_pre
	          ($input_stream,
		   $output_stream,
		   "$line",
		   $nline,
		   "<verbatimpre *[a-zA-Z]*=?\"?[0-9]*\"? *>",
		   "<\/verbatimpre>",
                   "$typesetting",
		   "$original_file_name");
          }
        else
          {
            # Other lines are simply transfered as-is.
            print $output_stream ("$line");
          }
      }

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

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


#======================================================================
# Start of program.
#----------------------------------------------------------------------

local ($source_file_name) = "";
local ($derivation) = "";
local ($action) = "";
local ($draft) = 0;
local ($compact) = 0;
local ($long) = 0;
local ($paper_extension)   = "";
local ($paper)             = "a4"; # default to A4
local ($paper_width)       = "120mm"; # default to A4
local ($paper_height)      = "297mm"; # default to A4
local ($paper_orientation) = "normal"; # default to A4 normal
local ($page_numbering) = "";
local (@substitutions) = ();
local ($subst_from) = "";
local ($subst_to) = "";
local ($sgml_include) = ();
local ($nsgmls_include_options) = "";
local ($end_of_options) = 0;
local ($n) = 0;
local ($typesetting) = "";
local ($verbose) = 0;

# used to tell what kind of target is the post-SP elaboration for.
local ($sgml_target) = $typesetting;

local ($root_file_name) = "";
local ($step_1_temp_file) = "";
local ($step_2_temp_file) = "";
local ($step_3_temp_file) = &temporary_file ($temporary_file_name_prefix);
local ($step_4_temp_file) = "$step_3_temp_file-step4"; # we must know in advance


# Scan arguments.
for ($n = 0; $n <= $#ARGV; $n++)
  {
    # Analyze argument $n.
    if ($ARGV[$n] !~ m/^-/)
     {
        # Options are terminated as this argument has no minus at the
        # beguinning. This must be a file name.
        if ($end_of_options)
          {
            # As options are already terminated, this is an extra
            # argument: a mistake.
            printf STDERR (gettext ("%s: no more arguments allowed after the file name: %s\n"),
                                     $program_executable, $ARGV[$n]);
            exit 1;
          }
        else
          {
            # This is the first time that we encounter an argument
            # without "-". Must be the source file.
            $end_of_options = 1;
            $source_file_name = $ARGV[$n];
          }
      }
    elsif ($ARGV[$n] eq "--help")
      {
        # The user is asking for help.
        &help_syntax;
        exit 0;
      }
    elsif ($ARGV[$n] eq "--version")
      {
        # The user wants to know the program version.
        &version_info;
        exit 0;

      }
    elsif ($ARGV[$n] eq "--draft")
      {
        # The user wants to get draft typesetting.
        $draft = 1;
      }
    elsif ($ARGV[$n] eq "--compact")
      {
        # The user wants to get compact typesetting.
        $compact = 1;
      }
    elsif ($ARGV[$n] eq "--halfcompact")
      {
        # The user wants to get half compact typesetting.
        $compact = 0.5;
      }
    elsif ($ARGV[$n] eq "--long")
      {
        # The user wants to get long PostScript typesetting.
        $long = 1;
	$paper_extension = "long";
	
	#---------------------------------------------------------------
	# Change starting paper size.
	#---------------------------------------------------------------
	($paper_width, $paper_height) = &paper_size ($paper, $paper_orientation, $paper_extension);
      }
    elsif ($ARGV[$n] eq "--thin")
      {
        # The user wants to get thin PostScript typesetting.
        #$long = 101;
        $long = 1;
	$paper_extension = "thin";

	#---------------------------------------------------------------
	# Change starting paper size.
	#---------------------------------------------------------------
	($paper_width, $paper_height) = &paper_size ($paper, $paper_orientation, $paper_extension);
      }
    elsif ($ARGV[$n] eq "--extralong")
      {
        # The user wants to get long PostScript typesetting.
        #$long = 2;
        $long = 1;
	$paper_extension = "extralong";

	#---------------------------------------------------------------
	# Change starting paper size.
	#---------------------------------------------------------------
	($paper_width, $paper_height) = &paper_size ($paper, $paper_orientation, $paper_extension);
      }
    elsif ($ARGV[$n] eq "--large")
      {
        # The user wants to get long PostScript typesetting.
        #$long = 10;
        $long = 1;
	$paper_extension = "large";

	#---------------------------------------------------------------
	# Change starting paper size.
	#---------------------------------------------------------------
	($paper_width, $paper_height) = &paper_size ($paper, $paper_orientation, $paper_extension);
      }
    elsif ($ARGV[$n] eq "--extralarge")
      {
        # The user wants to get long PostScript typesetting.
        #$long = 20;
        $long = 1;
	$paper_extension = "extralarge";

	#---------------------------------------------------------------
	# Change starting paper size.
	#---------------------------------------------------------------
	($paper_width, $paper_height) = &paper_size ($paper, $paper_orientation, $paper_extension);
      }
    elsif ($ARGV[$n] eq "--sgml-syntax"
           || $ARGV[$n] eq "--sgml-check")
      {
        # The user wants to check the SGML source.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "sgml-check";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                                     $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] eq "--html-check")
      {
        # The user wants to check the HTML source.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "html-check";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                                     $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] eq "--html401-check")
      {
        # The user wants to check the HTML source.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "html401-check";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                                     $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] eq "--html320-check")
      {
        # The user wants to check the HTML source.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "html320-check";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                                     $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] eq "--sgml-syntax-hard"
           || $ARGV[$n] eq "--sgml-check-hard")
      {
        # The user wants to check all SGML aspects.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "sgml-check-hard";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                                     $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] =~ m/^--derivation=(.*)$/)
      {
        # The user tells the name of the derivation.
        # We need to verify that the derivation wasn't already definied.
        if ($derivation eq "")
          {
            $derivation = $1;
          }
        else
          {
            printf STDERR (gettext ("%s: only one derivation option is allowed: %s\n"),
                                     $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] =~ m/^--sgml-include=(.*)$/)
      {
        # The user tells the name of an SGML parameter entity
        # that should be assigned with the word "INCLUDE". That
        # is, we want:
        #
        # <!ENTITY % name "INCLUDE">
        #
        # This option is cumulative; this way, we add to an array.
        $sgml_include[$#sgml_include+1] = $1;
      }
    elsif ( $ARGV[$n] =~ m/^--paper=(.+)$/ )
      {
	#---------------------------------------------------------------
        # The user tells what page size.
        # We need to verify that the dimentions werent already definied.
	#---------------------------------------------------------------
        $paper = lc $1;
        ($paper_width, $paper_height) = &paper_size ($paper, $paper_orientation, $paper_extension);
        if ($paper_width > 0 && $paper_height > 0)
          {
	    #-----------------------------------------------------------
            # The paper formats are ok (and should be strings).
	    #-----------------------------------------------------------
            ;
          }
        else
          {
    	    #-----------------------------------------------------------
	    # There is a problem.
	    #-----------------------------------------------------------
            printf STDERR (gettext ("%s: paper size unknown %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ( $ARGV[$n] =~ m/^--paper-orientation=(.+)$/ )
      {
	#---------------------------------------------------------------
        # The user tells the paper orientation.
        # We need to verify the previous orientation.
	#---------------------------------------------------------------
	if (lc ($1) eq "potrait"
	    || lc ($1) eq "inverted")
	  {
	    # OK.
    	    if ($paper_orientation eq lc ($1))
	      {
		# Nothing to change.
		;
	      }
	    else
	      {
		#-------------------------------------------------------
    		# Must revert axes and save new orientation.
		#-------------------------------------------------------
		($paper_width, $paper_height) = ($paper_height, $paper_width);
		$paper_orientation = lc ($1);
	      }
	  }
	else
	  {
    	    #-----------------------------------------------------------
	    # There is a problem.
	    #-----------------------------------------------------------
            printf STDERR (gettext ("%s: paper orientation unknown %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
	  }
      }
    elsif ( $ARGV[$n] =~ m/^--replace-char=(.+),(.+)$/ )
      {
        # The user tells to replace some character inside the
        # source file.
        $subst_from = $1;
        $subst_to = $2;

        if ($subst_from eq ""
            || $subst_to eq "")
          {
            # There is something wrong.
            printf STDERR (gettext ("%s: substitution unknown %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
        else
          {
            # Add a new substitution couple inside the array.
            $#substitutions++;
            $substitutions[$#substitutions] = ();
            $substitutions[$#substitutions][0] = $subst_from;
            $substitutions[$#substitutions][1] = $subst_to;
          }
      }
    elsif ( $ARGV[$n] =~ m/^--page-numbering=(.*)$/ )
      {
        # The user tells how to handle page numbering.
        if ($page_numbering eq "")
          {
            $page_numbering = $1;
            if ($page_numbering eq "plain"
                || $page_numbering eq "default")
              {
                # OK.
                ;
              }
            else
              {
                printf STDERR (gettext ("%s: only the words plain and default are allowed: %s\n"),
                               $program_executable, $ARGV[$n]);
                exit 1;
              }
          }
        else
          {
            printf STDERR (gettext ("%s: page numbering may be specified only once: %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] eq "--tex"
           || $ARGV[$n] eq "--latex")
      {
        # The user wants to generate only a LaTeX source for debugging.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "latex";
            $typesetting = "LATEX";
            $sgml_target = "LATEX";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ( $ARGV[$n] eq "--dvi" )
      {
        # The user wants to generate a DVI output.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "dvi";
            $typesetting = "LATEX";
            $sgml_target = "DVI";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ( $ARGV[$n] eq "--sp" )
      {
        # The user wants to generate a SP output for debugging.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "sp";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] eq "--ps"
           || $ARGV[$n] eq "--postscript")
      {
        # The user wants to generate a PostScript output.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "ps";
            $typesetting = "LATEX";
            $sgml_target = "PS";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] eq "--pdf")
      {
        # The user wants to generate a PDF output.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "pdf";
            $typesetting = "LATEX";
            $sgml_target = "PDF";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] eq "--html")
      {
        # The user wants to generate a standard HTML output.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "html";
            $typesetting = "HTML";
            $sgml_target = "HTML";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] eq "--html-text")
      {
        # The user wants to generate a single HTML output for text
        # browsers.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "html-text";
            $typesetting = "HTML";
            $sgml_target = "HTML-TEXT";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    elsif ($ARGV[$n] eq "--verbose")
      {
	# Verbose mode was required.
	$verbose = 1;
      }
    elsif ($ARGV[$n] eq "--clean")
      {
        # The user wants to generate a DVI output.
        # We need to verify that the action wasnt already definied.
        if ($action eq "")
          {
            $action = "clean";
          }
        else
          {
            printf STDERR (gettext ("%s: only one action option is allowed: %s\n"),
                           $program_executable, $ARGV[$n]);
            exit 1;
          }
      }
    else
      {
        # Must be an unknown option.
        printf STDERR (gettext ("%s: unknown option: %s\n"),
                       $program_executable, $ARGV[$n]);
        exit 1;
      }

  }

# Are arguments logical?
# Define default values an prepare some values.
if ($derivation eq "")
  {
    $derivation = "MAIN";
  }

if ($action eq "")
  {
    $action = "sp";
  }

for ($n = 0 ; $n <= $#sgml_include ; $n++)
  {
    $nsgmls_include_options
      = $nsgmls_include_options . " -i" . $sgml_include[$n];
  }

#----------------------------------------------------------------------
# We assume that if we are here, all arguments are ok.
# If we are here, there is something to do.
#----------------------------------------------------------------------

# Define the root file name.
$root_file_name = &root_name ("$source_file_name", ".sgml");

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

# Prepare the diagnostic messages file. It will be reopened when
# necessary.
system( "mv -f $root_file_name.diag $root_file_name.diag~" );
open (DIAG, "> $root_file_name.diag");
close (DIAG);

# If we have to clean from stale files; we do here:
if ($action eq "clean")
 {
    system( "rm $root_file_name.log > /dev/null 2>&1" );
    system( "rm $root_file_name.aux > /dev/null 2>&1" );
    system( "rm $root_file_name.pageref > /dev/null 2>&1" );
    system( "rm $root_file_name.diag > /dev/null 2>&1" );

    exit 0;
  }

# If we have to check an HTML or XML file...
if ($action eq "html-check")
  {
    # We just check the HTML. The output is controlled by less, so
    # we can read it well.
    system
      ("cat $source_file_name | nsgmls -s -c $HTML_CATALOG 2>&1 | less");

    exit 0;
  }
if ($action eq "html320-check")
  {
    # We just check the HTML 3.2. The output is controlled by less, so
    # we can read it well.
    system
      ("cat $source_file_name | nsgmls -s -c $HTML320_CATALOG 2>&1 | less");

    exit 0;
  }
if ($action eq "html401-check")
  {
    # We just check the HTML 4.01. The output is controlled by less, so
    # we can read it well.
    system
      ("cat $source_file_name | nsgmls -s -c $HTML401_CATALOG 2>&1 | less");

    exit 0;
  }
elsif ($action eq "xml-check")
  {
    # We just check the XML. The output is controlled by less, so
    # we can read it well.
    system
      ("cat $source_file_name | nsgmls -s -c $XML_CATALOG 2>&1 | less");

    exit 0;
  }

# First step filter.
# &step_1_filter (INPUT_FILE, TYPESETTING, DERIVATION_NAME)
$step_1_temp_file
  = &step_1_filter ($source_file_name, $typesetting, $derivation, \@substitutions);

# Second step filter.
# &step_2_filter (INPUT_FILE, TYPESETTING, ORIGINAL_FILE_NAME)
$step_2_temp_file
  = &step_2_filter ($step_1_temp_file, $typesetting, $source_file_name);

# Now we call nsgmls from the SP package and do what it is required.
if ($action eq "sgml-check")
  {
    # We just check the SGML. The output is controlled by less, so
    # we can read it well.
    system
      ("cat $step_2_temp_file | nsgmls $nsgmls_include_options -s -c $CATALOG 2>&1 | less");
  }
elsif ($action eq "sgml-check-hard")
  {
    # We just check the SGML in an hard way.
    # The output is controlled by less, so
    # we can read it well.
    system
      ("cat $step_2_temp_file | nsgmls $nsgmls_include_options -wall -s -c $CATALOG 2>&1 | less");
  }
else
  {
    # Tell what we are doing.
    &diag_output (sprintf (gettext ("%s:%s: step 3: SGML parse\n"),
                           $program_executable, $source_file_name));

    # We obtain a first pass SP output.
    system
      ("cat $step_2_temp_file | nsgmls $nsgmls_include_options -c $CATALOG > $step_3_temp_file");

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


    if ($action eq "sp")
      {
        # All done. The SP output is ready.
        # We just copy the temporary file into an appropriate name.
        system ("cp $step_3_temp_file $root_file_name.sp");
        system ("cp $step_4_temp_file $root_file_name.sp2");
      }
    else
      {
        # We have to elaborate the post-SP output 

	# Tell what we are going to do.
	&diag_output (sprintf (gettext ("%s:%s: step 5: parsing post-SP for target %s\n"),
                               $program_executable, $source_file_name, $sgml_target));

        # We just need to call:
        #&sgml_post_sp_elab ($step_4_temp_file,
        #                    $typesetting,
        #                    $sgml_target,
        #                    $draft,
        #                    $page_numbering,
        #                    $compact,
        #                    $long,
        #                    $source_file_name,
        #                    $root_file_name);
        #
        # But we cannot, as this will take away all resources and
        # the system() function will not work well for further
        # elaborations.
        #
        # So this function is inside a specific Perl program:
        # alml-sp2be.
        #
        # Notice that arguments must be enclosed with double quotes
        # because these arguments may be empty.
        #
        # Last argument, $verbose, is meant to be like a global variable.
        #
        system ("alml-sp2be \"$step_4_temp_file\" \"$typesetting\" \"$sgml_target\" \"$draft\" \"$page_numbering\" \"$compact\" \"$long\" \"$source_file_name\" \"$root_file_name\" \"$verbose\" \"$paper_width\" \"$paper_height\"");

        if ($action eq "latex")
          {
            # All done. The LaTeX source is ready.
            ;   
          }
        elsif ($action eq "html")
          {
            # All done. The HTML output is ready.
            ;   
          }
        elsif ($action eq "html-text")
          {
            # All done. The HTML output is ready.
            ;   
          }
        elsif ($action eq "dvi")
          {
	    system ("mv -f $root_file_name.aux $root_file_name.aux~");
            system ("mv -f $root_file_name.pageref $root_file_name.pageref~");
            system ("mv -f $root_file_name.log $root_file_name.log~");
            system ("latex $root_file_name.tex");
            # We need to call an external program because of a memory problem.
            system ("alml-pageref \"$root_file_name\" 0 \"$verbose\"");
            system ("latex $root_file_name.tex");
            # We need to call an external program because of a memory problem.
            system ("alml-pageref \"$root_file_name\" 1 \"$verbose\"");
            system ("latex $root_file_name.tex");
          }
        elsif ($action eq "ps")
          {
	    system ("mv -f $root_file_name.aux $root_file_name.aux~");
            system ("mv -f $root_file_name.pageref $root_file_name.pageref~");
            system ("mv -f $root_file_name.log $root_file_name.log~");
            system ("latex $root_file_name.tex");
            # We need to call an external program because of a memory problem.
            system ("alml-pageref \"$root_file_name\" 0 \"$verbose\"");
            system ("latex $root_file_name.tex");
            # We need to call an external program because of a memory problem.
            system ("alml-pageref \"$root_file_name\" 1 \"$verbose\"");
            system ("latex $root_file_name.tex");

            if ($paper_extension eq "")
              {
		#-------------------------------------------------------
		# DVIPS will find page dimensions from \special{...}
		# inside TeX code.
		#-------------------------------------------------------
                system ("dvips -K -o $root_file_name.ps $root_file_name.dvi");
              }
            elsif ($paper_extension eq "long"
	        && $paper eq "a4"
		&& $paper_orientation eq "normal")
              {
		#-------------------------------------------------------
	        # The name *.X2V.ps means two times vertical; that
		# is, two columns.
		#-------------------------------------------------------
                local ($temporary_ps) = &temporary_file ($temporary_file_name_prefix);
                system ("dvips -K -T 210mm,594mm -o $temporary_ps $root_file_name.dvi");
		#-------------------------------------------------------
                # Use PSUtils to convert the file.
		#-------------------------------------------------------
                system ("cat $temporary_ps                                \\
                           | pstops -w 42cm -h 59.4cm                     \\
                               -q \"2:0\@1(1cm,0cm)+1\@1(20cm,0cm)\"     \\
                           | psresize -W 42cm -H 59.4cm -w 21cm -h 29.7cm \\
                           > $root_file_name.X2V.ps");
		&ps_new_bounding_box ( "$root_file_name.X2V.ps", "%%BoundingBox: 0 0 596 842");
                system ("rm -f $temporary_ps");
              }
            elsif ($paper_extension eq "thin"
	           && $paper eq "a4"
		   && $paper_orientation eq "normal")
              {
		#-------------------------------------------------------
	        # The name *.X1T.ps means thin once vertical; that
		# is, one thin column (half A4).
		#-------------------------------------------------------
                local ($temporary_ps) = &temporary_file ($temporary_file_name_prefix);
                system ("dvips -K -T 210mm,594mm -o $temporary_ps $root_file_name.dvi");
		#-------------------------------------------------------
                # Use PSUtils to convert the file.
		#-------------------------------------------------------
                system ("cat $temporary_ps                                \\
		         | psresize -W 21cm -H 59.4cm -w 10.5cm -h 29.7cm   \\
			 > $root_file_name.X1T.ps");
		&ps_new_bounding_box ( "$root_file_name.X1T.ps", "%%BoundingBox: 0 0 298 842");
                system ("rm -f $temporary_ps");
              }
            elsif ($paper_extension eq "extralong"
	           && $paper eq "a4"
		   && $paper_orientation eq "normal")
              {
		#-------------------------------------------------------
	        # The name *.X3V.ps means three times vertical; that
		# is, three columns.
		#-------------------------------------------------------
                local ($temporary_ps) = &temporary_file ($temporary_file_name_prefix);
                system ("dvips -K -T 210mm,891mm -o $temporary_ps $root_file_name.dvi");
		#-------------------------------------------------------
                # Use PSUtils to convert the file.
		#-------------------------------------------------------
                system ("cat $temporary_ps                                \\
                           | pstops -w 63cm -h 89.1cm                     \\
                               -q \"3:0\@1(2cm,-0.5cm)+1\@1(21cm,-0.5cm)+2\@1(40cm,-0.5cm)\"     \\
                           | psresize -W 63cm -H 89.1cm -w 21cm -h 29.7cm \\
                           > $root_file_name.X3V.ps");
		&ps_new_bounding_box ( "$root_file_name.X3V.ps", "%%BoundingBox: 0 0 596 842");
                system ("rm -f $temporary_ps");
              }
            elsif ($paper_extension eq "large"
	           && $paper eq "a4"
		   && $paper_orientation eq "normal")
              {
	        # The name *.X3H.ps means three times horizontal; that
		# is, three columns; on landscape paper.
                local ($temporary_ps) = &temporary_file ($temporary_file_name_prefix);
                system ("dvips -K -T 210mm,445.5mm -o $temporary_ps $root_file_name.dvi");
                # Use PSUtils to convert the file.
                system ("cat $temporary_ps                                \\
                           | pstops -w 44.5cm -h 63cm                      \\
                               -q \"3:0\@1(1.7cm,18.5cm)+1\@1(21cm,18.5cm)+2\@1(40cm,18.5cm)\"     \\
                           | psresize -W 44.55cm -H 63cm -h 21cm -w 29.7cm \\
                           > $root_file_name.X3H.ps");
		&ps_new_bounding_box ( "$root_file_name.X3H.ps", "%%BoundingBox: 0 0 596 842");
                system ("rm -f $temporary_ps");
              }
            elsif ($paper_extension eq "extralarge"
	           && $paper eq "a4"
		   && $paper_orientation eq "normal")
              {
	        # The name *.X4H.ps means four times horizontal; that
		# is, three columns; on landscape paper.
                local ($temporary_ps) = &temporary_file ($temporary_file_name_prefix);
                system ("dvips -K -T 210mm,594mm -o $temporary_ps $root_file_name.dvi");
                # Use PSUtils to convert the file.
                system ("cat $temporary_ps                                \\
                           | pstops -w 59.4cm -h 63cm                      \\
                               -q \"4:0\@1(3cm,14cm)+1\@1(22cm,14cm)+2\@1(41cm,14cm)+3\@1(60cm,14cm)\"     \\
                           | psresize -W 59.4cm -H 63cm -h 21cm -w 29.7cm \\
                           > $root_file_name.X4H.ps");
		&ps_new_bounding_box ( "$root_file_name.X4H.ps", "%%BoundingBox: 0 0 596 842");
                system ("rm -f $temporary_ps");
              }
            elsif ($paper_extension eq ""
	           && $paper eq "a4"
		   && $paper_orientation eq "normal")
              {
                system ("dvips -K -t a4 -o $root_file_name.ps $root_file_name.dvi");
              }
            else
              {
    		printf STDERR (gettext ("%s: wrong combination of paper (%s) and extension (%s)!\n"),
            		       $program_executable,
			       $paper,
			       $paper_extension);
                system ("dvips -K -t a4 -o $root_file_name.ps $root_file_name.dvi");
              }
          }
        elsif ($action eq "pdf")
          {
	    system ("mv -f $root_file_name.aux $root_file_name.aux~");
            system ("mv -f $root_file_name.pageref $root_file_name.pageref~");
            system ("mv -f $root_file_name.log $root_file_name.log~");
            system ("pdflatex $root_file_name.tex");
            # We need to call an external program because of a memory problem.
            system ("alml-pageref \"$root_file_name\" 0 \"$verbose\"");
            system ("pdflatex $root_file_name.tex");
            # We need to call an external program because of a memory problem.
            system ("alml-pageref \"$root_file_name\" 1 \"$verbose\"");
            system ("pdflatex $root_file_name.tex");
          }
      }
}

# Delete temporary files.
# It is strange, but sometimes, unlink() doesn't work as expected.
# This is because we use "rm" instead.
unlink ($step_1_temp_file);
unlink ($step_2_temp_file);
unlink ($step_3_temp_file);
system ("rm -f $step_3_temp_file");
unlink ($step_4_temp_file);
system ("rm -f $temp_files_list");

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

