--          This file is part of SmartEiffel The GNU Eiffel Compiler.
--       Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE
--            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr
--                       http://SmartEiffel.loria.fr
-- SmartEiffel 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, or (at your option)  any  later
-- version. SmartEiffel 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  SmartEiffel;  see the file COPYING.  If not,
-- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-- Boston, MA 02111-1307, USA.
--
class INSTALL
   --
   -- The portable `install' command to install SmartEiffel.
   -- The installation is done from scratch. Unless "-skip_c_compilation" is
   -- specified, all commands are recompiled from scratch (the compiler
   -- itself is bootstrapped !).
   --

inherit COMMAND_LINE_TOOLS rename system_tools as dev_null end

creation make

feature {NONE}

   command_name: STRING is "install"

   interactive: BOOLEAN
	 -- No automatic compiler selection or system name selection.

   skip_c_compilation: BOOLEAN
	 -- Useful, if precompile binaries are already included with a
	 -- distribution.

   system_se_path: STRING
	 -- The "system.se" file path is the very first information this
	 -- install program tries to compute. For example, on Windows, the
	 -- value may be "C:SmartEiffel\sys\system.se". This file is intended
	 -- to contains the `system_name' value on its very first line.

   set_system_se_path is
      local
	 string: STRING
      do
	 echo.put_string("Checking %"SmartEiffel%" environment variable:%N")
	 system_se_path := echo.getenv(fz_smarteiffel,Void)
	 if system_se_path = Void or else system_se_path.count = 0 then
	    string := fz_smarteiffel.twin
	    string.to_upper
	    system_se_path := echo.getenv(string,Void)
	 end
	 if system_se_path = Void or else system_se_path.count = 0 then
	    fatal_problem_description_start
	    echo.put_string("[
	       Environment variable "SmartEiffel" is not set.
               Please, set this variable with the absolute path of 
               the "SmartEiffel/sys/system.se" file.
                             ]")
	    fatal_problem_description_end
	 end
	 if not system_se_path.has_suffix("system.se") then
	    fatal_problem_description_start
	    echo.put_string(
	    "Value of the Environment variable %"SmartEiffel%"%Nis %"")
	    echo.put_string(system_se_path)
	    echo.put_string("%".%N")
	    echo.put_string(
	    "Please, set this variable with the absolute path of%N%
	    %the %"SmartEiffel/sys/system.se%" file.%N%
	    %For example, on Linux, the value is%N%
	    %often %"/usr/lib/SmartEiffel/sys/system.se%".%N%
	    %On Windows, %"C:\SmartEiffel\sys\system.se%" is a correct %
	    %value%Nwhen the SmartEiffel directory is at toplevel of the C %
	    %hard disk.%N")
	    fatal_problem_description_end
	 end
	 if not file_exists(system_se_path) then
	    fatal_problem_description_start
	    echo.put_string(
	    "Value of the Environment variable %"SmartEiffel%" value%Nis %"")
	    echo.put_string(system_se_path)
	    echo.put_string(
	    "%".%N%
	    %There is no readable file %"")
	    echo.put_string(system_se_path)
	    echo.put_string(
	    "%".%N%
	    %Check this absolute path as well as read permission.%N")
	    fatal_problem_description_end
	 end
	 echo.put_string(
	 "Value of the Environment variable %"SmartEiffel%" is correctly %
	 %set%Nto some existing file%Npath (%"")
	 echo.put_string(system_se_path)
	 echo.put_string("%").%N")
	 basic_directory.reset_notation_using(system_se_path)
	 echo.put_string("File/directory path handling with a ")
	 if basic_directory.unix_notation then
	    echo.put_string("UNIX")
	 elseif basic_directory.windows_notation then
	    echo.put_string("Windows")
	 elseif basic_directory.cygwin_notation then
	    echo.put_string("Cygwin/Windows")
	 elseif basic_directory.amiga_notation then
	    echo.put_string("Amiga")
	 elseif basic_directory.macintosh_notation then
	    echo.put_string("Macintosh")
	 elseif basic_directory.openvms_notation then
	    echo.put_string("OpenVMS")
	 else
	    echo.put_string("?not_yet_known?")
	 end
	 echo.put_string(" notation.%N")
      end

   installation_path: STRING
	 -- Using the `system_se_path', the `installation_path' of SmartEiffel is
	 -- computed. For example, on Windows, a correct value may be
	 -- "C:\SmartEiffel\".

   set_installation_path is
      local
	 string: STRING
      do
	 echo.put_string("Checking that the SmartEiffel directory exists:%N")
	 string := system_se_path.twin
	 basic_directory.compute_parent_directory_of(string)
	 if basic_directory.last_entry.is_empty then
	    fatal_problem_description_start
	    echo.put_string("Unable to compute parent directory %Nof %"")
	    echo.put_string(system_se_path)
	    echo.put_string("%".%N")
	    fatal_problem_description_end
	 end
	 string := basic_directory.last_entry.twin
	 basic_directory.compute_parent_directory_of(string)
	 if basic_directory.last_entry.is_empty then
	    fatal_problem_description_start
	    echo.put_string("Unable to compute parent directory %Nof %"")
	    echo.put_string(string)
	    echo.put_string("%".%N")
	    fatal_problem_description_end
	 end
	 installation_path := basic_directory.last_entry.twin
	 echo.put_string("SmartEiffel directory path is %"")
	 echo.put_string(installation_path)
	 echo.put_string("%".%N")
      end

   system_name: STRING
	 -- The `system_name' is one element of SYSTEM_TOOLS `system_list'
	 -- ("UNIX", "Windows", "Cygwin", "BeOS", "Macintosh",
	 -- "Amiga", "DOS", "OS2", "OpenVMS", "Elate", etc.).

   set_system_name is
	 -- Ask for or try to detect the system automatically.
      do
	 echo.put_string("System name detection:%N")
	 if interactive then
	    system_name := choice_in("System name selection",
				     system_tools.system_list)
	 elseif file_exists("/sys/rc") then
	    -- We're looking for a file unique to the new Amiga Digital
	    -- Environment running on Taos.
	    echo.put_string("System seems to be an Amiga on Taos Elate.%N")
	    system_name := "Elate"
	 elseif file_exists("s:startup-sequence") then
	    -- This check has to be performed BEFORE the Unix check
	    -- ("/bin/ls"), because the latter might be true if the user
	    -- installed GeekGadgets and one of those perverted patches
	    -- to handle Unix-style paths !
	    echo.put_string("System seems to be an Amiga.%N")
	    system_name := "Amiga"
	 elseif file_exists("/boot/beos/system/Tracker") then
	    echo.put_string("System seems to be BeOS.%N")
	    system_name := "BeOS"
	 elseif file_exists("/bin/ls.exe") then
	    echo.put_string("System seems to be Cygwin.%N")
	    system_name := "Cygwin"
	 elseif file_exists("/bin/ls") then
	    echo.put_string("System seems to be UNIX.%N")
	    system_name := "UNIX"
	 else
	    if basic_directory.system_notation_detected then
	       if basic_directory.unix_notation then
		  system_name := "UNIX"
	       elseif basic_directory.windows_notation then
		  system_name := "Windows"
	       elseif basic_directory.cygwin_notation then
		  system_name := "Cygwin"
	       elseif basic_directory.amiga_notation then
		  system_name := "Amiga"
	       elseif basic_directory.macintosh_notation then
		  system_name := "Macintosh"
	       elseif basic_directory.openvms_notation then
		  system_name := "OpenVMS"
	       end
	    end
	    if system_name = Void then
	       basic_directory.connect_to("C:\")
	       if basic_directory.is_connected then
		  system_name := "Windows"
		  basic_directory.disconnect
	       else
		  std_output.put_string("Automatic system detection failed (sorry).%N")
		  system_name := choice_in("System name selection",
					   system_tools.system_list)
	       end
	    end
	 end
	 echo.put_string("System is %"")
	 echo.put_string(system_name)
	 echo.put_string("%".%NTry to update file %"")
	 echo.put_string(system_se_path)
	 echo.put_string("%".%N")
	 echo.tfw_connect(tfw,system_se_path)
	 tfw_check_is_connected(system_se_path)
	 tfw.put_string(system_name)
	 tfw.put_character('%N')
	 tfw.disconnect
	 echo.put_string("Update of %"")
	 echo.put_string(system_se_path)
	 echo.put_string("%" done.%N")
	 system_tools.make
	 if not system_name.same_as(system_tools.system_name) then
	    fatal_problem_description_start
	    echo.put_string("Unkown SYSTEM_TOOLS.system_name %"")
	    echo.put_string(system_name)
	    echo.put_string("%".%N")
	    fatal_problem_description_end
	 end
      end

   echo_tfw_put_string(directory: STRING) is
      do
	 echo.put_string(directory)
	 tfw.put_string(directory)
      end

   write_default_loadpath_se_file is
	 -- Write the appropriate "C:\SmartEiffel\sys\loadpath.se" file.
      local
	 path, directory, tools_directory: STRING
	 list: ARRAY[STRING]; i: INTEGER
      do
	 echo.put_string("Writing default loadpath.se file:%N")
	 path := installation_path.twin
	 basic_directory.compute_subdirectory_with(path,"sys")
	 if basic_directory.last_entry.is_empty then
	    fatal_problem_description_start
	    echo.put_string("Unable to compute subdirectory %"sys%" of %"")
	    echo.put_string(path)
	    echo.put_string("%".%N")
	    fatal_problem_description_end
	 end
	 path.copy(basic_directory.last_entry)
	 basic_directory.compute_file_path_with(path,"loadpath.")
	 path.copy(basic_directory.last_entry)
	 path.append(system_name)
	 echo.tfw_connect(tfw,path)
	 tfw_check_is_connected(path)
	 echo.put_string("--- Written data ---%N")
	 -- The current working directory is the very first item:
	 if ("UNIX").same_as(system_name) then
	    directory := "./%N"
	 elseif ("Cygwin").same_as(system_name) then
	    directory := "./%N"
	 elseif ("DOS").same_as(system_name) then
	    directory := ".\%N"
	 elseif ("Windows").same_as(system_name) then
	    directory := ".\%N"
	 elseif ("BeOS").same_as(system_name) then
	    directory := "./%N"
	 elseif ("Macintosh").same_as(system_name) then
	    directory := ":%N"
	 elseif ("OpenVMS").same_as(system_name) then
	    directory := "[]%N"
	 elseif ("OS2").same_as(system_name) then
	    directory := ".\%N"
	 elseif ("Amiga").same_as(system_name) then
	    directory := "%N"
	 elseif ("Elate").same_as(system_name) then
	    directory := "./%N"
	 end
	 if directory /= Void then
	    echo_tfw_put_string(directory)
	 end
	 -- All sub-directories of "lib":
	 from
	    list := <<
		      "kernel",
		      "base",
		      "io",
		      "iterator",
		      "random",
		      "number",
		      "sorting",
		      "time",
		      "scoop",
		      "misc"
		      >>
	    i := list.lower
	 until
	    i > list.upper
	 loop
	    directory := installation_path.twin
	    basic_directory.compute_subdirectory_with(directory,"lib")
	    directory.copy(basic_directory.last_entry)
	    basic_directory.compute_subdirectory_with(directory,list.item(i))
	    directory.copy(basic_directory.last_entry)
	    directory.extend('%N')
	    echo_tfw_put_string(directory)
	    i := i + 1
	 end
	 -- The "tool" directory itself:
	 tools_directory := installation_path.twin
	 basic_directory.compute_subdirectory_with(tools_directory,"tools")
	 tools_directory.copy(basic_directory.last_entry)
	 echo_tfw_put_string(tools_directory)
	 echo_tfw_put_string("%N")
	 -- All sub-directories of "tools":
	 from
	    list := <<
		      "expression",
		      "instruction",
		      "e_type",
		      "feature",
		      "run_feature",
		      "misc"
		      >>
	    i := list.lower
	 until
	    i > list.upper
	 loop
	    directory := tools_directory.twin
	    basic_directory.compute_subdirectory_with(directory,list.item(i))
	    directory.copy(basic_directory.last_entry)
	    directory.extend('%N')
	    echo_tfw_put_string(directory)
	    i := i + 1
	 end
	 -- And finally, the tutorial directory:
	 directory := installation_path.twin
	 basic_directory.compute_subdirectory_with(directory,"tutorial")
	 directory.copy(basic_directory.last_entry)
	 echo_tfw_put_string(directory)
	 echo.put_string("%N--- Written data ---%N")
	 tfw.disconnect
	 echo.put_string("Update of %"")
	 echo.put_string(path)
	 echo.put_string("%" done.%NThe default loadpath is updated.%N")
      end

   compiler_se_path: STRING
	 -- The path name of the file which is used to save the
	 -- `c_compiler_name' with its default options. For example,
	 -- on Windows, the value may be "C:SmartEiffel\sys\compiler.se"

   set_compiler_se_path is
      local
	 path: STRING
      do
	 path := installation_path.twin
	 basic_directory.compute_subdirectory_with(path,"sys")
	 path := basic_directory.last_entry.twin
	 basic_directory.compute_file_path_with(path,"compiler.se")
	 compiler_se_path := basic_directory.last_entry.twin
      end

   garbage_collector_file_path: STRING
	 -- The garbage collector path file. For example, on Windows, a
	 -- correct value may be "C:\SmartEiffel\sys\gc".

   set_garbage_collector_file_path is
      local
	 path: STRING
      do
	 echo.put_string("Computing GC file path:%N")
	 path := installation_path.twin
	 basic_directory.compute_subdirectory_with(path,"sys")
	 if basic_directory.last_entry.is_empty then
	    fatal_problem_description_start
	    echo.put_string("Unable to compute directory path with %"")
	    echo.put_string(path)
	    echo.put_string("%" and %"sys%".%N")
	    fatal_problem_description_end
	 end
	 path := basic_directory.last_entry.twin
	 basic_directory.compute_file_path_with(path,"gc")
	 path := basic_directory.last_entry.twin
	 garbage_collector_file_path := path
	 echo.put_string("GC file path is %"")
	 echo.put_string(garbage_collector_file_path)
	 echo.put_string("%" and %"sys%".%N")
      end

   garbage_collector: STRING
	 -- The content of the first word of file `garbage_collector_file_path'
	 -- (the specific code for the GC).

   garbage_collector_selection is
      local
	 cmd: STRING; s: SYSTEM
      do
	 echo.put_string("Garbage collector selection:%N")
	 if ("UNIX").same_as(system_name) then
	    cmd := system_se_path.twin
	    cmd.remove_suffix("sys/system.se")
	    cmd.append("misc/GC.SH")
	    echo.put_string("Launching script %"")
	    echo.put_string(cmd)
	    echo.put_string("%".%N")
	    s.execute_command_line(cmd)
	 elseif ("Amiga").same_as(system_name) then
	    garbage_collector := "m68k-amigaos.c"
	 elseif system_name.is_equal("Elate") then
	    garbage_collector := "elate.c"
	 elseif ("Windows").same_as(system_name) then
	    garbage_collector := "windows.c"
	 elseif ("BeOS").same_as(system_name) then
	    garbage_collector := "beos_x86.c"
	 elseif ("DOS").same_as(system_name) then
	    garbage_collector := "windows.c"
	 elseif ("Macintosh").same_as(system_name) then
	    garbage_collector := "MacintoshPPC.c"
	 elseif ("OS2").same_as(system_name) then
	    garbage_collector := "windows.c"
	 elseif ("OpenVMS").same_as(system_name) then
	    garbage_collector := "generic.c"
	 elseif ("Cygwin").same_as(system_name) then
	    garbage_collector := "windows.c"
	 end
	 if garbage_collector = Void then
	    echo.tfr_connect(tfr,garbage_collector_file_path)
	    garbage_collector := echo.read_word_in(tfr)
	    tfr.disconnect
	    echo.put_string("Selected GC for %"")
	    echo.put_string(garbage_collector)
	    echo.put_string("%".%N")
	 else
	    echo.put_string("Selected GC for %"")
	    echo.put_string(garbage_collector)
	    echo.put_string("%".%N")
	    echo.tfw_connect(tfw,garbage_collector_file_path)
	    tfw_check_is_connected(garbage_collector_file_path)
	    tfw.put_string(garbage_collector)
	    tfw.put_character('%N')
	    tfw.disconnect
	 end
      end

   c_compiler_name: STRING
	 -- The `c_compiler_name' is one element of SYSTEM_TOOLS `compiler_list'
	 -- ("gcc", "lcc-win32", "cc", etc.).

   c_compiler_linker_options: STRING is ""
	 -- Default extra options for the C compiler/linker.

   set_c_compiler_name is
      do
	 echo.put_string("C compiler selection:%N")
	 if c_compiler_name = Void then
	    if ("Cygwin").same_as(system_name) then
	       c_compiler_name := "gcc"
	       c_compiler_linker_options.copy("-O2")
	    elseif ("Elate").same_as(system_name) then
	       c_compiler_name := "vpcc"
	    elseif ("OpenVMS").same_as(system_name) then
	       c_compiler_name := "OpenVMS_CC"
	    elseif not interactive then
	       if ("UNIX").same_as(system_name) then
		  c_compiler_name := "gcc"
		  if ("linux.c").same_as(garbage_collector) then
		     c_compiler_linker_options.copy("-pipe")
		  elseif ("sparc.c").same_as(garbage_collector) then
		     c_compiler_linker_options.copy("-pipe")
		  end
	       end
	    end
	 end
	 if c_compiler_name = Void then
	    c_compiler_name := choice_in("C compiler selection",
					 system_tools.compiler_list)
	 end
	 echo.put_string("Selected C compiler is %"")
	 echo.put_string(c_compiler_name)
	 echo.put_string("%".%N")
	 echo.put_string("Try to update %"")
	 echo.put_string(compiler_se_path)
	 echo.put_string("%".%N")
	 echo.tfw_connect(tfw,compiler_se_path)
	 tfw_check_is_connected(compiler_se_path)
	 tfw.put_string(c_compiler_name)
	 if interactive then
	    if c_compiler_linker_options.is_empty then
	       interactive_c_compiler_linker_options
	    end
	 end
	 if not c_compiler_linker_options.is_empty then
	    tfw.put_character(' ')
	    tfw.put_string(c_compiler_linker_options)
	 end
	 tfw.put_character('%N')
	 tfw.disconnect
	 echo.put_string("Update of %"")
	 echo.put_string(compiler_se_path)
	 echo.put_string("%" done.%N")
	 echo.put_string("[
            Hint: It is possible to change some default option(s) for the C
            compiler just after the compiler name in the very first line of 
            the file "
                          ]")
	 echo.put_string(compiler_se_path)
	 echo.put_string("[
	    ". For example, the very first line can be "gcc -pipe -O3".
            (If you are not an expert of C compilation, do not add any options.)
            
                          ]")
         system_tools.set_c_compiler(Void)
	 system_tools.default_c_compiler_options(true)
      end

   interactive_c_compiler_linker_options is
	 -- To set `c_compiler_linker_options' interactively.
      require
	 interactive
      do
	 std_output.put_string(
	 "-----%NIt is possible to add some default option(s) to be passed%N%
	 %to the C compiler/linker.%N")
	 if ("gcc").same_as(c_compiler_name) then
	    std_output.put_string(
	    "With gcc the -pipe option is recommended (unfortunately%N%
            %this is not supported for all platforms).%N%
            %The -pipe option is supported on all Linux platforms.%N")
	 end
	 std_output.put_string(
	 "Enter now one single line for extra option(s) or an empty line:%N")
	 std_input.read_line
	 c_compiler_linker_options.copy(std_input.last_string)
      end

   bin_directory_path: STRING
	 -- The path where binary files are to be placed. For example,
	 -- on Windows, the value may be "C:SmartEiffel\bin\"

   set_bin_directory_path is
      do
	 bin_directory_path := installation_path.twin
	 basic_directory.compute_subdirectory_with(bin_directory_path,"bin")
	 bin_directory_path := basic_directory.last_entry.twin
	 -- Because WinZip may not create an empty directory :
	 basic_directory.connect_to(bin_directory_path)
	 if basic_directory.is_connected then
	    basic_directory.disconnect
	 elseif basic_directory.create_new_directory(bin_directory_path) then
	    echo.put_string("Directory %"")
	    echo.put_string(bin_directory_path)
	    echo.put_string("%" created.%N")
	 else
	    echo.put_string("Directory %"")
	    echo.put_string(bin_directory_path)
	    echo.put_string("%" not found.%N")
	 end
      end

   bin_c_directory_path: STRING
	 -- The path where source files are to be found. For example,
	 -- on Windows, the value may be "C:SmartEiffel\bin_c\"

   set_bin_c_directory_path is
      do
	 bin_c_directory_path := installation_path.twin
	 basic_directory.compute_subdirectory_with(bin_c_directory_path,"bin_c")
	 bin_c_directory_path := basic_directory.last_entry.twin
      end

   check_system_path_variable_warning is
      local
	 do_warning: BOOLEAN
	 bin_directory, variable, content: STRING
      do
	 do_warning := true
	 bin_directory := bin_directory_path.twin
	 if (("UNIX").same_as(system_name)
	     or else
	     ("Cygwin").same_as(system_name)
	     or else
	     ("Elate").same_as(system_name))
	  then
	    if ("Elate").same_as(system_name) then
	       variable := "shell.path"
	    else
	       variable := "PATH"
	    end
	    content := echo.getenv(variable,Void)
	    if content /= Void then
	       from
		  if bin_directory.last = '/' then
		     bin_directory.remove_last(1)
		  end
		  content := content.twin
	       variant
		  content.count
	       until
		  content.count = 0
	       loop
		  if content.has_prefix(bin_directory) then
		     content.remove_first(bin_directory.count)
		     if content.count = 0 then
			do_warning := false
		     elseif content.first = ':' then
			content.clear
			do_warning := false
		     elseif content.first = '/' then
			content.remove_first(1)
			if content.count = 0 then
			   do_warning := false
			elseif content.first = ':' then
			   content.clear
			   do_warning := false
			end
		     end
		  else
		     content.remove_first(1)
		  end
	       end
	    end
	 elseif ("Windows").same_as(system_name) then
	    content := echo.getenv("PATH",Void)
	    if content /= Void then
	       from
		  if bin_directory.last = '\' then
		     bin_directory.remove_last(1)
		  end
		  bin_directory.to_lower
		  content := content.twin
		  content.to_lower
	       variant
		  content.count
	       until
		  content.count = 0
	       loop
		  if content.has_prefix(bin_directory) then
		     content.remove_first(bin_directory.count)
		     if content.count = 0 then
			do_warning := false
		     elseif content.first = ';' then
			content.clear
			do_warning := false
		     elseif content.first = '\' then
			content.remove_first(1)
			if content.count = 0 then
			   do_warning := false
			elseif content.first = ';' then
			   content.clear
			   do_warning := false
			end
		     end
		  else
		     content.remove_first(1)
		  end
	       end
	    end
	 else
	    do_warning := false
	 end
	 if do_warning then
	    std_output.put_string("Do not forget to add %"")
	    std_output.put_string(bin_directory_path)
	    std_output.put_string("%" in %Nyour %"")
	    if variable /= Void then
	       std_output.put_string(variable)
	    else
	       std_output.put_string("<PATH>")
	    end
	    std_output.put_string("%" system variable.%N")
	 end
      end

   gathered_information_summary is
      do
	 std_output.put_string("-----%N%
			       %Summary of gathered information :%N%
			       %   installation_path = %"")
	 std_output.put_string(installation_path)
	 std_output.put_string("%"%N   system_name = %"")
	 std_output.put_string(system_name)
	 std_output.put_string("%"%N   c_compiler_name = %"")
	 std_output.put_string(c_compiler_name)
	 std_output.put_string("%"%N")
	 if not c_compiler_linker_options.is_empty then
	    std_output.put_string("   c_compiler_linker_options = %"")
	    std_output.put_string(c_compiler_linker_options)
	    std_output.put_string("%"%N")
	 end
	 std_output.put_string("   garbage_collector = %"")
	 std_output.put_string(garbage_collector)
	 std_output.put_string("%"%N")
	 if interactive then
	    if not yes_or_no("Continue installation",true) then
	       std_output.put_string("SmartEiffel installation aborted.%N")
	       install_exit(exit_success_code)
	    end
	 end
	 std_output.put_string("---%NSmartEiffel's bootstrap started ...%N")
      end

   move_executable_for(name: STRING) is
	 -- Move the executable for command `name' from `bin_c_directory_path'
	 -- to in `bin_directory_path'.
      local
	 executable, old_path, new_path: STRING
      do
	 executable := name.twin
	 system_tools.add_x_suffix(executable)
	 basic_directory.compute_file_path_with(bin_c_directory_path,executable)
	 old_path := basic_directory.last_entry.twin
	 basic_directory.compute_file_path_with(bin_directory_path,executable)
	 new_path := basic_directory.last_entry.twin
	 if not file_exists(old_path) then
	    fatal_problem_description_start
	    echo.put_string("Unable to find executable %"")
	    echo.put_string(old_path)
	    echo.put_string("%".%N")
	    fatal_problem_description_end
	 end
	 if not ("Elate").same_as(system_name) then
	    echo.file_renaming(old_path,new_path)
	 else
	    -- Use the `cpt' command to copy the command from the old to the
	    -- new location.  we can't copy tools in Elate with a normal copy
	    -- in the filesystem:
	    command.copy("cpt ")
	    command.append(old_path)
	    command.extend(' ')
	    command.append(new_path)
	    std_output.put_string(command)
	    std_output.put_string("%N")
	    echo.system_call(command)
	 end
      end

   split_mode_c_compile(name: STRING) is
	 -- Assume the current working directory is `bin_c_directory_path', 
	 -- compile some command `name' produced without the "-no_split" 
	 -- flag.
      local
	 entry: STRING; i, max: INTEGER; directory: DIRECTORY
      do
	 echo.put_string("C compiling %"")
	 echo.put_string(name)
	 echo.put_string("*.c%" files.%N")
	 ace.set_executable_name(name)
	 create directory.scan_current_working_directory
	 if not directory.last_scan_status then
	    fatal_problem_description_start
	    echo.put_string("Unable to open current working directory.%N")
	    fatal_problem_description_end
	 end
	 from
	    i := directory.lower
	 until
	    i > directory.upper
	 loop
	    entry := directory.item(i).twin
	    echo_variable("entry",entry)
	    open_vms_entry_patch(entry)
	    if not entry.has_prefix(name) then
	    elseif not entry.has_suffix(".c") then
	    else
	       max := max + 1
	       system_tools.split_mode_c_compiler_command(command,entry)
	       std_output.put_string(command)
	       std_output.put_string("%N")
	       echo.system_call(command)
	    end
	    i := i + 1
	 end
	 system_tools.split_mode_linker_command(command,name,max)
	 std_output.put_string(command)
	 std_output.put_string("%N")
	 echo.system_call(command)
	 system_tools.remove_other_extra_files(name)
	 move_executable_for(name)
      end

   call_compile_to_c(options, name: STRING) is
      do
	 command.clear
	 system_tools.command_path_in(command,"compile_to_c")
	 command.extend(' ')
	 command.append(options)
	 command.append(" -o ")
	 command.append(name)
	 command.extend(' ')
	 command.append(name)
	 std_output.put_string(command)
	 std_output.put_string("%N")
	 echo.system_call(command)
      end

   prepare_bin_c_directory is
	 -- Assume the current working directory is `bin_c_directory_path',
	 -- prepare all C source files.
      local
	 i: INTEGER
	 args, item: STRING
      do
	 from
	    i := 1
	 until
	    i > no_split_command_list.count
	 loop
	    item := no_split_command_list.item(i)
	    if ("lcc-win32").same_as(c_compiler_name) then
	       args := "-boost -no_split"; -- See (*).
	    else
	       args := "-boost -no_split -no_gc"
	    end
	    call_compile_to_c(args,item)
	    i := i + 1
	 end
	 from
	    i := 1
	 until
	    i > splitted_command_list.count
	 loop
	    item := splitted_command_list.item(i)
	    if ("lcc-win32").same_as(c_compiler_name) then
	       args := "-boost"; -- See (*).
	    else
	       args := "-boost -no_gc"
	    end
	    call_compile_to_c(args,item)
	    i := i + 1
	 end
	 -- (*): because the bad/slow Microsoft malloc is used, we
	 -- get better results when the GC is on (thus the -no_gc
	 -- flag is not used).
      end

   no_split_mode_c_compile(name: STRING) is
	 -- Assume the current working directory is `bin_c_directory_path', compile some
	 -- command `name' produced with the "-no_split" flag.
      local
	 c_name: STRING
      do
	 c_name := name.twin
	 c_name.append(".c")
	 ace.set_executable_name(name)
	 system_tools.no_split_mode_command(command,c_name)
	 std_output.put_string(command)
	 std_output.put_character('%N')
	 echo.system_call(command)
	 move_executable_for(name)
      end

   no_split_command_list: ARRAY[STRING] is
	 -- Small commands which can be compiled with the -no_split flag.
      once
	 Result := <<
		     "clean",
		     "compile",
		     "finder",
		     "ace_check",
		     "print_jvm_class"
		     >>
      end

   splitted_command_list: ARRAY[STRING] is
	 -- Small commands which can be compiled with the -no_split flag.
      once
	 Result := <<
		     "compile_to_c",
		     "short",
		     "pretty"
		     "compile_to_jvm",
		     >>
      end

   c_compile_no_split_command_list is
	 -- Apply `no_split_mode_c_compile' for all names of `no_split_command_list'.
      local
	 item: STRING
	 i: INTEGER
      do
	 from
	    i := 1
	 until
	    i > no_split_command_list.count
	 loop
	    item := no_split_command_list.item(i)
	    no_split_mode_c_compile(item)
	    i := i + 1
	 end
      end

   c_compile_splitted_command_list is
	 -- Apply `splitted_mode_c_compile' for all names of `splitted_command_list'.
      local
	 item: STRING
	 i: INTEGER
      do
	 from
	    i := 1
	 until
	    i > splitted_command_list.count
	 loop
	    item := splitted_command_list.item(i)
	    split_mode_c_compile(item)
	    i := i + 1
	 end
      end

   fatal_problem_description_start is
      do
	 echo.set_verbose
	 echo.put_string(
	 "*** Fatal problem during installation of SmartEiffel.%N%
	 %    Read carefully the following information before starting%N%
	 %    again the `install' -debug command.%N%
	 %***************************************************************%N")
      end

   fatal_problem_description_end is
      do
	 echo.put_string(
	 "***************************************************************%N%
	 %Fix the previously described problem and launch again `install'.%N")
	 restore_current_working_directory
	 install_exit(exit_failure_code)
      end

   tfw_check_is_connected(path: STRING) is
      do
	 if not tfw.is_connected then
	    fatal_problem_description_start
	    echo.put_string("Cannot write file %"")
	    echo.put_string(path)
	    echo.put_string("%".%NCheck write permissions.")
	    fatal_problem_description_end
	 end
      end

   choice_in(title: STRING; names: ARRAY[STRING]): STRING is
	 -- Force some item to be selected interactively.
      local
	 i: INTEGER
	 w, n: STRING
      do
	 from
	 until
	    Result /= Void
	 loop
	    std_output.put_string(title)
	    std_output.put_string(":%N  ")
	    from
	       i := 1
	    until
	       i > names.upper
	    loop
	       std_output.put_string(names.item(i))
	       i := i + 1
	       if i <= names.upper then
		  std_output.put_string(", ")
	       end
	    end
	    std_output.put_string("%N? ")
	    std_output.flush
	    std_input.read_word
	    from
	       i := names.lower
	       w := std_input.last_string.twin
	       w.to_lower
	    until
	       i > names.upper
	    loop
	       n := names.item(i).twin
	       n.to_lower
	       if w.same_as(n) then
		  Result := names.item(i)
		  i := names.upper
	       elseif n.has_prefix(w) then
		  if Result /= Void then
		     Result := Void
		  else
		     Result := names.item(i)
		  end
	       end
	       i := i + 1
	    end
	    if Result = Void then
	       std_output.put_string("%"")
	       std_output.put_string(w)
	       std_output.put_string("%" is not a valid choice.%N")
	    end
	 end
	 std_output.put_string("selected: ")
	 std_output.put_string(Result)
	 std_output.put_string("%N")
      ensure
	 Result /= Void
	 names.fast_has(Result)
      end

   echo_usage_exit is
      do
	 echo.set_verbose
	 echo.put_string("usage: ")
	 echo.put_string(command_name)
         echo.put_string(
            " [-interactive] [-skip_c_compilation] [-cc <name>] [-debug]%N")
	 restore_current_working_directory
	 install_exit(exit_failure_code)
      end

   basic_directory: BASIC_DIRECTORY

   system_tools: SYSTEM_TOOLS is
      once
	 !!Result.install
      end

   tfr: TEXT_FILE_READ is
      once
	 !!Result.make
      end

   tfw: TEXT_FILE_WRITE is
      once
	 !!Result.make
      end

   cwd: STRING
	 -- Used to save the initial current working directory (it
	 -- must be restored before exit using `restore_current_working_directory'
	 -- because we are not always under UNIX.

   restore_current_working_directory is
      do
	 if cwd /= Void then
	    basic_directory.change_current_working_directory(cwd)
	 end
      end

   command: STRING is
      once
	 !!Result.make(512)
      end

   call_clean(name: STRING) is
      do
	 command.clear
	 system_tools.command_path_in(command,"clean")
	 command.extend(' ')
	 command.append(name)
	 std_output.put_string(command)
	 std_output.put_string("%N")
	 echo.system_call(command)
      end

   clean_bin_c_directory_path is
	 -- Assume the current working directory is `bin_c_directory_path'.
      local
	 i: INTEGER; item: STRING; directory: DIRECTORY
      do
	 from
	    i := 1
	 until
	    i > no_split_command_list.count
	 loop
	    item := no_split_command_list.item(i)
	    call_clean(item)
	    i := i + 1
	 end
	 from
	    i := 1
	 until
	    i > splitted_command_list.count
	 loop
	    item := splitted_command_list.item(i)
	    if not item.is_equal("compile_to_c") then
	       call_clean(item)
	    end
	    i := i + 1
	 end
	 -- To remove some C compiler specific files:
	 !!directory.scan_current_working_directory
	 from
	    i := directory.lower
	 until
	    i > directory.upper
	 loop
	    item := directory.item(i).twin
	    -- echo_variable("item",item)
	    open_vms_entry_patch(item)
	    if item.has_prefix("compile_to_c") then
	       inspect
		  item.last
	       when 'h', 'c', 'H', 'C' then
	       else
		  echo.file_removing(item)
	       end
	    end
	    i := i + 1
	 end
	 if ("lcc-win32").same_as(c_compiler_name) then
	    echo.put_string("In order to reset %"compile_to_c%" -no_gc in %"")
	    echo.put_string(bin_c_directory_path)
	    echo.put_string("%".%N")
	    call_clean("compile_to_c")
	    call_compile_to_c("-boost -no_gc","compile_to_c")
	    echo.remove_file("compile_to_c.bat")
	 end
      end

   yes_or_no(question: STRING; default_answer: BOOLEAN): BOOLEAN is
      local
	 answer: STRING
      do
	 std_output.put_string(question)
	 std_output.put_string(" (yes/no)?")
	 if default_answer then
	    std_output.put_string("[yes]")
	 else
	    std_output.put_string("[no]")
	 end
	 std_output.flush
	 std_input.read_line
	 answer := std_input.last_string
	 answer.to_lower
	 if answer.is_empty then
	    Result := default_answer
	 elseif (("y").is_equal(answer)
		 or else
		 ("yes").is_equal(answer)
		 or else
		 ("o").is_equal(answer)
		 or else
		 ("oui").is_equal(answer))
	  then
	    Result := true
	 elseif (("n").is_equal(answer)
		 or else
		 ("no").is_equal(answer)
		 or else
		 ("non").is_equal(answer))
	  then
	 else
	    std_output.put_string("yes or no ?%NThis is not clear.%N")
	    Result := yes_or_no(question,default_answer)
	 end
      end

   open_vms_entry_patch(entry: STRING) is
	 -- Remove the strange ;123 version suffix of the OpenVMS system.
      require
	 not entry.is_empty
      local
	 stop: BOOLEAN; s: STRING
      do
	 if ("OpenVMS").same_as(system_name) then
	    from
	       -- Because the system uses uppercase only:
	       entry.to_lower
	       s := entry.twin
	    until
	       stop
	    loop
	       if s.count = 0 then
		  stop := true
	       elseif s.last = ';' then
		  s.remove_last(1)
		  entry.copy(s)
		  stop := true
	       elseif s.last.is_decimal_digit then
		  s.remove_last(1)
	       else
		  stop := true
	       end
	    end
	    echo_variable("OpenVMS",entry)
	 end
      end

   echo_variable(name, value: STRING) is
	 -- To echo some extra -debug information.
      do
	 echo.put_string(name)
	 echo.put_string(" = %"")
	 echo.put_string(value)
	 echo.put_string("%".%N")
      end

   install_exit(exit_code: INTEGER) is
	 -- To exit properly from the `install' program.
      do
	 if system_name = Void or else ("Windows").same_as(system_name) then
	    -- To avoid to the terminal window to be erased before
	    -- the user has read previous messages.
	    std_output.put_string("Type <Enter> to continue.%N")
	    std_input.read_character
	 end
	 die_with_code(exit_code)
      end

   make is
      local
	 i: INTEGER; arg: STRING; b: BOOLEAN
      do
	 from
	    i := 1
	 until
	    i > argument_count
	 loop
	    arg := argument(i)
	    if is_version_flag(arg) then
	    elseif flag_match("debug",arg) then
	       echo.set_verbose
	    elseif flag_match("interactive",arg) then
	       interactive := true
	    elseif flag_match("skip_c_compilation",arg) then
	       skip_c_compilation := true
	    elseif flag_match("cc",arg) then
	       if i < argument_count then
		  i := i + 1
		  c_compiler_name := argument(i)
	       else
		  std_output.put_string("compiler name must be specified %
					%after %"-cc%"%N")
		  echo_usage_exit
               end
            else
   	       echo_usage_exit
            end
	    i := i + 1
	 end
	 std_output.put_string("Install of SmartEiffel started.%N")
	 if interactive then
	    interactive := yes_or_no("{
Do you want to continue the installation of SmartEiffel with
the -interactive mode activated?
Actually, there are just a few questions to answer and then
all the process is automatic.
Continue the with the -interactive mode
                                      }", true)
	 end
	 if interactive and then not echo.verbose then
	    b := yes_or_no("{
Do you want to see all what's done during the installation (i.e. to switch
on the -debug mode)?
Actually, the -debug mode is really verbose and is really useful only in
case of problem. Also note that you can always rerun this install procedure.
Add the -debug verbose option now
                            }", false)
	    if b then echo.set_verbose end
	 end
	 if not interactive then
	    std_output.put_string("Automatic installation in progress...%N")
	 end
	 echo.put_string("Version of command %"")
	 echo.put_string(command_name)
	 echo.put_string("%" is:%N")
	 echo.put_string(smart_eiffel.copyright)
	 basic_directory.connect_to_current_working_directory
	 cwd := basic_directory.last_entry.twin
	 echo_variable("CurrentWorkingDirectory",cwd)
	 if basic_directory.is_connected then
	    basic_directory.disconnect
	 end
	 set_system_se_path
	 set_installation_path
	 set_system_name
	 write_default_loadpath_se_file
	 set_compiler_se_path
	 set_garbage_collector_file_path
	 garbage_collector_selection
	 set_c_compiler_name
	 set_bin_directory_path
	 set_bin_c_directory_path
	 basic_directory.change_current_working_directory(bin_c_directory_path)
	 if basic_directory.last_entry.is_empty then
	    fatal_problem_description_start
	    echo.put_string(
	       "Unable to change current working directory %Nto %"")
	    echo.put_string(bin_c_directory_path)
	    echo.put_string("%".%N")
	    fatal_problem_description_end
	 end
	 gathered_information_summary
         if skip_c_compilation then
	 else
	    std_output.put_string("C Compiling in %"")
	    std_output.put_string(basic_directory.last_entry)
	    std_output.put_string("%".%N")
	    split_mode_c_compile("compile_to_c")
	    prepare_bin_c_directory
	    c_compile_no_split_command_list
	    c_compile_splitted_command_list
	    clean_bin_c_directory_path
	 end
	 restore_current_working_directory
	 std_output.put_string("SmartEiffel installation done.%N")
	 check_system_path_variable_warning
	 install_exit(exit_success_code)
      end

end -- INSTALL
