OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ada / gnatcmd.adb
index b754aff..c75931a 100644 (file)
@@ -6,18 +6,17 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1996-2002 Free Software Foundation, Inc.          --
+--          Copyright (C) 1996-2008, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
--- ware  Foundation;  either version 2,  or (at your option) any later ver- --
+-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
 -- OUT 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  distributed with GNAT;  see file COPYING.  If not, write --
--- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
--- MA 02111-1307, USA.                                                      --
+-- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
+-- http://www.gnu.org/licenses for a complete copy of the license.          --
 --                                                                          --
 -- GNAT was originally developed  by the GNAT team at  New York University. --
 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
 
 with Csets;
-with MLib.Tgt;
+with MLib.Tgt; use MLib.Tgt;
 with MLib.Utl;
+with MLib.Fil;
 with Namet;    use Namet;
-with Opt;
+with Opt;      use Opt;
 with Osint;    use Osint;
 with Output;
 with Prj;      use Prj;
@@ -38,10 +38,11 @@ with Prj.Env;
 with Prj.Ext;  use Prj.Ext;
 with Prj.Pars;
 with Prj.Util; use Prj.Util;
-with Sdefault; use Sdefault;
+with Sinput.P;
 with Snames;   use Snames;
-with Stringt;  use Stringt;
 with Table;
+with Targparm;
+with Tempdir;
 with Types;    use Types;
 with Hostparm; use Hostparm;
 --  Used to determine if we are in VMS or not for error message purposes
@@ -50,2258 +51,1155 @@ with Ada.Characters.Handling; use Ada.Characters.Handling;
 with Ada.Command_Line;        use Ada.Command_Line;
 with Ada.Text_IO;             use Ada.Text_IO;
 
-with Gnatvsn;
 with GNAT.OS_Lib;             use GNAT.OS_Lib;
 
-with Table;
+with VMS_Conv;                use VMS_Conv;
 
 procedure GNATCmd is
-
-   Ada_Include_Path : constant String := "ADA_INCLUDE_PATH";
-   Ada_Objects_Path : constant String := "ADA_OBJECTS_PATH";
-
+   Project_Tree      : constant Project_Tree_Ref := new Project_Tree_Data;
    Project_File      : String_Access;
    Project           : Prj.Project_Id;
    Current_Verbosity : Prj.Verbosity := Prj.Default;
    Tool_Package_Name : Name_Id       := No_Name;
 
+   B_Start : String_Ptr    := new String'("b~");
+   --  Prefix of binder generated file, changed to b__ for VMS
+
+   Old_Project_File_Used : Boolean := False;
    --  This flag indicates a switch -p (for gnatxref and gnatfind) for
-   --  an old fashioned project file. -p cannot be used in conjonction
+   --  an old fashioned project file. -p cannot be used in conjunction
    --  with -P.
 
-   Old_Project_File_Used : Boolean := False;
+   Max_Files_On_The_Command_Line : constant := 30; --  Arbitrary
 
-   --  A table to keep the switches on the command line
+   Temp_File_Name : String_Access := null;
+   --  The name of the temporary text file to put a list of source/object
+   --  files to pass to a tool, when there are more than
+   --  Max_Files_On_The_Command_Line files.
 
-   package Last_Switches is new Table.Table
+   ASIS_Main : String_Access := null;
+   --  Main for commands Check, Metric and Pretty, when -U is used
+
+   package First_Switches is new Table.Table
      (Table_Component_Type => String_Access,
       Table_Index_Type     => Integer,
       Table_Low_Bound      => 1,
       Table_Initial        => 20,
       Table_Increment      => 100,
-      Table_Name           => "Gnatcmd.Last_Switches");
-
+      Table_Name           => "Gnatcmd.First_Switches");
    --  A table to keep the switches from the project file
 
-   package First_Switches is new Table.Table
+   package Carg_Switches is new Table.Table
      (Table_Component_Type => String_Access,
       Table_Index_Type     => Integer,
       Table_Low_Bound      => 1,
       Table_Initial        => 20,
       Table_Increment      => 100,
-      Table_Name           => "Gnatcmd.First_Switches");
+      Table_Name           => "Gnatcmd.Carg_Switches");
+   --  A table to keep the switches following -cargs for ASIS tools
 
-   ------------------
-   -- SWITCH TABLE --
-   ------------------
-
-   --  The switch tables contain an entry for each switch recognized by the
-   --  command processor. The syntax of entries is as follows:
-
-   --    SWITCH_STRING ::= "/ command-qualifier-name TRANSLATION"
+   package Rules_Switches is new Table.Table
+     (Table_Component_Type => String_Access,
+      Table_Index_Type     => Integer,
+      Table_Low_Bound      => 1,
+      Table_Initial        => 20,
+      Table_Increment      => 100,
+      Table_Name           => "Gnatcmd.Rules_Switches");
+   --  A table to keep the switches following -rules for gnatcheck
 
-   --    TRANSLATION ::=
-   --      DIRECT_TRANSLATION
-   --    | DIRECTORIES_TRANSLATION
-   --    | FILE_TRANSLATION
-   --    | NO_SPACE_FILE_TRANSL
-   --    | NUMERIC_TRANSLATION
-   --    | STRING_TRANSLATION
-   --    | OPTIONS_TRANSLATION
-   --    | COMMANDS_TRANSLATION
-   --    | ALPHANUMPLUS_TRANSLATION
-   --    | OTHER_TRANSLATION
+   package Library_Paths is new Table.Table (
+     Table_Component_Type => String_Access,
+     Table_Index_Type     => Integer,
+     Table_Low_Bound      => 1,
+     Table_Initial        => 20,
+     Table_Increment      => 100,
+     Table_Name           => "Make.Library_Path");
 
-   --    DIRECT_TRANSLATION       ::= space UNIX_SWITCHES
-   --    DIRECTORIES_TRANSLATION  ::= =* UNIX_SWITCH *
-   --    DIRECTORY_TRANSLATION    ::= =% UNIX_SWITCH %
-   --    FILE_TRANSLATION         ::= =@ UNIX_SWITCH @
-   --    NO_SPACE_FILE_TRANSL     ::= =< UNIX_SWITCH >
-   --    NUMERIC_TRANSLATION      ::= =# UNIX_SWITCH # | # number #
-   --    STRING_TRANSLATION       ::= =" UNIX_SWITCH "
-   --    OPTIONS_TRANSLATION      ::= =OPTION {space OPTION}
-   --    COMMANDS_TRANSLATION     ::= =? ARGS space command-name
-   --    ALPHANUMPLUS_TRANSLATION ::= =| UNIX_SWITCH |
+   --  Packages of project files to pass to Prj.Pars.Parse, depending on the
+   --  tool. We allocate objects because we cannot declare aliased objects
+   --  as we are in a procedure, not a library level package.
 
-   --    UNIX_SWITCHES ::= UNIX_SWITCH {, UNIX_SWITCH}
+   subtype SA is String_Access;
 
-   --    UNIX_SWITCH ::= unix-switch-string | !unix-switch-string | `string'
+   Naming_String      : constant SA := new String'("naming");
+   Binder_String      : constant SA := new String'("binder");
+   Compiler_String    : constant SA := new String'("compiler");
+   Check_String       : constant SA := new String'("check");
+   Synchronize_String : constant SA := new String'("synchronize");
+   Eliminate_String   : constant SA := new String'("eliminate");
+   Finder_String      : constant SA := new String'("finder");
+   Linker_String      : constant SA := new String'("linker");
+   Gnatls_String      : constant SA := new String'("gnatls");
+   Pretty_String      : constant SA := new String'("pretty_printer");
+   Stack_String       : constant SA := new String'("stack");
+   Gnatstub_String    : constant SA := new String'("gnatstub");
+   Metric_String      : constant SA := new String'("metrics");
+   Xref_String        : constant SA := new String'("cross_reference");
 
-   --    OPTION ::= option-name space UNIX_SWITCHES
+   Packages_To_Check_By_Binder   : constant String_List_Access :=
+     new String_List'((Naming_String, Binder_String));
 
-   --    ARGS ::= -cargs | -bargs | -largs
+   Packages_To_Check_By_Check : constant String_List_Access :=
+     new String_List'((Naming_String, Check_String, Compiler_String));
 
-   --  Here command-qual is the name of the switch recognized by the GNATCmd.
-   --  This is always given in upper case in the templates, although in the
-   --  actual commands, either upper or lower case is allowed.
+   Packages_To_Check_By_Sync : constant String_List_Access :=
+     new String_List'((Naming_String, Synchronize_String, Compiler_String));
 
-   --  The unix-switch-string always starts with a minus, and has no commas
-   --  or spaces in it. Case is significant in the unix switch string. If a
-   --  unix switch string is preceded by the not sign (!) it means that the
-   --  effect of the corresponding command qualifer is to remove any previous
-   --  occurrence of the given switch in the command line.
+   Packages_To_Check_By_Eliminate : constant String_List_Access :=
+     new String_List'((Naming_String, Eliminate_String, Compiler_String));
 
-   --  The DIRECTORIES_TRANSLATION format is used where a list of directories
-   --  is given. This possible corresponding formats recognized by GNATCmd are
-   --  as shown by the following example for the case of PATH
+   Packages_To_Check_By_Finder    : constant String_List_Access :=
+     new String_List'((Naming_String, Finder_String));
 
-   --    PATH=direc
-   --    PATH=(direc,direc,direc,direc)
+   Packages_To_Check_By_Linker    : constant String_List_Access :=
+     new String_List'((Naming_String, Linker_String));
 
-   --  When more than one directory is present for the DIRECTORIES case, then
-   --  multiple instances of the corresponding unix switch are generated,
-   --  with the file name being substituted for the occurrence of *.
+   Packages_To_Check_By_Gnatls    : constant String_List_Access :=
+     new String_List'((Naming_String, Gnatls_String));
 
-   --  The FILE_TRANSLATION format is similar except that only a single
-   --  file is allowed, not a list of files, and only one unix switch is
-   --  generated as a result.
+   Packages_To_Check_By_Pretty    : constant String_List_Access :=
+     new String_List'((Naming_String, Pretty_String, Compiler_String));
 
-   --  the NO_SPACE_FILE_TRANSL is similar to FILE_TRANSLATION, except that
-   --  no space is inserted between the switch and the file name.
+   Packages_To_Check_By_Stack     : constant String_List_Access :=
+     new String_List'((Naming_String, Stack_String));
 
-   --  The NUMERIC_TRANSLATION format is similar to the FILE_TRANSLATION case
-   --  except that the parameter is a decimal integer in the range 0 to 999.
+   Packages_To_Check_By_Gnatstub  : constant String_List_Access :=
+     new String_List'((Naming_String, Gnatstub_String, Compiler_String));
 
-   --  For the OPTIONS_TRANSLATION case, GNATCmd similarly permits one or
-   --  more options to appear (although only in some cases does the use of
-   --  multiple options make logical sense). For example, taking the
-   --  case of ERRORS for GCC, the following are all allowed:
+   Packages_To_Check_By_Metric  : constant String_List_Access :=
+     new String_List'((Naming_String, Metric_String, Compiler_String));
 
-   --    /ERRORS=BRIEF
-   --    /ERRORS=(FULL,VERBOSE)
-   --    /ERRORS=(BRIEF IMMEDIATE)
+   Packages_To_Check_By_Xref      : constant String_List_Access :=
+     new String_List'((Naming_String, Xref_String));
 
-   --  If no option is provided (e.g. just /ERRORS is written), then the
-   --  first option in the list is the default option. For /ERRORS this
-   --  is NORMAL, so /ERRORS with no option is equivalent to /ERRORS=NORMAL.
+   Packages_To_Check : String_List_Access := Prj.All_Packages;
 
-   --  The COMMANDS_TRANSLATION case is only used for gnatmake, to correspond
-   --  to the use of -cargs, -bargs and -largs (the ARGS string as indicated
-   --  is one of these three possibilities). The name given by COMMAND is the
-   --  corresponding command name to be used to interprete the switches to be
-   --  passed on. Switches of this type set modes, e.g. /COMPILER_QUALIFIERS
-   --  sets the mode so that all subsequent switches, up to another switch
-   --  with COMMANDS_TRANSLATION apply to the corresponding commands issued
-   --  by the make utility. For example
+   ----------------------------------
+   -- Declarations for GNATCMD use --
+   ----------------------------------
 
-   --    /COMPILER_QUALIFIERS /LIST /BINDER_QUALIFIERS /MAIN
-   --    /COMPILER_QUALIFIERS /NOLIST /COMPILE_CHECKS=SYNTAX
+   The_Command : Command_Type;
+   --  The command specified in the invocation of the GNAT driver
 
-   --  Clearly these switches must come at the end of the list of switches
-   --  since all subsequent switches apply to an issued command.
+   Command_Arg : Positive := 1;
+   --  The index of the command in the arguments of the GNAT driver
 
-   --  For the DIRECT_TRANSLATION case, an implicit additional entry is
-   --  created by prepending NO to the name of the qualifer, and then
-   --  inverting the sense of the UNIX_SWITCHES string. For example,
-   --  given the entry:
+   My_Exit_Status : Exit_Status := Success;
+   --  The exit status of the spawned tool. Used to set the correct VMS
+   --  exit status.
 
-   --     "/LIST -gnatl"
+   Current_Work_Dir : constant String := Get_Current_Dir;
+   --  The path of the working directory
 
-   --  An implicit entry is created:
+   All_Projects : Boolean := False;
+   --  Flag used for GNAT CHECK, GNAT PRETTY, GNAT METRIC, and GNAT STACK to
+   --  indicate that the underlying tool (gnatcheck, gnatpp or gnatmetric)
+   --  should be invoked for all sources of all projects.
 
-   --     "/NOLIST !-gnatl"
+   -----------------------
+   -- Local Subprograms --
+   -----------------------
 
-   --  In the case where, a ! is already present, inverting the sense of the
-   --  switch means removing it.
+   procedure Add_To_Carg_Switches (Switch : String_Access);
+   --  Add a switch to the Carg_Switches table. If it is the first one, put the
+   --  switch "-cargs" at the beginning of the table.
+
+   procedure Add_To_Rules_Switches (Switch : String_Access);
+   --  Add a switch to the Rules_Switches table. If it is the first one, put
+   --  the switch "-crules" at the beginning of the table.
+
+   procedure Check_Files;
+   --  For GNAT LIST, GNAT PRETTY, GNAT METRIC, and GNAT STACK, check if a
+   --  project file is specified, without any file arguments. If it is the
+   --  case, invoke the GNAT tool with the proper list of files, derived from
+   --  the sources of the project.
+
+   function Check_Project
+     (Project      : Project_Id;
+      Root_Project : Project_Id) return Boolean;
+   --  Returns True if Project = Root_Project or if we want to consider all
+   --  sources of all projects. For GNAT METRIC, also returns True if Project
+   --  is extended by Root_Project.
+
+   procedure Check_Relative_Executable (Name : in out String_Access);
+   --  Check if an executable is specified as a relative path. If it is, and
+   --  the path contains directory information, fail. Otherwise, prepend the
+   --  exec directory. This procedure is only used for GNAT LINK when a project
+   --  file is specified.
+
+   function Configuration_Pragmas_File return Path_Name_Type;
+   --  Return an argument, if there is a configuration pragmas file to be
+   --  specified for Project, otherwise return No_Name. Used for gnatstub (GNAT
+   --  STUB), gnatpp (GNAT PRETTY), gnatelim (GNAT ELIM), and gnatmetric (GNAT
+   --  METRIC).
+
+   procedure Delete_Temp_Config_Files;
+   --  Delete all temporary config files. The caller is responsible for
+   --  ensuring that Keep_Temporary_Files is False.
+
+   procedure Get_Closure;
+   --  Get the sources in the closure of the ASIS_Main and add them to the
+   --  list of arguments.
 
-   subtype S is String;
-   --  A synonym to shorten the table
+   function Index (Char : Character; Str : String) return Natural;
+   --  Returns first occurrence of Char in Str, returns 0 if Char not in Str
 
-   type String_Ptr is access constant String;
-   --  String pointer type used throughout
+   procedure Non_VMS_Usage;
+   --  Display usage for platforms other than VMS
 
-   type Switches is array (Natural range <>) of String_Ptr;
-   --  Type used for array of swtiches
+   procedure Process_Link;
+   --  Process GNAT LINK, when there is a project file specified
 
-   type Switches_Ptr is access constant Switches;
+   procedure Set_Library_For
+     (Project             : Project_Id;
+      There_Are_Libraries : in out Boolean);
+   --  If Project is a library project, add the correct -L and -l switches to
+   --  the linker invocation.
 
-   --------------------------------
-   -- Switches for project files --
-   --------------------------------
+   procedure Set_Libraries is
+      new For_Every_Project_Imported (Boolean, Set_Library_For);
+   --  Add the -L and -l switches to the linker for all of the library
+   --  projects.
 
-   S_Ext_Ref      : aliased constant S := "/EXTERNAL_REFERENCE=" & '"'    &
-                                            "-X" & '"';
-
-   S_Project_File : aliased constant S := "/PROJECT_FILE=<"               &
-                                            "-P>";
-   S_Project_Verb : aliased constant S := "/PROJECT_FILE_VERBOSITY="      &
-                                            "DEFAULT "                    &
-                                               "-vP0 "                    &
-                                            "MEDIUM "                     &
-                                               "-vP1 "                    &
-                                            "HIGH "                       &
-                                               "-vP2";
-
-   ----------------------------
-   -- Switches for GNAT BIND --
-   ----------------------------
-
-   S_Bind_Bind    : aliased constant S := "/BIND_FILE="                    &
-                                            "ADA "                         &
-                                               "-A "                       &
-                                            "C "                           &
-                                               "-C";
-
-   S_Bind_Build   : aliased constant S := "/BUILD_LIBRARY=|"               &
-                                            "-L|";
-
-   S_Bind_Current : aliased constant S := "/CURRENT_DIRECTORY "            &
-                                            "!-I-";
-
-   S_Bind_Debug   : aliased constant S := "/DEBUG="                        &
-                                            "TRACEBACK "                   &
-                                               "-g2 "                      &
-                                            "ALL "                         &
-                                               "-g3 "                      &
-                                            "NONE "                        &
-                                               "-g0 "                      &
-                                            "SYMBOLS "                     &
-                                               "-g1 "                      &
-                                            "NOSYMBOLS "                   &
-                                               "!-g1 "                     &
-                                            "LINK "                        &
-                                               "-g3 "                      &
-                                            "NOTRACEBACK "                 &
-                                               "!-g2";
+   procedure Test_If_Relative_Path
+     (Switch : in out String_Access;
+      Parent : String);
+   --  Test if Switch is a relative search path switch. If it is and it
+   --  includes directory information, prepend the path with Parent. This
+   --  subprogram is only called when using project files.
 
-   S_Bind_DebugX  : aliased constant S := "/NODEBUG "                      &
-                                            "!-g";
+   --------------------------
+   -- Add_To_Carg_Switches --
+   --------------------------
 
-   S_Bind_Elab    : aliased constant S := "/ELABORATION_DEPENDENCIES "     &
-                                            "-e";
+   procedure Add_To_Carg_Switches (Switch : String_Access) is
+   begin
+      --  If the Carg_Switches table is empty, put "-cargs" at the beginning
 
-   S_Bind_Error   : aliased constant S := "/ERROR_LIMIT=#"                 &
-                                            "-m#";
+      if Carg_Switches.Last = 0 then
+         Carg_Switches.Increment_Last;
+         Carg_Switches.Table (Carg_Switches.Last) := new String'("-cargs");
+      end if;
 
-   S_Bind_Help    : aliased constant S := "/HELP "                         &
-                                            "-h";
-
-   S_Bind_Init    : aliased constant S := "/INITIALIZE_SCALARS="           &
-                                            "INVALID "                     &
-                                               "-Sin "                     &
-                                            "LOW "                         &
-                                               "-Slo "                     &
-                                            "HIGH "                        &
-                                               "-Shi";
-
-   S_Bind_Library : aliased constant S := "/LIBRARY_SEARCH=*"              &
-                                            "-aO*";
-
-   S_Bind_Linker  : aliased constant S := "/LINKER_OPTION_LIST "           &
-                                            "-K";
-
-   S_Bind_List    : aliased constant S := "/LIST_RESTRICTIONS "            &
-                                            "-r";
-
-   S_Bind_Main    : aliased constant S := "/MAIN "                         &
-                                            "!-n";
-
-   S_Bind_Nostinc : aliased constant S := "/NOSTD_INCLUDES "               &
-                                            "-nostdinc";
-
-   S_Bind_Nostlib : aliased constant S := "/NOSTD_LIBRARIES "              &
-                                            "-nostdlib";
-
-   S_Bind_No_Time : aliased constant S := "/NO_TIME_STAMP_CHECK "          &
-                                            "-t";
-
-   S_Bind_Object  : aliased constant S := "/OBJECT_LIST "                  &
-                                            "-O";
-
-   S_Bind_Order   : aliased constant S := "/ORDER_OF_ELABORATION "         &
-                                            "-l";
-
-   S_Bind_Output  : aliased constant S := "/OUTPUT=@"                      &
-                                            "-o@";
-
-   S_Bind_OutputX : aliased constant S := "/NOOUTPUT "                     &
-                                            "-c";
-
-   S_Bind_Pess    : aliased constant S := "/PESSIMISTIC_ELABORATION "      &
-                                            "-p";
-
-   S_Bind_Read    : aliased constant S := "/READ_SOURCES="                 &
-                                            "ALL "                         &
-                                               "-s "                       &
-                                            "NONE "                        &
-                                               "-x "                       &
-                                            "AVAILABLE "                   &
-                                               "!-x,!-s";
-
-   S_Bind_ReadX   : aliased constant S := "/NOREAD_SOURCES "               &
-                                            "-x";
-
-   S_Bind_Rename  : aliased constant S := "/RENAME_MAIN=<"                  &
-                                            "-M>";
-
-   S_Bind_Report  : aliased constant S := "/REPORT_ERRORS="                &
-                                            "VERBOSE "                     &
-                                               "-v "                       &
-                                            "BRIEF "                       &
-                                               "-b "                       &
-                                            "DEFAULT "                     &
-                                               "!-b,!-v";
-
-   S_Bind_ReportX : aliased constant S := "/NOREPORT_ERRORS "              &
-                                            "!-b,!-v";
-
-   S_Bind_Restr   : aliased constant S := "/RESTRICTION_LIST "             &
-                                            "-r";
-
-   S_Bind_RTS     : aliased constant S := "/RUNTIME_SYSTEM=|"              &
-                                            "--RTS=|";
-
-   S_Bind_Search  : aliased constant S := "/SEARCH=*"                      &
-                                            "-I*";
-
-   S_Bind_Shared  : aliased constant S := "/SHARED "                       &
-                                            "-shared";
-
-   S_Bind_Slice   : aliased constant S := "/TIME_SLICE=#"                  &
-                                            "-T#";
-
-   S_Bind_Source  : aliased constant S := "/SOURCE_SEARCH=*"               &
-                                            "-aI*";
-
-   S_Bind_Time    : aliased constant S := "/TIME_STAMP_CHECK "             &
-                                            "!-t";
-
-   S_Bind_Verbose : aliased constant S := "/VERBOSE "                      &
-                                            "-v";
-
-   S_Bind_Warn    : aliased constant S := "/WARNINGS="                     &
-                                            "NORMAL "                      &
-                                               "!-ws,!-we "                &
-                                            "SUPPRESS "                    &
-                                               "-ws "                      &
-                                            "ERROR "                       &
-                                               "-we";
-
-   S_Bind_WarnX   : aliased constant S := "/NOWARNINGS "                   &
-     "-ws";
-
-   Bind_Switches : aliased constant Switches :=
-     (S_Bind_Bind    'Access,
-      S_Bind_Build   'Access,
-      S_Bind_Current 'Access,
-      S_Bind_Debug   'Access,
-      S_Bind_DebugX  'Access,
-      S_Bind_Elab    'Access,
-      S_Bind_Error   'Access,
-      S_Ext_Ref      'Access,
-      S_Bind_Help    'Access,
-      S_Bind_Init    'Access,
-      S_Bind_Library 'Access,
-      S_Bind_Linker  'Access,
-      S_Bind_List    'Access,
-      S_Bind_Main    'Access,
-      S_Bind_Nostinc 'Access,
-      S_Bind_Nostlib 'Access,
-      S_Bind_No_Time 'Access,
-      S_Bind_Object  'Access,
-      S_Bind_Order   'Access,
-      S_Bind_Output  'Access,
-      S_Bind_OutputX 'Access,
-      S_Bind_Pess    'Access,
-      S_Project_File 'Access,
-      S_Project_Verb 'Access,
-      S_Bind_Read    'Access,
-      S_Bind_ReadX   'Access,
-      S_Bind_Rename  'Access,
-      S_Bind_Report  'Access,
-      S_Bind_ReportX 'Access,
-      S_Bind_Restr   'Access,
-      S_Bind_RTS     'Access,
-      S_Bind_Search  'Access,
-      S_Bind_Shared  'Access,
-      S_Bind_Slice   'Access,
-      S_Bind_Source  'Access,
-      S_Bind_Time    'Access,
-      S_Bind_Verbose 'Access,
-      S_Bind_Warn    'Access,
-      S_Bind_WarnX   'Access);
-
-   ----------------------------
-   -- Switches for GNAT CHOP --
-   ----------------------------
-
-   S_Chop_Comp   : aliased constant S := "/COMPILATION "                   &
-                                            "-c";
-
-   S_Chop_File   : aliased constant S := "/FILE_NAME_MAX_LENGTH=#"         &
-                                            "-k#";
-
-   S_Chop_Help   : aliased constant S := "/HELP "                          &
-                                            "-h";
-
-   S_Chop_Over   : aliased constant S := "/OVERWRITE "                     &
-                                            "-w";
-
-   S_Chop_Pres   : aliased constant S := "/PRESERVE "                      &
-                                            "-p";
-
-   S_Chop_Quiet  : aliased constant S := "/QUIET "                         &
-                                            "-q";
-
-   S_Chop_Ref    : aliased constant S := "/REFERENCE "                     &
-                                            "-r";
-
-   S_Chop_Verb   : aliased constant S := "/VERBOSE "                       &
-                                            "-v";
-
-   Chop_Switches : aliased constant Switches :=
-     (S_Chop_Comp   'Access,
-      S_Chop_File   'Access,
-      S_Chop_Help   'Access,
-      S_Chop_Over   'Access,
-      S_Chop_Pres   'Access,
-      S_Chop_Quiet  'Access,
-      S_Chop_Ref    'Access,
-      S_Chop_Verb   'Access);
+      Carg_Switches.Increment_Last;
+      Carg_Switches.Table (Carg_Switches.Last) := Switch;
+   end Add_To_Carg_Switches;
 
-   -------------------------------
-   -- Switches for GNAT COMPILE --
-   -------------------------------
+   ---------------------------
+   -- Add_To_Rules_Switches --
+   ---------------------------
 
-   S_GCC_Ada_83  : aliased constant S := "/83 "                            &
-                                             "-gnat83";
-
-   S_GCC_Ada_95  : aliased constant S := "/95 "                            &
-                                             "!-gnat83";
-
-   S_GCC_Asm     : aliased constant S := "/ASM "                           &
-                                             "-S,!-c";
-
-   S_GCC_Checks  : aliased constant S := "/CHECKS="                        &
-                                             "FULL "                       &
-                                                "-gnato,!-gnatE,!-gnatp "  &
-                                             "OVERFLOW "                   &
-                                                "-gnato "                  &
-                                             "ELABORATION "                &
-                                                "-gnatE "                  &
-                                             "ASSERTIONS "                 &
-                                                "-gnata "                  &
-                                             "DEFAULT "                    &
-                                                "!-gnato,!-gnatp "         &
-                                             "SUPPRESS_ALL "               &
-                                                "-gnatp";
-
-   S_GCC_ChecksX : aliased constant S := "/NOCHECKS "                      &
-                                             "-gnatp,!-gnato,!-gnatE";
-
-   S_GCC_Compres : aliased constant S := "/COMPRESS_NAMES "                &
-                                             "-gnatC";
-
-   S_GCC_Config  : aliased constant S := "/CONFIGURATION_PRAGMAS_FILE=<"   &
-                                             "-gnatec>";
-
-   S_GCC_Current : aliased constant S := "/CURRENT_DIRECTORY "             &
-                                             "!-I-";
-
-   S_GCC_Debug   : aliased constant S := "/DEBUG="                         &
-                                            "SYMBOLS "                     &
-                                               "-g2 "                      &
-                                            "NOSYMBOLS "                   &
-                                               "!-g2 "                     &
-                                            "TRACEBACK "                   &
-                                               "-g1 "                      &
-                                            "ALL "                         &
-                                               "-g3 "                      &
-                                            "NONE "                        &
-                                               "-g0 "                      &
-                                            "NOTRACEBACK "                 &
-                                               "-g0";
-
-   S_GCC_DebugX  : aliased constant S := "/NODEBUG "                       &
-                                             "!-g";
-
-   S_GCC_Dist    : aliased constant S := "/DISTRIBUTION_STUBS="            &
-                                            "RECEIVER "                    &
-                                               "-gnatzr "                  &
-                                            "CALLER "                      &
-                                              "-gnatzc";
-
-   S_GCC_DistX   : aliased constant S := "/NODISTRIBUTION_STUBS "          &
-                                            "!-gnatzr,!-gnatzc";
-
-   S_GCC_Error   : aliased constant S := "/ERROR_LIMIT=#"                  &
-                                            "-gnatm#";
-
-   S_GCC_ErrorX  : aliased constant S := "/NOERROR_LIMIT "                 &
-                                            "-gnatm999";
-
-   S_GCC_Expand  : aliased constant S := "/EXPAND_SOURCE "                 &
-                                            "-gnatG";
-
-   S_GCC_Extend  : aliased constant S := "/EXTENSIONS_ALLOWED "            &
-                                            "-gnatX";
-
-   S_GCC_File    : aliased constant S := "/FILE_NAME_MAX_LENGTH=#"         &
-                                            "-gnatk#";
-
-   S_GCC_Force   : aliased constant S := "/FORCE_ALI "                     &
-                                            "-gnatQ";
-
-   S_GCC_Help    : aliased constant S := "/HELP "                     &
-                                            "-gnath";
-
-   S_GCC_Ident   : aliased constant S := "/IDENTIFIER_CHARACTER_SET="      &
-                                             "DEFAULT "                    &
-                                                "-gnati1 "                 &
-                                             "1 "                          &
-                                                "-gnati1 "                 &
-                                             "2 "                          &
-                                                "-gnati2 "                 &
-                                             "3 "                          &
-                                                "-gnati3 "                 &
-                                             "4 "                          &
-                                                "-gnati4 "                 &
-                                             "5 "                          &
-                                                "-gnati5 "                 &
-                                             "PC "                         &
-                                                "-gnatip "                 &
-                                             "PC850 "                      &
-                                                "-gnati8 "                 &
-                                             "FULL_UPPER "                 &
-                                                "-gnatif "                 &
-                                             "NO_UPPER "                   &
-                                                "-gnatin "                 &
-                                             "WIDE "                       &
-                                                "-gnatiw";
-
-   S_GCC_IdentX  : aliased constant S := "/NOIDENTIFIER_CHARACTER_SET "    &
-                                             "-gnati1";
-
-   S_GCC_Immed   : aliased constant S := "/IMMEDIATE_ERRORS "    &
-                                             "-gnatdO";
-
-   S_GCC_Inline  : aliased constant S := "/INLINE="                        &
-                                            "PRAGMA "                      &
-                                              "-gnatn "                    &
-                                            "FULL "                        &
-                                              "-gnatN "                    &
-                                            "SUPPRESS "                    &
-                                              "-fno-inline";
-
-   S_GCC_InlineX : aliased constant S := "/NOINLINE "                      &
-                                             "!-gnatn";
-
-   S_GCC_Jumps   : aliased constant S := "/LONGJMP_SETJMP "                &
-                                             "-gnatL";
-
-   S_GCC_Length  : aliased constant S := "/MAX_LINE_LENGTH=#"              &
-                                             "-gnatyM#";
-
-   S_GCC_List    : aliased constant S := "/LIST "                          &
-                                             "-gnatl";
-
-   S_GCC_Noadc   : aliased constant S := "/NO_GNAT_ADC "                   &
-                                             "-gnatA";
-
-   S_GCC_Noload  : aliased constant S := "/NOLOAD "                        &
-                                             "-gnatc";
-
-   S_GCC_Nostinc : aliased constant S := "/NOSTD_INCLUDES "                &
-                                             "-nostdinc";
-
-   S_GCC_Opt     : aliased constant S := "/OPTIMIZE="                      &
-                                            "ALL "                         &
-                                               "-O2,!-O0,!-O1,!-O3 "       &
-                                            "NONE "                        &
-                                               "-O0,!-O1,!-O2,!-O3 "       &
-                                            "SOME "                        &
-                                               "-O1,!-O0,!-O2,!-O3 "       &
-                                            "DEVELOPMENT "                 &
-                                               "-O1,!-O0,!-O2,!-O3 "       &
-                                            "UNROLL_LOOPS "                &
-                                               "-funroll-loops "           &
-                                            "INLINING "                    &
-                                               "-O3,!-O0,!-O1,!-O2";
-
-   S_GCC_OptX    : aliased constant S := "/NOOPTIMIZE "                    &
-                                            "-O0,!-O1,!-O2,!-O3";
-
-   S_GCC_Polling : aliased constant S := "/POLLING "                       &
-                                            "-gnatP";
-
-   S_GCC_Report  : aliased constant S := "/REPORT_ERRORS="                 &
-                                            "VERBOSE "                     &
-                                               "-gnatv "                   &
-                                            "BRIEF "                       &
-                                               "-gnatb "                   &
-                                            "FULL "                        &
-                                               "-gnatf "                   &
-                                            "IMMEDIATE "                   &
-                                               "-gnate "                   &
-                                            "DEFAULT "                     &
-                                               "!-gnatb,!-gnatv";
-
-   S_GCC_ReportX : aliased constant S := "/NOREPORT_ERRORS "               &
-                                            "!-gnatb,!-gnatv";
-
-   S_GCC_Repinfo : aliased constant S := "/REPRESENTATION_INFO="           &
-                                            "ARRAYS "                      &
-                                               "-gnatR1 "                  &
-                                            "NONE "                        &
-                                               "-gnatR0 "                  &
-                                            "OBJECTS "                     &
-                                               "-gnatR2 "                  &
-                                            "SYMBOLIC "                    &
-                                               "-gnatR3 "                  &
-                                            "DEFAULT "                     &
-                                               "-gnatR";
-
-   S_GCC_RepinfX : aliased constant S := "/NOREPRESENTATION_INFO "         &
-                                            "!-gnatR";
-
-   S_GCC_Search  : aliased constant S := "/SEARCH=*"                       &
-                                            "-I*";
-
-   S_GCC_Style   : aliased constant S := "/STYLE_CHECKS="                  &
-                                            "ALL_BUILTIN "                 &
-                                               "-gnaty "                   &
-                                            "1 "                           &
-                                               "-gnaty1 "                  &
-                                            "2 "                           &
-                                               "-gnaty2 "                  &
-                                            "3 "                           &
-                                               "-gnaty3 "                  &
-                                            "4 "                           &
-                                               "-gnaty4 "                  &
-                                            "5 "                           &
-                                               "-gnaty5 "                  &
-                                            "6 "                           &
-                                               "-gnaty6 "                  &
-                                            "7 "                           &
-                                               "-gnaty7 "                  &
-                                            "8 "                           &
-                                               "-gnaty8 "                  &
-                                            "9 "                           &
-                                               "-gnaty9 "                  &
-                                            "ATTRIBUTE "                   &
-                                               "-gnatya "                  &
-                                            "BLANKS "                      &
-                                               "-gnatyb "                  &
-                                            "COMMENTS "                    &
-                                               "-gnatyc "                  &
-                                            "END "                         &
-                                               "-gnatye "                  &
-                                            "VTABS "                       &
-                                               "-gnatyf "                  &
-                                            "GNAT "                        &
-                                               "-gnatg "                   &
-                                            "HTABS "                       &
-                                               "-gnatyh "                  &
-                                            "IF_THEN "                     &
-                                               "-gnatyi "                  &
-                                            "KEYWORD "                     &
-                                               "-gnatyk "                  &
-                                            "LAYOUT "                      &
-                                               "-gnatyl "                  &
-                                            "LINE_LENGTH "                 &
-                                               "-gnatym "                  &
-                                            "STANDARD_CASING "             &
-                                               "-gnatyn "                  &
-                                            "ORDERED_SUBPROGRAMS "         &
-                                               "-gnatyo "                  &
-                                            "NONE "                        &
-                                               "!-gnatg,!-gnatr "          &
-                                            "PRAGMA "                      &
-                                               "-gnatyp "                  &
-                                            "RM_COLUMN_LAYOUT "            &
-                                               "-gnatr "                   &
-                                            "SPECS "                       &
-                                               "-gnatys "                  &
-                                            "TOKEN "                       &
-                                               "-gnatyt ";
-
-   S_GCC_StyleX  : aliased constant S := "/NOSTYLE_CHECKS "                &
-                                            "!-gnatg,!-gnatr";
-
-   S_GCC_Syntax  : aliased constant S := "/SYNTAX_ONLY "                   &
-                                            "-gnats";
-
-   S_GCC_Trace   : aliased constant S := "/TRACE_UNITS "                   &
-                                            "-gnatdc";
-
-   S_GCC_Tree    : aliased constant S := "/TREE_OUTPUT "                   &
-                                            "-gnatt";
-
-   S_GCC_Trys    : aliased constant S := "/TRY_SEMANTICS "                 &
-                                            "-gnatq";
-
-   S_GCC_Units   : aliased constant S := "/UNITS_LIST "                    &
-                                            "-gnatu";
-
-   S_GCC_Unique  : aliased constant S := "/UNIQUE_ERROR_TAG "              &
-                                            "-gnatU";
-
-   S_GCC_Upcase  : aliased constant S := "/UPPERCASE_EXTERNALS "           &
-                                            "-gnatF";
-
-   S_GCC_Valid   : aliased constant S := "/VALIDITY_CHECKING="             &
-                                            "DEFAULT "                     &
-                                               "-gnatVd "                  &
-                                            "NODEFAULT "                   &
-                                               "-gnatVD "                  &
-                                            "COPIES "                      &
-                                               "-gnatVc "                  &
-                                            "NOCOPIES "                    &
-                                               "-gnatVC "                  &
-                                            "FLOATS "                      &
-                                               "-gnatVf "                  &
-                                            "NOFLOATS "                    &
-                                               "-gnatVF "                  &
-                                            "IN_PARAMS "                   &
-                                               "-gnatVi "                  &
-                                            "NOIN_PARAMS "                 &
-                                               "-gnatVI "                  &
-                                            "MOD_PARAMS "                  &
-                                               "-gnatVm "                  &
-                                            "NOMOD_PARAMS "                &
-                                               "-gnatVM "                  &
-                                            "OPERANDS "                    &
-                                               "-gnatVo "                  &
-                                            "NOOPERANDS "                  &
-                                               "-gnatVO "                  &
-                                            "RETURNS "                     &
-                                               "-gnatVr "                  &
-                                            "NORETURNS "                   &
-                                               "-gnatVR "                  &
-                                            "SUBSCRIPTS "                  &
-                                               "-gnatVs "                  &
-                                            "NOSUBSCRIPTS "                &
-                                               "-gnatVS "                  &
-                                            "TESTS "                       &
-                                               "-gnatVt "                  &
-                                            "NOTESTS "                     &
-                                               "-gnatVT "                  &
-                                            "ALL "                         &
-                                               "-gnatVa "                  &
-                                            "NONE "                        &
-                                               "-gnatVn";
-
-   S_GCC_Verbose : aliased constant S := "/VERBOSE "                       &
-                                            "-v";
-
-   S_GCC_Warn    : aliased constant S := "/WARNINGS="                      &
-                                            "DEFAULT "                     &
-                                               "!-gnatws,!-gnatwe "        &
-                                            "ALL_GCC "                     &
-                                               "-Wall "                    &
-                                            "BIASED_ROUNDING "             &
-                                               "-gnatwb "                  &
-                                            "NOBIASED_ROUNDING "           &
-                                               "-gnatwB "                  &
-                                            "CONDITIONALS "                &
-                                               "-gnatwc "                  &
-                                            "NOCONDITIONALS "              &
-                                               "-gnatwC "                  &
-                                            "IMPLICIT_DEREFERENCE "        &
-                                               "-gnatwd "                  &
-                                            "NO_IMPLICIT_DEREFERENCE "     &
-                                               "-gnatwD "                  &
-                                            "ELABORATION "                 &
-                                               "-gnatwl "                  &
-                                            "NOELABORATION "               &
-                                               "-gnatwL "                  &
-                                            "ERRORS "                      &
-                                               "-gnatwe "                  &
-                                            "HIDING "                      &
-                                               "-gnatwh "                  &
-                                            "NOHIDING "                    &
-                                               "-gnatwH "                  &
-                                            "IMPLEMENTATION "              &
-                                               "-gnatwi "                  &
-                                            "NOIMPLEMENTATION "            &
-                                               "-gnatwI "                  &
-                                            "INEFFECTIVE_INLINE "          &
-                                               "-gnatwp "                  &
-                                            "NOINEFFECTIVE_INLINE "        &
-                                               "-gnatwP "                  &
-                                            "OPTIONAL "                    &
-                                               "-gnatwa "                  &
-                                            "NOOPTIONAL "                  &
-                                               "-gnatwA "                  &
-                                            "OVERLAYS "                    &
-                                               "-gnatwo "                  &
-                                            "NOOVERLAYS "                  &
-                                               "-gnatwO "                  &
-                                            "REDUNDANT "                   &
-                                               "-gnatwr "                  &
-                                            "NOREDUNDANT "                 &
-                                               "-gnatwR "                  &
-                                            "SUPPRESS "                    &
-                                               "-gnatws "                  &
-                                            "UNINITIALIZED "               &
-                                               "-Wuninitialized "          &
-                                            "UNREFERENCED_FORMALS "        &
-                                               "-gnatwf "                  &
-                                            "NOUNREFERENCED_FORMALS "      &
-                                               "-gnatwF "                  &
-                                            "UNUSED "                      &
-                                               "-gnatwu "                  &
-                                            "NOUNUSED "                    &
-                                               "-gnatwU";
-
-   S_GCC_WarnX   : aliased constant S := "/NOWARNINGS "                    &
-                                            "-gnatws";
-
-   S_GCC_Wide    : aliased constant S := "/WIDE_CHARACTER_ENCODING="       &
-                                             "BRACKETS "                   &
-                                                "-gnatWb "                 &
-                                             "NONE "                       &
-                                                "-gnatWn "                 &
-                                             "HEX "                        &
-                                                "-gnatWh "                 &
-                                             "UPPER "                      &
-                                                "-gnatWu "                 &
-                                             "SHIFT_JIS "                  &
-                                                "-gnatWs "                 &
-                                             "UTF8 "                       &
-                                                "-gnatW8 "                 &
-                                             "EUC "                        &
-                                                "-gnatWe";
-
-   S_GCC_WideX   : aliased constant S := "/NOWIDE_CHARACTER_ENCODING "     &
-                                             "-gnatWn";
-
-   S_GCC_Xdebug  : aliased constant S := "/XDEBUG "                        &
-                                             "-gnatD";
-
-   S_GCC_Xref    : aliased constant S := "/XREF="                          &
-                                            "GENERATE "                    &
-                                               "!-gnatx "                  &
-                                            "SUPPRESS "                    &
-                                               "-gnatx";
-
-   GCC_Switches : aliased constant Switches :=
-     (S_GCC_Ada_83  'Access,
-      S_GCC_Ada_95  'Access,
-      S_GCC_Asm     'Access,
-      S_GCC_Checks  'Access,
-      S_GCC_ChecksX 'Access,
-      S_GCC_Compres 'Access,
-      S_GCC_Config  'Access,
-      S_GCC_Current 'Access,
-      S_GCC_Debug   'Access,
-      S_GCC_DebugX  'Access,
-      S_GCC_Dist    'Access,
-      S_GCC_DistX   'Access,
-      S_GCC_Error   'Access,
-      S_GCC_ErrorX  'Access,
-      S_GCC_Expand  'Access,
-      S_GCC_Extend  'Access,
-      S_Ext_Ref     'Access,
-      S_GCC_File    'Access,
-      S_GCC_Force   'Access,
-      S_GCC_Help    'Access,
-      S_GCC_Ident   'Access,
-      S_GCC_IdentX  'Access,
-      S_GCC_Immed   'Access,
-      S_GCC_Inline  'Access,
-      S_GCC_InlineX 'Access,
-      S_GCC_Jumps   'Access,
-      S_GCC_Length  'Access,
-      S_GCC_List    'Access,
-      S_GCC_Noadc   'Access,
-      S_GCC_Noload  'Access,
-      S_GCC_Nostinc 'Access,
-      S_GCC_Opt     'Access,
-      S_GCC_OptX    'Access,
-      S_GCC_Polling 'Access,
-      S_Project_File'Access,
-      S_Project_Verb'Access,
-      S_GCC_Report  'Access,
-      S_GCC_ReportX 'Access,
-      S_GCC_Repinfo 'Access,
-      S_GCC_RepinfX 'Access,
-      S_GCC_Search  'Access,
-      S_GCC_Style   'Access,
-      S_GCC_StyleX  'Access,
-      S_GCC_Syntax  'Access,
-      S_GCC_Trace   'Access,
-      S_GCC_Tree    'Access,
-      S_GCC_Trys    'Access,
-      S_GCC_Units   'Access,
-      S_GCC_Unique  'Access,
-      S_GCC_Upcase  'Access,
-      S_GCC_Valid   'Access,
-      S_GCC_Verbose 'Access,
-      S_GCC_Warn    'Access,
-      S_GCC_WarnX   'Access,
-      S_GCC_Wide    'Access,
-      S_GCC_WideX   'Access,
-      S_GCC_Xdebug  'Access,
-      S_GCC_Xref    'Access);
-
-   ----------------------------
-   -- Switches for GNAT ELIM --
-   ----------------------------
-
-   S_Elim_All    : aliased constant S := "/ALL "                           &
-                                            "-a";
-
-   S_Elim_Bind   : aliased constant S := "/BIND_FILE=<"                    &
-                                            "-b>";
-
-   S_Elim_Miss   : aliased constant S := "/MISSED "                        &
-                                            "-m";
-
-   S_Elim_Quiet  : aliased constant S := "/QUIET "                         &
-                                            "-q";
-
-   S_Elim_Tree   : aliased constant S := "/TREE_DIRS=*"                    &
-                                            "-T*";
-
-   S_Elim_Verb   : aliased constant S := "/VERBOSE "                       &
-                                            "-v";
-
-   Elim_Switches : aliased constant Switches :=
-     (S_Elim_All    'Access,
-      S_Elim_Bind   'Access,
-      S_Elim_Miss   'Access,
-      S_Elim_Quiet  'Access,
-      S_Elim_Tree   'Access,
-      S_Elim_Verb   'Access);
-
-   ----------------------------
-   -- Switches for GNAT FIND --
-   ----------------------------
-
-   S_Find_All     : aliased constant S := "/ALL_FILES "                    &
-                                            "-a";
-
-   S_Find_Deriv   : aliased constant S := "/DERIVED_TYPE_INFORMATION "     &
-                                            "-d";
-
-   S_Find_Expr    : aliased constant S := "/EXPRESSIONS "                  &
-                                            "-e";
-
-   S_Find_Full    : aliased constant S := "/FULL_PATHNAME "                &
-                                            "-f";
-
-   S_Find_Ignore  : aliased constant S := "/IGNORE_LOCALS "                &
-                                            "-g";
-
-   S_Find_Nostinc : aliased constant S := "/NOSTD_INCLUDES "               &
-                                            "-nostdinc";
-
-   S_Find_Nostlib : aliased constant S := "/NOSTD_LIBRARIES "              &
-                                            "-nostdlib";
-
-   S_Find_Object  : aliased constant S := "/OBJECT_SEARCH=*"               &
-                                            "-aO*";
-
-   S_Find_Print   : aliased constant S := "/PRINT_LINES "                  &
-                                            "-s";
-
-   S_Find_Project : aliased constant S := "/PROJECT=@"                     &
-                                            "-p@";
-
-   S_Find_Ref     : aliased constant S := "/REFERENCES "                   &
-                                            "-r";
-
-   S_Find_Search  : aliased constant S := "/SEARCH=*"                      &
-                                            "-I*";
-
-   S_Find_Source  : aliased constant S := "/SOURCE_SEARCH=*"               &
-                                            "-aI*";
-
-   S_Find_Types   : aliased constant S := "/TYPE_HIERARCHY "               &
-                                            "-t";
-
-   Find_Switches : aliased constant Switches :=
-     (S_Find_All     'Access,
-      S_Find_Deriv   'Access,
-      S_Find_Expr    'Access,
-      S_Ext_Ref      'Access,
-      S_Find_Full    'Access,
-      S_Find_Ignore  'Access,
-      S_Find_Nostinc 'Access,
-      S_Find_Nostlib 'Access,
-      S_Find_Object  'Access,
-      S_Find_Print   'Access,
-      S_Find_Project 'Access,
-      S_Project_File 'Access,
-      S_Project_Verb 'Access,
-      S_Find_Ref     'Access,
-      S_Find_Search  'Access,
-      S_Find_Source  'Access,
-      S_Find_Types   'Access);
+   procedure Add_To_Rules_Switches (Switch : String_Access) is
+   begin
+      --  If the Rules_Switches table is empty, put "-rules" at the beginning
 
-   ------------------------------
-   -- Switches for GNAT KRUNCH --
-   ------------------------------
+      if Rules_Switches.Last = 0 then
+         Rules_Switches.Increment_Last;
+         Rules_Switches.Table (Rules_Switches.Last) := new String'("-rules");
+      end if;
 
-   S_Krunch_Count  : aliased constant S := "/COUNT=#"                      &
-                                            "`#";
+      Rules_Switches.Increment_Last;
+      Rules_Switches.Table (Rules_Switches.Last) := Switch;
+   end Add_To_Rules_Switches;
 
-   Krunch_Switches : aliased constant Switches  :=
-     (1 .. 1 => S_Krunch_Count  'Access);
+   -----------------
+   -- Check_Files --
+   -----------------
 
-   -------------------------------
-   -- Switches for GNAT LIBRARY --
-   -------------------------------
+   procedure Check_Files is
+      Add_Sources : Boolean := True;
+      Unit_Data   : Prj.Unit_Data;
+      Subunit     : Boolean := False;
 
-   S_Lbr_Config    : aliased constant S := "/CONFIG=@"                     &
-                                            "--config=@";
-
-   S_Lbr_Create    : aliased constant S := "/CREATE=%"                     &
-                                            "--create=%";
-
-   S_Lbr_Delete    : aliased constant S := "/DELETE=%"                     &
-                                            "--delete=%";
-
-   S_Lbr_Set       : aliased constant S := "/SET=%"                        &
-                                            "--set=%";
-
-   Lbr_Switches : aliased constant Switches  :=
-     (S_Lbr_Config 'Access,
-      S_Lbr_Create 'Access,
-      S_Lbr_Delete 'Access,
-      S_Lbr_Set    'Access);
-
-   ----------------------------
-   -- Switches for GNAT LINK --
-   ----------------------------
-
-   S_Link_Bind    : aliased constant S := "/BIND_FILE="                    &
-                                            "ADA "                         &
-                                               "-A "                       &
-                                            "C "                           &
-                                               "-C";
-
-   S_Link_Debug   : aliased constant S := "/DEBUG="                        &
-                                            "ALL "                         &
-                                               "-g3 "                      &
-                                            "NONE "                        &
-                                               "-g0 "                      &
-                                            "TRACEBACK "                   &
-                                               "-g1 "                      &
-                                            "NOTRACEBACK "                 &
-                                               "-g0";
-
-   S_Link_Execut  : aliased constant S := "/EXECUTABLE=@"                  &
-                                            "-o@";
-
-   S_Link_Force   : aliased constant S := "/FORCE_OBJECT_FILE_LIST "       &
-                                            "-f";
-
-   S_Link_Ident   : aliased constant S := "/IDENTIFICATION=" & '"'         &
-                                            "--for-linker=IDENT="          &
-                                            '"';
-
-   S_Link_Nocomp  : aliased constant S := "/NOCOMPILE "                    &
-                                            "-n";
-
-   S_Link_Nofiles : aliased constant S := "/NOSTART_FILES "                &
-                                            "-nostartfiles";
-
-   S_Link_Noinhib : aliased constant S := "/NOINHIBIT-EXEC "               &
-                                            "--for-linker=--noinhibit-exec";
-
-   S_Link_Static  : aliased constant S := "/STATIC "                       &
-                                            "--for-linker=-static";
-
-   S_Link_Verb    : aliased constant S := "/VERBOSE "                      &
-                                            "-v";
-
-   S_Link_ZZZZZ   : aliased constant S := "/<other> "                      &
-                                            "--for-linker=";
-
-   Link_Switches : aliased constant Switches :=
-     (S_Link_Bind    'Access,
-      S_Link_Debug   'Access,
-      S_Link_Execut  'Access,
-      S_Ext_Ref      'Access,
-      S_Link_Force   'Access,
-      S_Link_Ident   'Access,
-      S_Link_Nocomp  'Access,
-      S_Link_Nofiles 'Access,
-      S_Link_Noinhib 'Access,
-      S_Project_File 'Access,
-      S_Project_Verb 'Access,
-      S_Link_Static  'Access,
-      S_Link_Verb    'Access,
-      S_Link_ZZZZZ   'Access);
-
-   ----------------------------
-   -- Switches for GNAT LIST --
-   ----------------------------
-
-   S_List_All     : aliased constant S := "/ALL_UNITS "                    &
-                                            "-a";
-
-   S_List_Current : aliased constant S := "/CURRENT_DIRECTORY "            &
-                                            "!-I-";
-
-   S_List_Nostinc : aliased constant S := "/NOSTD_INCLUDES "               &
-                                            "-nostdinc";
-
-   S_List_Object  : aliased constant S := "/OBJECT_SEARCH=*"               &
-                                            "-aO*";
-
-   S_List_Output  : aliased constant S := "/OUTPUT="                       &
-                                            "SOURCES "                     &
-                                               "-s "                       &
-                                            "DEPEND "                      &
-                                               "-d "                       &
-                                            "OBJECTS "                     &
-                                               "-o "                       &
-                                            "UNITS "                       &
-                                               "-u "                       &
-                                            "OPTIONS "                     &
-                                               "-h "                       &
-                                            "VERBOSE "                     &
-                                               "-v ";
-
-   S_List_Search  : aliased constant S := "/SEARCH=*"                      &
-                                            "-I*";
-
-   S_List_Source  : aliased constant S := "/SOURCE_SEARCH=*"               &
-                                            "-aI*";
+   begin
+      --  Check if there is at least one argument that is not a switch
 
-   List_Switches : aliased constant Switches :=
-     (S_List_All     'Access,
-      S_List_Current 'Access,
-      S_Ext_Ref      'Access,
-      S_List_Nostinc 'Access,
-      S_List_Object  'Access,
-      S_List_Output  'Access,
-      S_Project_File 'Access,
-      S_Project_Verb 'Access,
-      S_List_Search  'Access,
-      S_List_Source  'Access);
+      for Index in 1 .. Last_Switches.Last loop
+         if Last_Switches.Table (Index) (1) /= '-' then
+            Add_Sources := False;
+            exit;
+         end if;
+      end loop;
 
-   ----------------------------
-   -- Switches for GNAT MAKE --
-   ----------------------------
+      --  If all arguments were switches, add the path names of all the sources
+      --  of the main project.
 
-   S_Make_Actions : aliased constant S := "/ACTIONS="                      &
-                                            "COMPILE "                     &
-                                               "-c "                       &
-                                            "BIND "                        &
-                                               "-b "                       &
-                                            "LINK "                        &
-                                               "-l ";
+      if Add_Sources then
+         declare
+            Current_Last : constant Integer := Last_Switches.Last;
+         begin
+            --  Gnatstack needs to add the .ci file for the binder
+            --  generated files corresponding to all of the library projects
+            --  and main units belonging to the application.
 
-   S_Make_All     : aliased constant S := "/ALL_FILES "                    &
-                                            "-a";
+            if The_Command = Stack then
+               for Proj in Project_Table.First ..
+                           Project_Table.Last (Project_Tree.Projects)
+               loop
+                  if Check_Project (Proj, Project) then
+                     declare
+                        Data : Project_Data renames
+                                 Project_Tree.Projects.Table (Proj);
+                        Main : String_List_Id := Data.Mains;
+                        File : String_Access;
 
-   S_Make_Bind    : aliased constant S := "/BINDER_QUALIFIERS=?"           &
-                                            "-bargs BIND";
+                     begin
+                        --  Include binder generated files for main programs
+
+                        while Main /= Nil_String loop
+                           File :=
+                             new String'
+                               (Get_Name_String (Data.Object_Directory.Name) &
+                                Directory_Separator                          &
+                                B_Start.all                                  &
+                                MLib.Fil.Ext_To
+                                  (Get_Name_String
+                                     (Project_Tree.String_Elements.Table
+                                        (Main).Value),
+                                   "ci"));
+
+                           if Is_Regular_File (File.all) then
+                              Last_Switches.Increment_Last;
+                              Last_Switches.Table (Last_Switches.Last) := File;
+                           end if;
 
-   S_Make_Comp    : aliased constant S := "/COMPILER_QUALIFIERS=?"         &
-                                            "-cargs COMPILE";
-
-   S_Make_Cond    : aliased constant S := "/CONDITIONAL_SOURCE_SEARCH=*"   &
-                                            "-A*";
-
-   S_Make_Cont    : aliased constant S := "/CONTINUE_ON_ERROR "            &
-                                            "-k";
-
-   S_Make_Current : aliased constant S := "/CURRENT_DIRECTORY "            &
-                                            "!-I-";
-
-   S_Make_Dep     : aliased constant S := "/DEPENDENCIES_LIST "            &
-                                            "-M";
-
-   S_Make_Doobj   : aliased constant S := "/DO_OBJECT_CHECK "              &
-                                            "-n";
-
-   S_Make_Execut  : aliased constant S := "/EXECUTABLE=@"                  &
-                                            "-o@";
-
-   S_Make_Force   : aliased constant S := "/FORCE_COMPILE "                &
-                                            "-f";
-
-   S_Make_Inplace : aliased constant S := "/IN_PLACE "                     &
-                                            "-i";
-
-   S_Make_Library : aliased constant S := "/LIBRARY_SEARCH=*"              &
-                                            "-L*";
-
-   S_Make_Link    : aliased constant S := "/LINKER_QUALIFIERS=?"           &
-                                            "-largs LINK";
-
-   S_Make_Mapping : aliased constant S := "/MAPPING "                      &
-                                            "-C";
-
-   S_Make_Minimal : aliased constant S := "/MINIMAL_RECOMPILATION "        &
-                                            "-m";
-
-   S_Make_Nolink  : aliased constant S := "/NOLINK "                       &
-                                            "-c";
-
-   S_Make_Nomain  : aliased constant S := "/NOMAIN "                       &
-                                            "-z";
-
-   S_Make_Nostinc : aliased constant S := "/NOSTD_INCLUDES "               &
-                                            "-nostdinc";
-
-   S_Make_Nostlib : aliased constant S := "/NOSTD_LIBRARIES "              &
-                                            "-nostdlib";
-
-   S_Make_Object  : aliased constant S := "/OBJECT_SEARCH=*"               &
-                                            "-aO*";
-
-   S_Make_Proc    : aliased constant S := "/PROCESSES=#"                   &
-                                            "-j#";
-
-   S_Make_Nojobs  : aliased constant S := "/NOPROCESSES "                  &
-                                            "-j1";
-
-   S_Make_Quiet   : aliased constant S := "/QUIET "                        &
-                                            "-q";
-
-   S_Make_Reason  : aliased constant S := "/REASONS "                      &
-                                            "-v";
-
-   S_Make_RTS     : aliased constant S := "/RUNTIME_SYSTEM=|"              &
-                                            "--RTS=|";
-
-   S_Make_Search  : aliased constant S := "/SEARCH=*"                      &
-                                            "-I*";
-
-   S_Make_Skip    : aliased constant S := "/SKIP_MISSING=*"                &
-                                            "-aL*";
-
-   S_Make_Source  : aliased constant S := "/SOURCE_SEARCH=*"               &
-                                            "-aI*";
-
-   S_Make_Switch  : aliased constant S := "/SWITCH_CHECK "               &
-                                            "-s";
+                           Main :=
+                             Project_Tree.String_Elements.Table (Main).Next;
+                        end loop;
 
-   S_Make_Unique  : aliased constant S := "/UNIQUE "                       &
-                                            "-u";
+                        if Data.Library then
 
-   S_Make_Verbose : aliased constant S := "/VERBOSE "                      &
-                                            "-v";
-
-   Make_Switches : aliased constant Switches :=
-     (S_Make_Actions 'Access,
-      S_Make_All     'Access,
-      S_Make_Bind    'Access,
-      S_Make_Comp    'Access,
-      S_Make_Cond    'Access,
-      S_Make_Cont    'Access,
-      S_Make_Current 'Access,
-      S_Make_Dep     'Access,
-      S_Make_Doobj   'Access,
-      S_Make_Execut  'Access,
-      S_Ext_Ref      'Access,
-      S_Make_Force   'Access,
-      S_Make_Inplace 'Access,
-      S_Make_Library 'Access,
-      S_Make_Link    'Access,
-      S_Make_Mapping 'Access,
-      S_Make_Minimal 'Access,
-      S_Make_Nolink  'Access,
-      S_Make_Nomain  'Access,
-      S_Make_Nostinc 'Access,
-      S_Make_Nostlib 'Access,
-      S_Make_Object  'Access,
-      S_Make_Proc    'Access,
-      S_Project_File 'Access,
-      S_Project_Verb 'Access,
-      S_Make_Nojobs  'Access,
-      S_Make_Quiet   'Access,
-      S_Make_Reason  'Access,
-      S_Make_RTS     'Access,
-      S_Make_Search  'Access,
-      S_Make_Skip    'Access,
-      S_Make_Source  'Access,
-      S_Make_Switch  'Access,
-      S_Make_Unique  'Access,
-      S_Make_Verbose 'Access);
-
-   ----------------------------
-   -- Switches for GNAT Name --
-   ----------------------------
-
-   S_Name_Conf    : aliased constant S := "/CONFIG_FILE=<"                   &
-                                            "-c>";
-
-   S_Name_Dirs    : aliased constant S := "/SOURCE_DIRS=*"                   &
-                                            "-d*";
-
-   S_Name_Dfile   : aliased constant S := "/DIRS_FILE=<"                     &
-                                            "-D>";
-
-   S_Name_Help    : aliased constant S := "/HELP"                            &
-                                            " -h";
-
-   S_Name_Proj    : aliased constant S := "/PROJECT_FILE=<"                  &
-                                            "-P>";
-
-   S_Name_Verbose : aliased constant S := "/VERBOSE"                         &
-                                            " -v";
-
-   Name_Switches : aliased constant Switches :=
-     (S_Name_Conf         'Access,
-      S_Name_Dirs         'Access,
-      S_Name_Dfile        'Access,
-      S_Name_Help         'Access,
-      S_Name_Proj         'Access,
-      S_Name_Verbose      'Access);
+                           --  Include the .ci file for the binder generated
+                           --  files that contains the initialization and
+                           --  finalization of the library.
 
-   ----------------------------------
-   -- Switches for GNAT PREPROCESS --
-   ----------------------------------
+                           File :=
+                             new String'
+                               (Get_Name_String (Data.Object_Directory.Name) &
+                                Directory_Separator                          &
+                                B_Start.all                                  &
+                                Get_Name_String (Data.Library_Name)          &
+                                ".ci");
 
-   S_Prep_Assoc   : aliased constant S := "/ASSOCIATE=" & '"'               &
-                                            "-D" & '"';
+                           if Is_Regular_File (File.all) then
+                              Last_Switches.Increment_Last;
+                              Last_Switches.Table (Last_Switches.Last) := File;
+                           end if;
+                        end if;
+                     end;
+                  end if;
+               end loop;
+            end if;
 
-   S_Prep_Blank   : aliased constant S := "/BLANK_LINES "                   &
-                                            "-b";
+            for Unit in Unit_Table.First ..
+                        Unit_Table.Last (Project_Tree.Units)
+            loop
+               Unit_Data := Project_Tree.Units.Table (Unit);
 
-   S_Prep_Com     : aliased constant S := "/COMMENTS "                      &
-                                            "-c";
+               --  For gnatls, we only need to put the library units, body or
+               --  spec, but not the subunits.
 
-   S_Prep_Ref     : aliased constant S := "/REFERENCE "                     &
-                                            "-r";
+               if The_Command = List then
+                  if
+                    Unit_Data.File_Names (Body_Part).Name /= No_File
+                      and then
+                    Unit_Data.File_Names (Body_Part).Path.Name /= Slash
+                  then
+                     --  There is a body, check if it is for this project
 
-   S_Prep_Remove  : aliased constant S := "/REMOVE "                        &
-                                            "!-b,!-c";
+                     if All_Projects or else
+                        Unit_Data.File_Names (Body_Part).Project = Project
+                     then
+                        Subunit := False;
 
-   S_Prep_Symbols : aliased constant S := "/SYMBOLS "                       &
-                                            "-s";
+                        if
+                          Unit_Data.File_Names (Specification).Name = No_File
+                            or else
+                            Unit_Data.File_Names
+                              (Specification).Path.Name = Slash
+                        then
+                           --  We have a body with no spec: we need to check if
+                           --  this is a subunit, because gnatls will complain
+                           --  about subunits.
 
-   S_Prep_Undef   : aliased constant S := "/UNDEFINED "                     &
-                                            "-u";
+                           declare
+                              Src_Ind : Source_File_Index;
 
-   Prep_Switches : aliased constant Switches :=
-     (S_Prep_Assoc   'Access,
-      S_Prep_Blank   'Access,
-      S_Prep_Com     'Access,
-      S_Prep_Ref     'Access,
-      S_Prep_Remove  'Access,
-      S_Prep_Symbols 'Access,
-      S_Prep_Undef   'Access);
+                           begin
+                              Src_Ind := Sinput.P.Load_Project_File
+                                (Get_Name_String
+                                   (Unit_Data.File_Names
+                                      (Body_Part).Path.Name));
+
+                              Subunit :=
+                                Sinput.P.Source_File_Is_Subunit
+                                  (Src_Ind);
+                           end;
+                        end if;
 
-   ------------------------------
-   -- Switches for GNAT SHARED --
-   ------------------------------
+                        if not Subunit then
+                           Last_Switches.Increment_Last;
+                           Last_Switches.Table (Last_Switches.Last) :=
+                             new String'
+                               (Get_Name_String
+                                    (Unit_Data.File_Names
+                                         (Body_Part).Display_Name));
+                        end if;
+                     end if;
 
-   S_Shared_Debug   : aliased constant S := "/DEBUG="                      &
-                                            "ALL "                         &
-                                               "-g3 "                      &
-                                            "NONE "                        &
-                                               "-g0 "                      &
-                                            "TRACEBACK "                   &
-                                               "-g1 "                      &
-                                            "NOTRACEBACK "                 &
-                                               "-g0";
+                  elsif
+                    Unit_Data.File_Names (Specification).Name /= No_File
+                      and then
+                    Unit_Data.File_Names (Specification).Path.Name /= Slash
+                  then
+                     --  We have a spec with no body; check if it is for this
+                     --  project.
 
-   S_Shared_Image  : aliased constant S := "/IMAGE=@"                      &
-                                            "-o@";
+                     if All_Projects or else
+                        Unit_Data.File_Names (Specification).Project = Project
+                     then
+                        Last_Switches.Increment_Last;
+                        Last_Switches.Table (Last_Switches.Last) :=
+                          new String'
+                            (Get_Name_String
+                                 (Unit_Data.File_Names
+                                      (Specification).Display_Name));
+                     end if;
+                  end if;
 
-   S_Shared_Ident   : aliased constant S := "/IDENTIFICATION=" & '"'       &
-                                            "--for-linker=IDENT="          &
-                                            '"';
+               --  For gnatstack, we put the .ci files corresponding to the
+               --  different units, including the binder generated files. We
+               --  only need to do that for the library units, body or spec,
+               --  but not the subunits.
 
-   S_Shared_Nofiles : aliased constant S := "/NOSTART_FILES "              &
-                                            "-nostartfiles";
+               elsif The_Command = Stack then
+                  if
+                    Unit_Data.File_Names (Body_Part).Name /= No_File
+                      and then
+                    Unit_Data.File_Names (Body_Part).Path.Name /= Slash
+                  then
+                     --  There is a body. Check if .ci files for this project
+                     --  must be added.
 
-   S_Shared_Noinhib : aliased constant S := "/NOINHIBIT-IMAGE "            &
-                                            "--for-linker=--noinhibit-exec";
+                     if
+                       Check_Project
+                         (Unit_Data.File_Names (Body_Part).Project, Project)
+                     then
+                        Subunit := False;
 
-   S_Shared_Verb    : aliased constant S := "/VERBOSE "                    &
-                                            "-v";
+                        if
+                          Unit_Data.File_Names (Specification).Name = No_File
+                            or else
+                            Unit_Data.File_Names
+                              (Specification).Path.Name = Slash
+                        then
+                           --  We have a body with no spec: we need to check
+                           --  if this is a subunit, because .ci files are not
+                           --  generated for subunits.
 
-   S_Shared_ZZZZZ   : aliased constant S := "/<other> "                    &
-                                            "--for-linker=";
+                           declare
+                              Src_Ind : Source_File_Index;
 
-   Shared_Switches : aliased constant Switches :=
-     (S_Shared_Debug   'Access,
-      S_Shared_Image   'Access,
-      S_Shared_Ident   'Access,
-      S_Shared_Nofiles 'Access,
-      S_Shared_Noinhib 'Access,
-      S_Shared_Verb    'Access,
-      S_Shared_ZZZZZ   'Access);
+                           begin
+                              Src_Ind := Sinput.P.Load_Project_File
+                                (Get_Name_String
+                                   (Unit_Data.File_Names
+                                      (Body_Part).Path.Name));
 
-   --------------------------------
-   -- Switches for GNAT STANDARD --
-   --------------------------------
+                              Subunit :=
+                                Sinput.P.Source_File_Is_Subunit (Src_Ind);
+                           end;
+                        end if;
 
-   Standard_Switches : aliased constant Switches := (1 .. 0 => null);
+                        if not Subunit then
+                           Last_Switches.Increment_Last;
+                           Last_Switches.Table (Last_Switches.Last) :=
+                             new String'
+                               (Get_Name_String
+                                    (Project_Tree.Projects.Table
+                                         (Unit_Data.File_Names
+                                              (Body_Part).Project).
+                                         Object_Directory.Name)      &
+                                Directory_Separator                  &
+                                MLib.Fil.Ext_To
+                                  (Get_Name_String
+                                     (Unit_Data.File_Names
+                                        (Body_Part).Display_Name),
+                                   "ci"));
+                        end if;
+                     end if;
 
-   ----------------------------
-   -- Switches for GNAT STUB --
-   ----------------------------
+                  elsif
+                    Unit_Data.File_Names (Specification).Name /= No_File
+                    and then
+                    Unit_Data.File_Names (Specification).Path.Name /= Slash
+                  then
+                     --  We have a spec with no body. Check if it is for this
+                     --  project.
 
-   S_Stub_Current : aliased constant S := "/CURRENT_DIRECTORY "            &
-                                            "!-I-";
+                     if
+                       Check_Project
+                         (Unit_Data.File_Names (Specification).Project,
+                          Project)
+                     then
+                        Last_Switches.Increment_Last;
+                        Last_Switches.Table (Last_Switches.Last) :=
+                          new String'
+                            (Get_Name_String
+                                 (Project_Tree.Projects.Table
+                                      (Unit_Data.File_Names
+                                           (Specification).Project).
+                                      Object_Directory.Name)         &
+                             Dir_Separator                           &
+                             MLib.Fil.Ext_To
+                               (Get_Name_String
+                                  (Unit_Data.File_Names
+                                     (Specification).Name),
+                                "ci"));
+                     end if;
+                  end if;
 
-   S_Stub_Full    : aliased constant S := "/FULL "                         &
-                                            "-f";
+               else
+                  --  For gnatcheck, gnatsync, gnatpp and gnatmetric, put all
+                  --  sources of the project, or of all projects if -U was
+                  --  specified.
+
+                  for Kind in Spec_Or_Body loop
+                     if Check_Project
+                          (Unit_Data.File_Names (Kind).Project, Project)
+                       and then Unit_Data.File_Names (Kind).Name /= No_File
+                       and then Unit_Data.File_Names (Kind).Path.Name /= Slash
+                     then
+                        Last_Switches.Increment_Last;
+                        Last_Switches.Table (Last_Switches.Last) :=
+                          new String'
+                            (Get_Name_String
+                               (Unit_Data.File_Names
+                                  (Kind).Path.Display_Name));
+                     end if;
+                  end loop;
+               end if;
+            end loop;
 
-   S_Stub_Header  : aliased constant S := "/HEADER="                       &
-                                            "GENERAL "                     &
-                                               "-hg "                      &
-                                            "SPEC "                        &
-                                               "-hs";
+            --  If the list of files is too long, create a temporary text file
+            --  that lists these files, and pass this temp file to gnatcheck,
+            --  gnatpp or gnatmetric using switch -files=.
 
-   S_Stub_Indent  : aliased constant S := "/INDENTATION=#"                 &
-                                            "-i#";
+            if Last_Switches.Last - Current_Last >
+              Max_Files_On_The_Command_Line
+            then
+               declare
+                  Temp_File_FD : File_Descriptor;
+                  Buffer       : String (1 .. 1_000);
+                  Len          : Natural;
+                  OK           : Boolean := True;
 
-   S_Stub_Length  : aliased constant S := "/LINE_LENGTH=#"                 &
-                                            "-l#";
+               begin
+                  Create_Temp_File (Temp_File_FD, Temp_File_Name);
+
+                  if Temp_File_Name /= null then
+                     for Index in Current_Last + 1 ..
+                       Last_Switches.Last
+                     loop
+                        Len := Last_Switches.Table (Index)'Length;
+                        Buffer (1 .. Len) := Last_Switches.Table (Index).all;
+                        Len := Len + 1;
+                        Buffer (Len) := ASCII.LF;
+                        Buffer (Len + 1) := ASCII.NUL;
+                        OK :=
+                          Write (Temp_File_FD,
+                                 Buffer (1)'Address,
+                                 Len) = Len;
+                        exit when not OK;
+                     end loop;
 
-   S_Stub_Quiet   : aliased constant S := "/QUIET "                        &
-                                            "-q";
+                     if OK then
+                        Close (Temp_File_FD, OK);
+                     else
+                        Close (Temp_File_FD, OK);
+                        OK := False;
+                     end if;
 
-   S_Stub_Search  : aliased constant S := "/SEARCH=*"                      &
-                                            "-I*";
+                     --  If there were any problem creating the temp file, then
+                     --  pass the list of files.
 
-   S_Stub_Tree    : aliased constant S := "/TREE_FILE="                    &
-                                            "OVERWRITE "                   &
-                                               "-t "                       &
-                                            "SAVE "                        &
-                                               "-k "                       &
-                                            "REUSE "                       &
-                                               "-r";
+                     if OK then
 
-   S_Stub_Verbose : aliased constant S := "/VERBOSE "                      &
-                                            "-v";
+                        --  Replace list of files with -files=<temp file name>
 
-   Stub_Switches : aliased constant Switches :=
-     (S_Stub_Current 'Access,
-      S_Stub_Full    'Access,
-      S_Stub_Header  'Access,
-      S_Stub_Indent  'Access,
-      S_Stub_Length  'Access,
-      S_Stub_Quiet   'Access,
-      S_Stub_Search  'Access,
-      S_Stub_Tree    'Access,
-      S_Stub_Verbose 'Access);
+                        Last_Switches.Set_Last (Current_Last + 1);
+                        Last_Switches.Table (Last_Switches.Last) :=
+                          new String'("-files=" & Temp_File_Name.all);
+                     end if;
+                  end if;
+               end;
+            end if;
+         end;
+      end if;
+   end Check_Files;
 
-   ----------------------------
-   -- Switches for GNAT XREF --
-   ----------------------------
+   -------------------
+   -- Check_Project --
+   -------------------
 
-   S_Xref_All     : aliased constant S := "/ALL_FILES "                    &
-                                            "-a";
+   function Check_Project
+     (Project      : Project_Id;
+      Root_Project : Project_Id) return Boolean
+   is
+   begin
+      if Project = No_Project then
+         return False;
 
-   S_Xref_Deriv   : aliased constant S := "/DERIVED_TYPES "                &
-                                            "-d";
+      elsif All_Projects or Project = Root_Project then
+         return True;
 
-   S_Xref_Full    : aliased constant S := "/FULL_PATHNAME "                &
-                                            "-f";
+      elsif The_Command = Metric then
+         declare
+            Data : Project_Data;
 
-   S_Xref_Global  : aliased constant S := "/IGNORE_LOCALS "                &
-                                            "-g";
+         begin
+            Data := Project_Tree.Projects.Table (Root_Project);
+            while Data.Extends /= No_Project loop
+               if Project = Data.Extends then
+                  return True;
+               end if;
 
-   S_Xref_Nostinc : aliased constant S := "/NOSTD_INCLUDES "               &
-                                            "-nostdinc";
+               Data := Project_Tree.Projects.Table (Data.Extends);
+            end loop;
+         end;
+      end if;
 
-   S_Xref_Nostlib : aliased constant S := "/NOSTD_LIBRARIES "              &
-                                            "-nostdlib";
+      return False;
+   end Check_Project;
 
-   S_Xref_Object  : aliased constant S := "/OBJECT_SEARCH=*"               &
-                                            "-aO*";
+   -------------------------------
+   -- Check_Relative_Executable --
+   -------------------------------
 
-   S_Xref_Project : aliased constant S := "/PROJECT=@"                     &
-                                            "-p@";
+   procedure Check_Relative_Executable (Name : in out String_Access) is
+      Exec_File_Name : constant String := Name.all;
 
-   S_Xref_Search  : aliased constant S := "/SEARCH=*"                      &
-                                            "-I*";
+   begin
+      if not Is_Absolute_Path (Exec_File_Name) then
+         for Index in Exec_File_Name'Range loop
+            if Exec_File_Name (Index) = Directory_Separator then
+               Fail ("relative executable (""" &
+                       Exec_File_Name &
+                       """) with directory part not allowed " &
+                       "when using project files");
+            end if;
+         end loop;
 
-   S_Xref_Source  : aliased constant S := "/SOURCE_SEARCH=*"               &
-                                            "-aI*";
+         Get_Name_String (Project_Tree.Projects.Table
+                            (Project).Exec_Directory.Name);
 
-   S_Xref_Output  : aliased constant S := "/UNUSED "                       &
-                                            "-u";
+         if Name_Buffer (Name_Len) /= Directory_Separator then
+            Name_Len := Name_Len + 1;
+            Name_Buffer (Name_Len) := Directory_Separator;
+         end if;
 
-   S_Xref_Tags    : aliased constant S := "/TAGS "                         &
-                                            "-v";
+         Name_Buffer (Name_Len + 1 ..
+                        Name_Len + Exec_File_Name'Length) :=
+           Exec_File_Name;
+         Name_Len := Name_Len + Exec_File_Name'Length;
+         Name := new String'(Name_Buffer (1 .. Name_Len));
+      end if;
+   end Check_Relative_Executable;
 
-   Xref_Switches : aliased constant Switches :=
-     (S_Xref_All     'Access,
-      S_Xref_Deriv   'Access,
-      S_Ext_Ref      'Access,
-      S_Xref_Full    'Access,
-      S_Xref_Global  'Access,
-      S_Xref_Nostinc 'Access,
-      S_Xref_Nostlib 'Access,
-      S_Xref_Object  'Access,
-      S_Xref_Project 'Access,
-      S_Project_File 'Access,
-      S_Project_Verb 'Access,
-      S_Xref_Search  'Access,
-      S_Xref_Source  'Access,
-      S_Xref_Output  'Access,
-      S_Xref_Tags    'Access);
+   --------------------------------
+   -- Configuration_Pragmas_File --
+   --------------------------------
 
-   -------------------
-   -- COMMAND TABLE --
-   -------------------
+   function Configuration_Pragmas_File return Path_Name_Type is
+   begin
+      Prj.Env.Create_Config_Pragmas_File
+        (Project, Project, Project_Tree, Include_Config_Files => False);
+      return Project_Tree.Projects.Table (Project).Config_File_Name;
+   end Configuration_Pragmas_File;
 
-   --  The command table contains an entry for each command recognized by
-   --  GNATCmd. The entries are represented by an array of records.
+   ------------------------------
+   -- Delete_Temp_Config_Files --
+   ------------------------------
 
-   type Parameter_Type is
-   --  A parameter is defined as a whitespace bounded string, not begining
-   --   with a slash. (But see note under FILES_OR_WILDCARD).
-     (File,
-      --  A required file or directory parameter.
+   procedure Delete_Temp_Config_Files is
+      Success : Boolean;
+      pragma Warnings (Off, Success);
 
-      Optional_File,
-      --  An optional file or directory parameter.
+   begin
+      --  This should only be called if Keep_Temporary_Files is False
 
-      Other_As_Is,
-      --  A parameter that's passed through as is (not canonicalized)
+      pragma Assert (not Keep_Temporary_Files);
 
-      Unlimited_Files,
-      --  An unlimited number of whitespace separate file or directory
-      --  parameters including wildcard specifications.
+      if Project /= No_Project then
+         for Prj in Project_Table.First ..
+                    Project_Table.Last (Project_Tree.Projects)
+         loop
+            if
+              Project_Tree.Projects.Table (Prj).Config_File_Temp
+            then
+               if Verbose_Mode then
+                  Output.Write_Str ("Deleting temp configuration file """);
+                  Output.Write_Str
+                    (Get_Name_String
+                       (Project_Tree.Projects.Table
+                          (Prj).Config_File_Name));
+                  Output.Write_Line ("""");
+               end if;
 
-      Unlimited_As_Is,
-      --  Un unlimited number of whitespace separated paameters that are
-      --  passed through as is (not canonicalized).
+               Delete_File
+                 (Name =>
+                    Get_Name_String
+                      (Project_Tree.Projects.Table (Prj).Config_File_Name),
+                  Success => Success);
+            end if;
+         end loop;
+      end if;
 
-      Files_Or_Wildcard);
-      --  A comma separated list of files and/or wildcard file specifications.
-      --  A comma preceded by or followed by whitespace is considered as a
-      --  single comma character w/o whitespace.
+      --  If a temporary text file that contains a list of files for a tool
+      --  has been created, delete this temporary file.
 
-   type Parameter_Array is array (Natural range <>) of Parameter_Type;
-   type Parameter_Ref is access all Parameter_Array;
+      if Temp_File_Name /= null then
+         Delete_File (Temp_File_Name.all, Success);
+      end if;
+   end Delete_Temp_Config_Files;
 
-   type Command_Type is
-     (Bind, Chop, Compile, Elim, Find, Krunch, Library, Link, List,
-      Make, Name, Preprocess, Shared, Standard, Stub, Xref, Undefined);
+   -----------------
+   -- Get_Closure --
+   -----------------
 
-   type Alternate_Command is (Comp, Ls, Kr, Prep, Psta);
-   --  Alternate command libel for non VMS system
+   procedure Get_Closure is
+      Args : constant Argument_List :=
+               (1 => new String'("-q"),
+                2 => new String'("-b"),
+                3 => new String'("-P"),
+                4 => Project_File,
+                5 => ASIS_Main,
+                6 => new String'("-bargs"),
+                7 => new String'("-R"),
+                8 => new String'("-Z"));
+      --  Arguments for the invocation of gnatmake which are added to the
+      --  Last_Arguments list by this procedure.
 
-   Corresponding_To : constant array (Alternate_Command) of Command_Type :=
-     (Comp  => Compile,
-      Ls    => List,
-      Kr    => Krunch,
-      Prep  => Preprocess,
-      Psta  => Standard);
-   --  Mapping of alternate commands to commands
+      FD : File_Descriptor;
+      --  File descriptor for the temp file that will get the output of the
+      --  invocation of gnatmake.
 
-   subtype Real_Command_Type is Command_Type range Bind .. Xref;
+      Name : Path_Name_Type;
+      --  Path of the file FD
 
-   type Command_Entry is record
-      Cname : String_Ptr;
-      --  Command name for GNAT xxx command
+      GN_Name : constant String := Program_Name ("gnatmake", "gnat").all;
+      --  Name for gnatmake
 
-      Usage : String_Ptr;
-      --  A usage string, used for error messages
+      GN_Path : constant String_Access := Locate_Exec_On_Path (GN_Name);
+      --  Path of gnatmake
 
-      Unixcmd : String_Ptr;
-      --  Corresponding Unix command
+      Return_Code : Integer;
 
-      Unixsws : Argument_List_Access;
-      --  Switches for the Unix command
+      Unused : Boolean;
+      pragma Warnings (Off, Unused);
 
-      VMS_Only : Boolean;
-      --  When True, the command can only be used on VMS
+      File : Ada.Text_IO.File_Type;
+      Line : String (1 .. 250);
+      Last : Natural;
+      --  Used to read file if there is an error, it is good enough to display
+      --  just 250 characters if the first line of the file is very long.
 
-      Switches : Switches_Ptr;
-      --  Pointer to array of switch strings
+      Udata : Unit_Data;
+      Path  : Path_Name_Type;
 
-      Params : Parameter_Ref;
-      --  Describes the allowable types of parameters.
-      --  Params (1) is the type of the first parameter, etc.
-      --  An empty parameter array means this command takes no parameters.
+   begin
+      if GN_Path = null then
+         Put_Line (Standard_Error, "could not locate " & GN_Name);
+         raise Error_Exit;
+      end if;
 
-      Defext : String (1 .. 3);
-      --  Default extension. If non-blank, then this extension is supplied by
-      --  default as the extension for any file parameter which does not have
-      --  an extension already.
-   end record;
+      --  Create the temp file
 
-   -------------------------
-   -- INTERNAL STRUCTURES --
-   -------------------------
+      Tempdir.Create_Temp_File (FD, Name);
 
-   --  The switches and commands are defined by strings in the previous
-   --  section so that they are easy to modify, but internally, they are
-   --  kept in a more conveniently accessible form described in this
-   --  section.
+      --  And close it, because on VMS Spawn with a file descriptor created
+      --  with Create_Temp_File does not redirect output.
 
-   --  Commands, command qualifers and options have a similar common format
-   --  so that searching for matching names can be done in a common manner.
+      Close (FD);
 
-   type Item_Id is (Id_Command, Id_Switch, Id_Option);
+      --  Spawn "gnatmake -q -b -P <project> <main> -bargs -R -Z"
 
-   type Translation_Type is
-     (
-      T_Direct,
-      --  A qualifier with no options.
-      --  Example: GNAT MAKE /VERBOSE
+      Spawn
+        (Program_Name => GN_Path.all,
+         Args         => Args,
+         Output_File  => Get_Name_String (Name),
+         Success      => Unused,
+         Return_Code  => Return_Code,
+         Err_To_Out   => True);
 
-      T_Directories,
-      --  A qualifier followed by a list of directories
-      --  Example: GNAT COMPILE /SEARCH=([], [.FOO], [.BAR])
+      Close (FD);
 
-      T_Directory,
-      --  A qualifier followed by one directory
-      --  Example: GNAT LIBRARY /SET=[.VAXFLOATLIB]
+      --  Read the output of the invocation of gnatmake
 
-      T_File,
-      --  A qualifier followed by a filename
-      --  Example: GNAT LINK /EXECUTABLE=FOO.EXE
+      Open (File, In_File, Get_Name_String (Name));
 
-      T_No_Space_File,
-      --  A qualifier followed by a filename
-      --  Example: GNAT MAKE /PROJECT_FILE=PRJ.GPR
+      --  If it was unsuccessful, display the first line in the file and exit
+      --  with error.
 
-      T_Numeric,
-      --  A qualifier followed by a numeric value.
-      --  Example: GNAT CHOP /FILE_NAME_MAX_LENGTH=39
+      if Return_Code /= 0 then
+         Get_Line (File, Line, Last);
 
-      T_String,
-      --  A qualifier followed by a quoted string. Only used by
-      --  /IDENTIFICATION qualfier.
-      --  Example: GNAT LINK /IDENTIFICATION="3.14a1 version"
+         if not Keep_Temporary_Files then
+            Delete (File);
+         else
+            Close (File);
+         end if;
 
-      T_Options,
-      --  A qualifier followed by a list of options.
-      --  Example: GNAT COMPILE /REPRESENTATION_INFO=(ARRAYS,OBJECTS)
+         Put_Line (Standard_Error, Line (1 .. Last));
+         Put_Line
+           (Standard_Error, "could not get closure of " & ASIS_Main.all);
+         raise Error_Exit;
 
-      T_Commands,
-      --  A qualifier followed by a list. Only used for
-      --  MAKE /COMPILER_QUALIFIERS /BINDER_QUALIFIERS /LINKER_QUALIFIERS
-      --  (gnatmake -cargs -bargs -largs )
-      --  Example: GNAT MAKE ... /LINKER_QUALIFIERS /VERBOSE FOOBAR.OBJ
+      else
+         --  Get each file name in the file, find its path and add it the
+         --  list of arguments.
+
+         while not End_Of_File (File) loop
+            Get_Line (File, Line, Last);
+            Path := No_Path;
+
+            for Unit in Unit_Table.First ..
+                        Unit_Table.Last (Project_Tree.Units)
+            loop
+               Udata := Project_Tree.Units.Table (Unit);
+
+               if Udata.File_Names (Specification).Name /= No_File
+                 and then
+                   Get_Name_String (Udata.File_Names (Specification).Name) =
+                      Line (1 .. Last)
+               then
+                  Path := Udata.File_Names (Specification).Path.Name;
+                  exit;
 
-      T_Other,
-      --  A qualifier passed directly to the linker. Only used
-      --  for LINK and SHARED if no other match is found.
-      --  Example: GNAT LINK FOO.ALI /SYSSHR
+               elsif Udata.File_Names (Body_Part).Name /= No_File
+                 and then
+                   Get_Name_String (Udata.File_Names (Body_Part).Name) =
+                     Line (1 .. Last)
+               then
+                  Path := Udata.File_Names (Body_Part).Path.Name;
+                  exit;
+               end if;
+            end loop;
 
-      T_Alphanumplus
-      --  A qualifier followed by a legal linker symbol prefix. Only used
-      --  for BIND /BUILD_LIBRARY (gnatbind -Lxyz).
-      --  Example: GNAT BIND /BUILD_LIBRARY=foobar
-      );
+            Last_Switches.Increment_Last;
 
-   type Item (Id : Item_Id);
-   type Item_Ptr is access all Item;
+            if Path /= No_Path then
+               Last_Switches.Table (Last_Switches.Last) :=
+                  new String'(Get_Name_String (Path));
 
-   type Item (Id : Item_Id) is record
-      Name : String_Ptr;
-      --  Name of the command, switch (with slash) or option
+            else
+               Last_Switches.Table (Last_Switches.Last) :=
+                 new String'(Line (1 .. Last));
+            end if;
+         end loop;
 
-      Next : Item_Ptr;
-      --  Pointer to next item on list, always has the same Id value
+         if not Keep_Temporary_Files then
+            Delete (File);
+         else
+            Close (File);
+         end if;
+      end if;
+   end Get_Closure;
 
-      Command : Command_Type := Undefined;
+   -----------
+   -- Index --
+   -----------
 
-      Unix_String : String_Ptr := null;
-      --  Corresponding Unix string. For a command, this is the unix command
-      --  name and possible default switches. For a switch or option it is
-      --  the unix switch string.
+   function Index (Char : Character; Str : String) return Natural is
+   begin
+      for Index in Str'Range loop
+         if Str (Index) = Char then
+            return Index;
+         end if;
+      end loop;
 
-      case Id is
+      return 0;
+   end Index;
 
-         when Id_Command =>
+   ------------------
+   -- Process_Link --
+   ------------------
 
-            Switches : Item_Ptr;
-            --  Pointer to list of switch items for the command, linked
-            --  through the Next fields with null terminating the list.
+   procedure Process_Link is
+      Look_For_Executable : Boolean := True;
+      There_Are_Libraries : Boolean := False;
+      Path_Option         : constant String_Access :=
+                              MLib.Linker_Library_Path_Option;
+      Prj                 : Project_Id := Project;
+      Arg                 : String_Access;
+      Last                : Natural := 0;
+      Skip_Executable     : Boolean := False;
 
-            Usage : String_Ptr;
-            --  Usage information, used only for errors and the default
-            --  list of commands output.
+   begin
+      --  Add the default search directories, to be able to find
+      --  libgnat in call to MLib.Utl.Lib_Directory.
 
-            Params : Parameter_Ref;
-            --  Array of parameters
+      Add_Default_Search_Dirs;
 
-            Defext : String (1 .. 3);
-            --  Default extension. If non-blank, then this extension is
-            --  supplied by default as the extension for any file parameter
-            --  which does not have an extension already.
+      Library_Paths.Set_Last (0);
 
-         when Id_Switch =>
+      --  Check if there are library project files
 
-            Translation : Translation_Type;
-            --  Type of switch translation. For all cases, except Options,
-            --  this is the only field needed, since the Unix translation
-            --  is found in Unix_String.
+      if MLib.Tgt.Support_For_Libraries /= None then
+         Set_Libraries (Project, Project_Tree, There_Are_Libraries);
+      end if;
 
-            Options : Item_Ptr;
-            --  For the Options case, this field is set to point to a list
-            --  of options item (for this case Unix_String is null in the
-            --  main switch item). The end of the list is marked by null.
+      --  If there are, add the necessary additional switches
 
-         when Id_Option =>
+      if There_Are_Libraries then
 
-            null;
-            --  No special fields needed, since Name and Unix_String are
-            --  sufficient to completely described an option.
+         --  Add -L<lib_dir> -lgnarl -lgnat -Wl,-rpath,<lib_dir>
 
-      end case;
-   end record;
+         Last_Switches.Increment_Last;
+         Last_Switches.Table (Last_Switches.Last) :=
+           new String'("-L" & MLib.Utl.Lib_Directory);
+         Last_Switches.Increment_Last;
+         Last_Switches.Table (Last_Switches.Last) :=
+           new String'("-lgnarl");
+         Last_Switches.Increment_Last;
+         Last_Switches.Table (Last_Switches.Last) :=
+           new String'("-lgnat");
 
-   subtype Command_Item is Item (Id_Command);
-   subtype Switch_Item  is Item (Id_Switch);
-   subtype Option_Item  is Item (Id_Option);
+         --  If Path_Option is not null, create the switch ("-Wl,-rpath," or
+         --  equivalent) with all the library dirs plus the standard GNAT
+         --  library dir.
 
-   ----------------------------------
-   -- Declarations for GNATCMD use --
-   ----------------------------------
+         if Path_Option /= null then
+            declare
+               Option  : String_Access;
+               Length  : Natural := Path_Option'Length;
+               Current : Natural;
 
-   Commands : Item_Ptr;
-   --  Pointer to head of list of command items, one for each command, with
-   --  the end of the list marked by a null pointer.
+            begin
+               --  First, compute the exact length for the switch
 
-   Last_Command : Item_Ptr;
-   --  Pointer to last item in Commands list
+               for Index in
+                 Library_Paths.First .. Library_Paths.Last
+               loop
+                  --  Add the length of the library dir plus one for the
+                  --  directory separator.
 
-   Normal_Exit : exception;
-   --  Raise this exception for normal program termination
+                  Length :=
+                    Length +
+                      Library_Paths.Table (Index)'Length + 1;
+               end loop;
 
-   Error_Exit : exception;
-   --  Raise this exception if error detected
+               --  Finally, add the length of the standard GNAT library dir
 
-   Errors : Natural := 0;
-   --  Count errors detected
+               Length := Length + MLib.Utl.Lib_Directory'Length;
+               Option := new String (1 .. Length);
+               Option (1 .. Path_Option'Length) := Path_Option.all;
+               Current := Path_Option'Length;
 
-   Command_Arg : Positive := 1;
+               --  Put each library dir followed by a dir separator
 
-   Command : Item_Ptr;
-   --  Pointer to command item for current command
+               for Index in
+                 Library_Paths.First .. Library_Paths.Last
+               loop
+                  Option
+                    (Current + 1 ..
+                       Current +
+                         Library_Paths.Table (Index)'Length) :=
+                      Library_Paths.Table (Index).all;
+                  Current :=
+                    Current +
+                      Library_Paths.Table (Index)'Length + 1;
+                  Option (Current) := Path_Separator;
+               end loop;
 
-   Make_Commands_Active : Item_Ptr := null;
-   --  Set to point to Command entry for COMPILE, BIND, or LINK as appropriate
-   --  if a COMMANDS_TRANSLATION switch has been encountered while processing
-   --  a MAKE Command.
+               --  Finally put the standard GNAT library dir
 
-   My_Exit_Status : Exit_Status := Success;
+               Option
+                 (Current + 1 ..
+                    Current + MLib.Utl.Lib_Directory'Length) :=
+                   MLib.Utl.Lib_Directory;
 
-   package Buffer is new Table.Table
-     (Table_Component_Type => Character,
-      Table_Index_Type     => Integer,
-      Table_Low_Bound      => 1,
-      Table_Initial        => 4096,
-      Table_Increment      => 2,
-      Table_Name           => "Buffer");
+               --  And add the switch to the last switches
 
-   Param_Count : Natural := 0;
-   --  Number of parameter arguments so far
+               Last_Switches.Increment_Last;
+               Last_Switches.Table (Last_Switches.Last) :=
+                 Option;
+            end;
+         end if;
+      end if;
 
-   Arg_Num : Natural;
-   --  Argument number
+      --  Check if the first ALI file specified can be found, either in the
+      --  object directory of the main project or in an object directory of a
+      --  project file extended by the main project. If the ALI file can be
+      --  found, replace its name with its absolute path.
 
-   Display_Command : Boolean := False;
-   --  Set true if /? switch causes display of generated command (on VMS)
+      Skip_Executable := False;
 
-   The_Command : Command_Type;
-   --  The command used
+      Switch_Loop : for J in 1 .. Last_Switches.Last loop
 
-   -----------------------
-   -- Local Subprograms --
-   -----------------------
+         --  If we have an executable just reset the flag
 
-   function Index (Char : Character; Str : String) return Natural;
-   --  Returns the first occurrence of Char in Str.
-   --  Returns 0 if Char is not in Str.
-
-   function Init_Object_Dirs return Argument_List;
-
-   function Invert_Sense (S : String) return String_Ptr;
-   --  Given a unix switch string S, computes the inverse (adding or
-   --  removing ! characters as required), and returns a pointer to
-   --  the allocated result on the heap.
-
-   function Is_Extensionless (F : String) return Boolean;
-   --  Returns true if the filename has no extension.
-
-   function Match (S1, S2 : String) return Boolean;
-   --  Determines whether S1 and S2 match. This is a case insensitive match.
-
-   function Match_Prefix (S1, S2 : String) return Boolean;
-   --  Determines whether S1 matches a prefix of S2. This is also a case
-   --  insensitive match (for example Match ("AB","abc") is True).
-
-   function Matching_Name
-     (S     : String;
-      Itm   : Item_Ptr;
-      Quiet : Boolean := False)
-      return  Item_Ptr;
-   --  Determines if the item list headed by Itm and threaded through the
-   --  Next fields (with null marking the end of the list), contains an
-   --  entry that uniquely matches the given string. The match is case
-   --  insensitive and permits unique abbreviation. If the match succeeds,
-   --  then a pointer to the matching item is returned. Otherwise, an
-   --  appropriate error message is written. Note that the discriminant
-   --  of Itm is used to determine the appropriate form of this message.
-   --  Quiet is normally False as shown, if it is set to True, then no
-   --  error message is generated in a not found situation (null is still
-   --  returned to indicate the not-found situation).
+         if Skip_Executable then
+            Skip_Executable := False;
 
-   procedure Non_VMS_Usage;
-   --  Display usage for platforms other than VMS
+         --  If -o, set flag so that next switch is not processed
 
-   function OK_Alphanumerplus (S : String) return Boolean;
-   --  Checks that S is a string of alphanumeric characters,
-   --  returning True if all alphanumeric characters,
-   --  False if empty or a non-alphanumeric character is present.
+         elsif Last_Switches.Table (J).all = "-o" then
+            Skip_Executable := True;
 
-   function OK_Integer (S : String) return Boolean;
-   --  Checks that S is a string of digits, returning True if all digits,
-   --  False if empty or a non-digit is present.
+         --  Normal case
 
-   procedure Output_Version;
-   --  Output the version of this program
+         else
+            declare
+               Switch         : constant String :=
+                                  Last_Switches.Table (J).all;
 
-   procedure Place (C : Character);
-   --  Place a single character in the buffer, updating Ptr
+               ALI_File       : constant String (1 .. Switch'Length + 4) :=
+                                  Switch & ".ali";
 
-   procedure Place (S : String);
-   --  Place a string character in the buffer, updating Ptr
+               Test_Existence : Boolean := False;
 
-   procedure Place_Lower (S : String);
-   --  Place string in buffer, forcing letters to lower case, updating Ptr
+            begin
+               Last := Switch'Length;
 
-   procedure Place_Unix_Switches (S : String_Ptr);
-   --  Given a unix switch string, place corresponding switches in Buffer,
-   --  updating Ptr appropriatelly. Note that in the case of use of ! the
-   --  result may be to remove a previously placed switch.
+               --  Skip real switches
 
-   procedure Set_Library_For
-     (Project             : Project_Id;
-      There_Are_Libraries : in out Boolean);
-   --  If Project is a library project, add the correct
-   --  -L and -l switches to the linker invocation.
+               if Switch'Length /= 0
+                 and then Switch (Switch'First) /= '-'
+               then
+                  --  Append ".ali" if file name does not end with it
 
-   procedure Set_Libraries is
-      new For_Every_Project_Imported (Boolean, Set_Library_For);
-   --  Add the -L and -l switches to the linker for all
-   --  of the library projects.
+                  if Switch'Length <= 4
+                    or else Switch (Switch'Last - 3 .. Switch'Last)
+                    /= ".ali"
+                  then
+                     Last := ALI_File'Last;
+                  end if;
 
-   procedure Validate_Command_Or_Option (N : String_Ptr);
-   --  Check that N is a valid command or option name, i.e. that it is of the
-   --  form of an Ada identifier with upper case letters and underscores.
+                  --  If file name includes directory information, stop if ALI
+                  --  file exists.
 
-   procedure Validate_Unix_Switch (S : String_Ptr);
-   --  Check that S is a valid switch string as described in the syntax for
-   --  the switch table item UNIX_SWITCH or else begins with a backquote.
+                  if Is_Absolute_Path (ALI_File (1 .. Last)) then
+                     Test_Existence := True;
 
-   procedure VMS_Conversion (The_Command : out Command_Type);
-   --  Converts VMS command line to equivalent Unix command line
+                  else
+                     for K in Switch'Range loop
+                        if Switch (K) = '/' or else
+                          Switch (K) = Directory_Separator
+                        then
+                           Test_Existence := True;
+                           exit;
+                        end if;
+                     end loop;
+                  end if;
 
-   -----------
-   -- Index --
-   -----------
+                  if Test_Existence then
+                     if Is_Regular_File (ALI_File (1 .. Last)) then
+                        exit Switch_Loop;
+                     end if;
 
-   function Index (Char : Character; Str : String) return Natural is
-   begin
-      for Index in Str'Range loop
-         if Str (Index) = Char then
-            return Index;
-         end if;
-      end loop;
+                  --  Look in object directories if ALI file exists
 
-      return 0;
-   end Index;
-
-   ----------------------
-   -- Init_Object_Dirs --
-   ----------------------
-
-   function Init_Object_Dirs return Argument_List is
-      Object_Dirs     : Integer;
-      Object_Dir      : Argument_List (1 .. 256);
-      Object_Dir_Name : String_Access;
-
-   begin
-      Object_Dirs := 0;
-      Object_Dir_Name := String_Access (Object_Dir_Default_Name);
-      Get_Next_Dir_In_Path_Init (Object_Dir_Name);
-
-      loop
-         declare
-            Dir : String_Access := String_Access
-              (Get_Next_Dir_In_Path (Object_Dir_Name));
-         begin
-            exit when Dir = null;
-            Object_Dirs := Object_Dirs + 1;
-            Object_Dir (Object_Dirs) :=
-              new String'("-L" &
-                          To_Canonical_Dir_Spec
-                          (To_Host_Dir_Spec
-                           (Normalize_Directory_Name (Dir.all).all,
-                            True).all, True).all);
-         end;
-      end loop;
-
-      Object_Dirs := Object_Dirs + 1;
-      Object_Dir (Object_Dirs) := new String'("-lgnat");
-
-      if Hostparm.OpenVMS then
-         Object_Dirs := Object_Dirs + 1;
-         Object_Dir (Object_Dirs) := new String'("-ldecgnat");
-      end if;
-
-      return Object_Dir (1 .. Object_Dirs);
-   end Init_Object_Dirs;
-
-   ------------------
-   -- Invert_Sense --
-   ------------------
-
-   function Invert_Sense (S : String) return String_Ptr is
-      Sinv : String (1 .. S'Length * 2);
-      --  Result (for sure long enough)
-
-      Sinvp : Natural := 0;
-      --  Pointer to output string
-
-   begin
-      for Sp in S'Range loop
-         if Sp = S'First or else S (Sp - 1) = ',' then
-            if S (Sp) = '!' then
-               null;
-            else
-               Sinv (Sinvp + 1) := '!';
-               Sinv (Sinvp + 2) := S (Sp);
-               Sinvp := Sinvp + 2;
-            end if;
-
-         else
-            Sinv (Sinvp + 1) := S (Sp);
-            Sinvp := Sinvp + 1;
-         end if;
-      end loop;
-
-      return new String'(Sinv (1 .. Sinvp));
-   end Invert_Sense;
-
-   ----------------------
-   -- Is_Extensionless --
-   ----------------------
-
-   function Is_Extensionless (F : String) return Boolean is
-   begin
-      for J in reverse F'Range loop
-         if F (J) = '.' then
-            return False;
-         elsif F (J) = '/' or else F (J) = ']' or else F (J) = ':' then
-            return True;
-         end if;
-      end loop;
-
-      return True;
-   end Is_Extensionless;
-
-   -----------
-   -- Match --
-   -----------
-
-   function Match (S1, S2 : String) return Boolean is
-      Dif : constant Integer := S2'First - S1'First;
-
-   begin
-
-      if S1'Length /= S2'Length then
-         return False;
-
-      else
-         for J in S1'Range loop
-            if To_Lower (S1 (J)) /= To_Lower (S2 (J + Dif)) then
-               return False;
-            end if;
-         end loop;
-
-         return True;
-      end if;
-   end Match;
-
-   ------------------
-   -- Match_Prefix --
-   ------------------
-
-   function Match_Prefix (S1, S2 : String) return Boolean is
-   begin
-      if S1'Length > S2'Length then
-         return False;
-      else
-         return Match (S1, S2 (S2'First .. S2'First + S1'Length - 1));
-      end if;
-   end Match_Prefix;
-
-   -------------------
-   -- Matching_Name --
-   -------------------
-
-   function Matching_Name
-     (S     : String;
-      Itm   : Item_Ptr;
-      Quiet : Boolean := False)
-     return  Item_Ptr
-   is
-      P1, P2 : Item_Ptr;
-
-      procedure Err;
-      --  Little procedure to output command/qualifier/option as appropriate
-      --  and bump error count.
-
-      ---------
-      -- Err --
-      ---------
-
-      procedure Err is
-      begin
-         if Quiet then
-            return;
-         end if;
-
-         Errors := Errors + 1;
-
-         if Itm /= null then
-            case Itm.Id is
-               when Id_Command =>
-                  Put (Standard_Error, "command");
-
-               when Id_Switch =>
-                  if OpenVMS then
-                     Put (Standard_Error, "qualifier");
                   else
-                     Put (Standard_Error, "switch");
-                  end if;
-
-               when Id_Option =>
-                  Put (Standard_Error, "option");
-
-            end case;
-         else
-            Put (Standard_Error, "input");
-
-         end if;
-
-         Put (Standard_Error, ": ");
-         Put (Standard_Error, S);
-      end Err;
-
-   --  Start of processing for Matching_Name
-
-   begin
-      --  If exact match, that's the one we want
-
-      P1 := Itm;
-      while P1 /= null loop
-         if Match (S, P1.Name.all) then
-            return P1;
-         else
-            P1 := P1.Next;
-         end if;
-      end loop;
-
-      --  Now check for prefix matches
-
-      P1 := Itm;
-      while P1 /= null loop
-         if P1.Name.all = "/<other>" then
-            return P1;
-
-         elsif not Match_Prefix (S, P1.Name.all) then
-            P1 := P1.Next;
-
-         else
-            --  Here we have found one matching prefix, so see if there is
-            --  another one (which is an ambiguity)
-
-            P2 := P1.Next;
-            while P2 /= null loop
-               if Match_Prefix (S, P2.Name.all) then
-                  if not Quiet then
-                     Put (Standard_Error, "ambiguous ");
-                     Err;
-                     Put (Standard_Error, " (matches ");
-                     Put (Standard_Error, P1.Name.all);
-
-                     while P2 /= null loop
-                        if Match_Prefix (S, P2.Name.all) then
-                           Put (Standard_Error, ',');
-                           Put (Standard_Error, P2.Name.all);
-                        end if;
+                     Project_Loop : loop
+                        declare
+                           Dir : constant String :=
+                                   Get_Name_String
+                                     (Project_Tree.Projects.Table
+                                        (Prj).Object_Directory.Name);
+                        begin
+                           if Is_Regular_File
+                                (Dir &
+                                 Directory_Separator &
+                                 ALI_File (1 .. Last))
+                           then
+                              --  We have found the correct project, so we
+                              --  replace the file with the absolute path.
+
+                              Last_Switches.Table (J) :=
+                                new String'
+                                  (Dir & Directory_Separator &
+                                   ALI_File (1 .. Last));
+
+                              --  And we are done
+
+                              exit Switch_Loop;
+                           end if;
+                        end;
 
-                        P2 := P2.Next;
-                     end loop;
+                        --  Go to the project being extended, if any
 
-                     Put_Line (Standard_Error, ")");
+                        Prj :=
+                          Project_Tree.Projects.Table (Prj).Extends;
+                        exit Project_Loop when Prj = No_Project;
+                     end loop Project_Loop;
                   end if;
-
-                  return null;
                end if;
+            end;
+         end if;
+      end loop Switch_Loop;
 
-               P2 := P2.Next;
-            end loop;
-
-            --  If we fall through that loop, then there was only one match
+      --  If a relative path output file has been specified, we add the exec
+      --  directory.
 
-            return P1;
+      for J in reverse 1 .. Last_Switches.Last - 1 loop
+         if Last_Switches.Table (J).all = "-o" then
+            Check_Relative_Executable
+              (Name => Last_Switches.Table (J + 1));
+            Look_For_Executable := False;
+            exit;
          end if;
       end loop;
 
-      --  If we fall through outer loop, there was no match
-
-      if not Quiet then
-         Put (Standard_Error, "unrecognized ");
-         Err;
-         New_Line (Standard_Error);
-      end if;
-
-      return null;
-   end Matching_Name;
-
-   -----------------------
-   -- OK_Alphanumerplus --
-   -----------------------
-
-   function OK_Alphanumerplus (S : String) return Boolean is
-   begin
-      if S'Length = 0 then
-         return False;
-
-      else
-         for J in S'Range loop
-            if not (Is_Alphanumeric (S (J)) or else
-                    S (J) = '_' or else S (J) = '$')
-            then
-               return False;
+      if Look_For_Executable then
+         for J in reverse 1 .. First_Switches.Last - 1 loop
+            if First_Switches.Table (J).all = "-o" then
+               Look_For_Executable := False;
+               Check_Relative_Executable
+                 (Name => First_Switches.Table (J + 1));
+               exit;
             end if;
          end loop;
-
-         return True;
       end if;
-   end OK_Alphanumerplus;
 
-   ----------------
-   -- OK_Integer --
-   ----------------
+      --  If no executable is specified, then find the name of the first ALI
+      --  file on the command line and issue a -o switch with the absolute path
+      --  of the executable in the exec directory.
 
-   function OK_Integer (S : String) return Boolean is
-   begin
-      if S'Length = 0 then
-         return False;
-
-      else
-         for J in S'Range loop
-            if not Is_Digit (S (J)) then
-               return False;
-            end if;
-         end loop;
-
-         return True;
-      end if;
-   end OK_Integer;
-
-   --------------------
-   -- Output_Version --
-   --------------------
-
-   procedure Output_Version is
-   begin
-      Put ("GNAT ");
-      Put (Gnatvsn.Gnat_Version_String);
-      Put_Line (" Copyright 1996-2002 Free Software Foundation, Inc.");
-   end Output_Version;
-
-   -----------
-   -- Place --
-   -----------
-
-   procedure Place (C : Character) is
-   begin
-      Buffer.Increment_Last;
-      Buffer.Table (Buffer.Last) := C;
-
-      --  Do not put a space as the first character in the buffer
-      if C = ' ' and then Buffer.Last = 1 then
-         Buffer.Decrement_Last;
-      end if;
-   end Place;
-
-   procedure Place (S : String) is
-   begin
-      for J in S'Range loop
-         Place (S (J));
-      end loop;
-   end Place;
-
-   -----------------
-   -- Place_Lower --
-   -----------------
-
-   procedure Place_Lower (S : String) is
-   begin
-      for J in S'Range loop
-         Place (To_Lower (S (J)));
-      end loop;
-   end Place_Lower;
-
-   -------------------------
-   -- Place_Unix_Switches --
-   -------------------------
-
-   procedure Place_Unix_Switches (S : String_Ptr) is
-      P1, P2, P3 : Natural;
-      Remove     : Boolean;
-      Slen       : Natural;
-
-   begin
-      P1 := S'First;
-      while P1 <= S'Last loop
-         if S (P1) = '!' then
-            P1 := P1 + 1;
-            Remove := True;
-         else
-            Remove := False;
-         end if;
-
-         P2 := P1;
-         pragma Assert (S (P1) = '-' or else S (P1) = '`');
-
-         while P2 < S'Last and then S (P2 + 1) /= ',' loop
-            P2 := P2 + 1;
-         end loop;
-
-         --  Switch is now in S (P1 .. P2)
-
-         Slen := P2 - P1 + 1;
+      if Look_For_Executable then
+         for J in 1 .. Last_Switches.Last loop
+            Arg  := Last_Switches.Table (J);
+            Last := 0;
 
-         if Remove then
-            P3 := 2;
-            while P3 <= Buffer.Last - Slen loop
-               if Buffer.Table (P3) = ' '
-                 and then String (Buffer.Table (P3 + 1 .. P3 + Slen)) =
-                                                             S (P1 .. P2)
-                 and then (P3 + Slen = Buffer.Last
-                             or else
-                           Buffer.Table (P3 + Slen + 1) = ' ')
+            if Arg'Length /= 0 and then Arg (Arg'First) /= '-' then
+               if Arg'Length > 4
+                 and then Arg (Arg'Last - 3 .. Arg'Last) = ".ali"
                then
-                  Buffer.Table (P3 .. Buffer.Last - Slen - 1) :=
-                    Buffer.Table (P3 + Slen + 1 .. Buffer.Last);
-                  Buffer.Set_Last (Buffer.Last - Slen - 1);
+                  Last := Arg'Last - 4;
 
-               else
-                  P3 := P3 + 1;
+               elsif Is_Regular_File (Arg.all & ".ali") then
+                  Last := Arg'Last;
                end if;
-            end loop;
-
-         else
-            Place (' ');
 
-            if S (P1) = '`' then
-               P1 := P1 + 1;
+               if Last /= 0 then
+                  Last_Switches.Increment_Last;
+                  Last_Switches.Table (Last_Switches.Last) :=
+                    new String'("-o");
+                  Get_Name_String
+                    (Project_Tree.Projects.Table
+                       (Project).Exec_Directory.Name);
+                  Last_Switches.Increment_Last;
+                  Last_Switches.Table (Last_Switches.Last) :=
+                    new String'(Name_Buffer (1 .. Name_Len) &
+                                Directory_Separator &
+                                Executable_Name
+                                  (Base_Name (Arg (Arg'First .. Last))));
+                  exit;
+               end if;
             end if;
-
-            Place (S (P1 .. P2));
-         end if;
-
-         P1 := P2 + 2;
-      end loop;
-   end Place_Unix_Switches;
+         end loop;
+      end if;
+   end Process_Link;
 
    ---------------------
    -- Set_Library_For --
@@ -2311,10 +1209,13 @@ procedure GNATCmd is
      (Project             : Project_Id;
       There_Are_Libraries : in out Boolean)
    is
+      Path_Option : constant String_Access :=
+                      MLib.Linker_Library_Path_Option;
+
    begin
       --  Case of library project
 
-      if Projects.Table (Project).Library then
+      if Project_Tree.Projects.Table (Project).Library then
          There_Are_Libraries := True;
 
          --  Add the -L switch
@@ -2323,7 +1224,8 @@ procedure GNATCmd is
          Last_Switches.Table (Last_Switches.Last) :=
            new String'("-L" &
                        Get_Name_String
-                       (Projects.Table (Project).Library_Dir));
+                         (Project_Tree.Projects.Table
+                            (Project).Library_Dir.Name));
 
          --  Add the -l switch
 
@@ -2331,252 +1233,90 @@ procedure GNATCmd is
          Last_Switches.Table (Last_Switches.Last) :=
            new String'("-l" &
                        Get_Name_String
-                       (Projects.Table (Project).Library_Name));
-
-         --  Add the Wl,-rpath switch if library non static
-
-         if Projects.Table (Project).Library_Kind /= Static then
-            declare
-               Option : constant String_Access :=
-                          MLib.Tgt.Linker_Library_Path_Option
-                            (Get_Name_String
-                              (Projects.Table (Project).Library_Dir));
-
-            begin
-               if Option /= null then
-                  Last_Switches.Increment_Last;
-                  Last_Switches.Table (Last_Switches.Last) :=
-                    Option;
-               end if;
-
-            end;
-
+                         (Project_Tree.Projects.Table
+                            (Project).Library_Name));
+
+         --  Add the directory to table Library_Paths, to be processed later
+         --  if library is not static and if Path_Option is not null.
+
+         if Project_Tree.Projects.Table (Project).Library_Kind /=
+              Static
+           and then Path_Option /= null
+         then
+            Library_Paths.Increment_Last;
+            Library_Paths.Table (Library_Paths.Last) :=
+              new String'(Get_Name_String
+                            (Project_Tree.Projects.Table
+                               (Project).Library_Dir.Name));
          end if;
-
       end if;
    end Set_Library_For;
 
-   --------------------------------
-   -- Validate_Command_Or_Option --
-   --------------------------------
+   ---------------------------
+   -- Test_If_Relative_Path --
+   ---------------------------
 
-   procedure Validate_Command_Or_Option (N : String_Ptr) is
+   procedure Test_If_Relative_Path
+     (Switch : in out String_Access;
+      Parent : String)
+   is
    begin
-      pragma Assert (N'Length > 0);
+      if Switch /= null then
 
-      for J in N'Range loop
-         if N (J) = '_' then
-            pragma Assert (N (J - 1) /= '_');
-            null;
-         else
-            pragma Assert (Is_Upper (N (J)) or else Is_Digit (N (J)));
-            null;
-         end if;
-      end loop;
-   end Validate_Command_Or_Option;
+         declare
+            Sw : String (1 .. Switch'Length);
+            Start : Positive := 1;
 
-   --------------------------
-   -- Validate_Unix_Switch --
-   --------------------------
+         begin
+            Sw := Switch.all;
 
-   procedure Validate_Unix_Switch (S : String_Ptr) is
-   begin
-      if S (S'First) = '`' then
-         return;
-      end if;
+            if Sw (1) = '-' then
+               if Sw'Length >= 3
+                 and then (Sw (2) = 'A' or else
+                           Sw (2) = 'I' or else
+                           Sw (2) = 'L')
+               then
+                  Start := 3;
 
-      pragma Assert (S (S'First) = '-' or else S (S'First) = '!');
+                  if Sw = "-I-" then
+                     return;
+                  end if;
 
-      for J in S'First + 1 .. S'Last loop
-         pragma Assert (S (J) /= ' ');
+               elsif Sw'Length >= 4
+                 and then (Sw (2 .. 3) = "aL" or else
+                           Sw (2 .. 3) = "aO" or else
+                           Sw (2 .. 3) = "aI")
+               then
+                  Start := 4;
 
-         if S (J) = '!' then
-            pragma Assert (S (J - 1) = ',' and then S (J + 1) = '-');
-            null;
-         end if;
-      end loop;
-   end Validate_Unix_Switch;
-
-   ----------------------
-   -- List of Commands --
-   ----------------------
-
-   --  Note that we put this after all the local bodies (except Non_VMS_Usage
-   --  and VMS_Conversion that use Command_List) to avoid some access before
-   --  elaboration problems.
-
-   Command_List : constant array (Real_Command_Type) of Command_Entry :=
-     (Bind =>
-       (Cname    => new S'("BIND"),
-        Usage    => new S'("GNAT BIND file[.ali] /qualifiers"),
-        VMS_Only => False,
-        Unixcmd  => new S'("gnatbind"),
-        Unixsws  => null,
-        Switches => Bind_Switches'Access,
-        Params   => new Parameter_Array'(1 => File),
-        Defext   => "ali"),
-
-      Chop =>
-        (Cname    => new S'("CHOP"),
-         Usage    => new S'("GNAT CHOP file [directory] /qualifiers"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatchop"),
-         Unixsws  => null,
-         Switches => Chop_Switches'Access,
-         Params   => new Parameter_Array'(1 => File, 2 => Optional_File),
-         Defext   => "   "),
-
-      Compile =>
-        (Cname    => new S'("COMPILE"),
-         Usage    => new S'("GNAT COMPILE filespec[,...] /qualifiers"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatmake"),
-         Unixsws  => new Argument_List' (1 => new String'("-f"),
-                                         2 => new String'("-u"),
-                                         3 => new String'("-c")),
-         Switches => GCC_Switches'Access,
-         Params   => new Parameter_Array'(1 => Files_Or_Wildcard),
-         Defext   => "   "),
-
-      Elim =>
-        (Cname    => new S'("ELIM"),
-         Usage    => new S'("GNAT ELIM name /qualifiers"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatelim"),
-         Unixsws  => null,
-         Switches => Elim_Switches'Access,
-         Params   => new Parameter_Array'(1 => Other_As_Is),
-         Defext   => "ali"),
-
-      Find =>
-        (Cname    => new S'("FIND"),
-         Usage    => new S'("GNAT FIND pattern[:sourcefile[:line"
-                            & "[:column]]] filespec[,...] /qualifiers"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatfind"),
-         Unixsws  => null,
-         Switches => Find_Switches'Access,
-         Params   => new Parameter_Array'(1 => Other_As_Is,
-                                          2 => Files_Or_Wildcard),
-         Defext   => "ali"),
-
-      Krunch =>
-        (Cname    => new S'("KRUNCH"),
-         Usage    => new S'("GNAT KRUNCH file [/COUNT=nnn]"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatkr"),
-         Unixsws  => null,
-         Switches => Krunch_Switches'Access,
-         Params   => new Parameter_Array'(1 => File),
-         Defext   => "   "),
-
-      Library =>
-        (Cname    => new S'("LIBRARY"),
-         Usage    => new S'("GNAT LIBRARY /[CREATE | SET | DELETE]"
-                            & "=directory [/CONFIG=file]"),
-         VMS_Only => True,
-         Unixcmd  => new S'("gnatlbr"),
-         Unixsws  => null,
-         Switches => Lbr_Switches'Access,
-         Params   => new Parameter_Array'(1 .. 0 => File),
-         Defext   => "   "),
-
-      Link =>
-        (Cname    => new S'("LINK"),
-         Usage    => new S'("GNAT LINK file[.ali]"
-                            & " [extra obj_&_lib_&_exe_&_opt files]"
-                            & " /qualifiers"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatlink"),
-         Unixsws  => null,
-         Switches => Link_Switches'Access,
-         Params   => new Parameter_Array'(1 => Unlimited_Files),
-         Defext   => "ali"),
-
-      List =>
-        (Cname    => new S'("LIST"),
-         Usage    => new S'("GNAT LIST /qualifiers object_or_ali_file"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatls"),
-         Unixsws  => null,
-         Switches => List_Switches'Access,
-         Params   => new Parameter_Array'(1 => File),
-         Defext   => "ali"),
-
-      Make =>
-        (Cname    => new S'("MAKE"),
-         Usage    => new S'("GNAT MAKE file /qualifiers (includes "
-                            & "COMPILE /qualifiers)"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatmake"),
-         Unixsws  => null,
-         Switches => Make_Switches'Access,
-         Params   => new Parameter_Array'(1 => File),
-         Defext   => "   "),
-
-      Name =>
-        (Cname    => new S'("NAME"),
-         Usage    => new S'("GNAT NAME /qualifiers naming-pattern "
-                            & "[naming-patterns]"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatname"),
-         Unixsws  => null,
-         Switches => Name_Switches'Access,
-         Params   => new Parameter_Array'(1 => Unlimited_As_Is),
-         Defext   => "   "),
-
-      Preprocess =>
-        (Cname    => new S'("PREPROCESS"),
-         Usage    => new S'("GNAT PREPROCESS ifile ofile dfile /qualifiers"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatprep"),
-         Unixsws  => null,
-         Switches => Prep_Switches'Access,
-         Params   => new Parameter_Array'(1 .. 3 => File),
-         Defext   => "   "),
-
-      Shared =>
-        (Cname    => new S'("SHARED"),
-         Usage    => new S'("GNAT SHARED [obj_&_lib_&_exe_&_opt"
-                            & "files] /qualifiers"),
-         VMS_Only => True,
-         Unixcmd  => new S'("gcc"),
-         Unixsws  => new Argument_List'(new String'("-shared")
-                                        & Init_Object_Dirs),
-         Switches => Shared_Switches'Access,
-         Params   => new Parameter_Array'(1 => Unlimited_Files),
-         Defext   => "   "),
-
-      Standard =>
-        (Cname    => new S'("STANDARD"),
-         Usage    => new S'("GNAT STANDARD"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatpsta"),
-         Unixsws  => null,
-         Switches => Standard_Switches'Access,
-         Params   => new Parameter_Array'(1 .. 0 => File),
-         Defext   => "   "),
-
-      Stub =>
-        (Cname    => new S'("STUB"),
-         Usage    => new S'("GNAT STUB file [directory]/qualifiers"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatstub"),
-         Unixsws  => null,
-         Switches => Stub_Switches'Access,
-         Params   => new Parameter_Array'(1 => File, 2 => Optional_File),
-         Defext   => "   "),
-
-      Xref =>
-        (Cname    => new S'("XREF"),
-         Usage    => new S'("GNAT XREF filespec[,...] /qualifiers"),
-         VMS_Only => False,
-         Unixcmd  => new S'("gnatxref"),
-         Unixsws  => null,
-         Switches => Xref_Switches'Access,
-         Params   => new Parameter_Array'(1 => Files_Or_Wildcard),
-         Defext   => "ali")
-      );
+               elsif Sw'Length >= 7
+                 and then Sw (2 .. 6) = "-RTS="
+               then
+                  Start := 7;
+               else
+                  return;
+               end if;
+            end if;
+
+            --  If the path is relative, test if it includes directory
+            --  information. If it does, prepend Parent to the path.
+
+            if not Is_Absolute_Path (Sw (Start .. Sw'Last)) then
+               for J in Start .. Sw'Last loop
+                  if Sw (J) = Directory_Separator then
+                     Switch :=
+                        new String'
+                              (Sw (1 .. Start - 1) &
+                               Parent &
+                               Directory_Separator &
+                               Sw (Start .. Sw'Last));
+                     return;
+                  end if;
+               end loop;
+            end if;
+         end;
+      end if;
+   end Test_If_Relative_Path;
 
    -------------------
    -- Non_VMS_Usage --
@@ -2591,9 +1331,22 @@ procedure GNATCmd is
 
       for C in Command_List'Range loop
          if not Command_List (C).VMS_Only then
-            Put ("GNAT " & Command_List (C).Cname.all);
+            if Targparm.AAMP_On_Target then
+               Put ("gnaampcmd ");
+            else
+               Put ("gnat ");
+            end if;
+
+            Put (To_Lower (Command_List (C).Cname.all));
             Set_Col (25);
-            Put (Command_List (C).Unixcmd.all);
+
+            --  Never call gnatstack with a prefix
+
+            if C = Stack then
+               Put (Command_List (C).Unixcmd.all);
+            else
+               Put (Program_Name (Command_List (C).Unixcmd.all, "gnat").all);
+            end if;
 
             declare
                Sws : Argument_List_Access renames Command_List (C).Unixsws;
@@ -2611,1228 +1364,79 @@ procedure GNATCmd is
       end loop;
 
       New_Line;
-      Put_Line ("Commands FIND, LIST and XREF accept project file " &
-                "switches -vPx, -Pprj and -Xnam=val");
+      Put_Line ("Commands find, list, metric, pretty, stack, stub and xref " &
+                "accept project file switches -vPx, -Pprj and -Xnam=val");
       New_Line;
    end Non_VMS_Usage;
 
-   --------------------
-   -- VMS_Conversion --
-   --------------------
-
-   procedure VMS_Conversion (The_Command : out Command_Type) is
-   begin
-      Buffer.Init;
-
-      --  First we must preprocess the string form of the command and options
-      --  list into the internal form that we use.
-
-      for C in Real_Command_Type loop
+   -------------------------------------
+   -- Start of processing for GNATCmd --
+   -------------------------------------
 
-         declare
-            Command : Item_Ptr := new Command_Item;
+begin
+   --  Initializations
 
-            Last_Switch : Item_Ptr;
-            --  Last switch in list
+   Namet.Initialize;
+   Csets.Initialize;
 
-         begin
-            --  Link new command item into list of commands
+   Snames.Initialize;
 
-            if Last_Command = null then
-               Commands := Command;
-            else
-               Last_Command.Next := Command;
-            end if;
+   Prj.Initialize (Project_Tree);
 
-            Last_Command := Command;
+   Last_Switches.Init;
+   Last_Switches.Set_Last (0);
 
-            --  Fill in fields of new command item
+   First_Switches.Init;
+   First_Switches.Set_Last (0);
+   Carg_Switches.Init;
+   Carg_Switches.Set_Last (0);
+   Rules_Switches.Init;
+   Rules_Switches.Set_Last (0);
 
-            Command.Name    := Command_List (C).Cname;
-            Command.Usage   := Command_List (C).Usage;
-            Command.Command := C;
+   VMS_Conv.Initialize;
 
-            if Command_List (C).Unixsws = null then
-               Command.Unix_String := Command_List (C).Unixcmd;
-            else
-               declare
-                  Cmd  : String (1 .. 5_000);
-                  Last : Natural := 0;
-                  Sws  : Argument_List_Access := Command_List (C).Unixsws;
+   Set_Mode (Ada_Only);
 
-               begin
-                  Cmd (1 .. Command_List (C).Unixcmd'Length) :=
-                    Command_List (C).Unixcmd.all;
-                  Last := Command_List (C).Unixcmd'Length;
+   --  Add the default search directories, to be able to find system.ads in the
+   --  subsequent call to Targparm.Get_Target_Parameters.
 
-                  for J in Sws'Range loop
-                     Last := Last + 1;
-                     Cmd (Last) := ' ';
-                     Cmd (Last + 1 .. Last + Sws (J)'Length) :=
-                       Sws (J).all;
-                     Last := Last + Sws (J)'Length;
-                  end loop;
+   Add_Default_Search_Dirs;
 
-                  Command.Unix_String := new String'(Cmd (1 .. Last));
-               end;
-            end if;
+   --  Get target parameters so that AAMP_On_Target will be set, for testing in
+   --  Osint.Program_Name to handle the mapping of GNAAMP tool names.
 
-            Command.Params := Command_List (C).Params;
-            Command.Defext := Command_List (C).Defext;
+   Targparm.Get_Target_Parameters;
 
-            Validate_Command_Or_Option (Command.Name);
+   --  Add the directory where the GNAT driver is invoked in front of the path,
+   --  if the GNAT driver is invoked with directory information. Do not do this
+   --  for VMS, where the notion of path does not really exist.
 
-            --  Process the switch list
+   if not OpenVMS then
+      declare
+         Command : constant String := Command_Name;
 
-            for S in Command_List (C).Switches'Range loop
+      begin
+         for Index in reverse Command'Range loop
+            if Command (Index) = Directory_Separator then
                declare
-                  SS : constant String_Ptr := Command_List (C).Switches (S);
-
-                  P  : Natural := SS'First;
-                  Sw : Item_Ptr := new Switch_Item;
+                  Absolute_Dir : constant String :=
+                                   Normalize_Pathname
+                                     (Command (Command'First .. Index));
 
-                  Last_Opt : Item_Ptr;
-                  --  Pointer to last option
+                  PATH         : constant String :=
+                                   Absolute_Dir &
+                  Path_Separator &
+                  Getenv ("PATH").all;
 
                begin
-                  --  Link new switch item into list of switches
-
-                  if Last_Switch = null then
-                     Command.Switches := Sw;
-                  else
-                     Last_Switch.Next := Sw;
-                  end if;
-
-                  Last_Switch := Sw;
-
-                  --  Process switch string, first get name
-
-                  while SS (P) /= ' ' and SS (P) /= '=' loop
-                     P := P + 1;
-                  end loop;
-
-                  Sw.Name := new String'(SS (SS'First .. P - 1));
-
-                  --  Direct translation case
-
-                  if SS (P) = ' ' then
-                     Sw.Translation := T_Direct;
-                     Sw.Unix_String := new String'(SS (P + 1 .. SS'Last));
-                     Validate_Unix_Switch (Sw.Unix_String);
-
-                     if SS (P - 1) = '>' then
-                        Sw.Translation := T_Other;
-
-                     elsif SS (P + 1) = '`' then
-                        null;
-
-                        --  Create the inverted case (/NO ..)
-
-                     elsif SS (SS'First + 1 .. SS'First + 2) /= "NO" then
-                        Sw := new Switch_Item;
-                        Last_Switch.Next := Sw;
-                        Last_Switch := Sw;
-
-                        Sw.Name :=
-                          new String'("/NO" & SS (SS'First + 1 .. P - 1));
-                        Sw.Translation := T_Direct;
-                        Sw.Unix_String := Invert_Sense (SS (P + 1 .. SS'Last));
-                        Validate_Unix_Switch (Sw.Unix_String);
-                     end if;
-
-                     --  Directories translation case
-
-                  elsif SS (P + 1) = '*' then
-                     pragma Assert (SS (SS'Last) = '*');
-                     Sw.Translation := T_Directories;
-                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
-                     Validate_Unix_Switch (Sw.Unix_String);
-
-                     --  Directory translation case
-
-                  elsif SS (P + 1) = '%' then
-                     pragma Assert (SS (SS'Last) = '%');
-                     Sw.Translation := T_Directory;
-                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
-                     Validate_Unix_Switch (Sw.Unix_String);
-
-                     --  File translation case
-
-                  elsif SS (P + 1) = '@' then
-                     pragma Assert (SS (SS'Last) = '@');
-                     Sw.Translation := T_File;
-                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
-                     Validate_Unix_Switch (Sw.Unix_String);
-
-                     --  No space file translation case
-
-                  elsif SS (P + 1) = '<' then
-                     pragma Assert (SS (SS'Last) = '>');
-                     Sw.Translation := T_No_Space_File;
-                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
-                     Validate_Unix_Switch (Sw.Unix_String);
-
-                     --  Numeric translation case
-
-                  elsif SS (P + 1) = '#' then
-                     pragma Assert (SS (SS'Last) = '#');
-                     Sw.Translation := T_Numeric;
-                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
-                     Validate_Unix_Switch (Sw.Unix_String);
-
-                     --  Alphanumerplus translation case
-
-                  elsif SS (P + 1) = '|' then
-                     pragma Assert (SS (SS'Last) = '|');
-                     Sw.Translation := T_Alphanumplus;
-                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
-                     Validate_Unix_Switch (Sw.Unix_String);
-
-                     --  String translation case
-
-                  elsif SS (P + 1) = '"' then
-                     pragma Assert (SS (SS'Last) = '"');
-                     Sw.Translation := T_String;
-                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last - 1));
-                     Validate_Unix_Switch (Sw.Unix_String);
-
-                     --  Commands translation case
-
-                  elsif SS (P + 1) = '?' then
-                     Sw.Translation := T_Commands;
-                     Sw.Unix_String := new String'(SS (P + 2 .. SS'Last));
-
-                     --  Options translation case
-
-                  else
-                     Sw.Translation := T_Options;
-                     Sw.Unix_String := new String'("");
-
-                     P := P + 1; -- bump past =
-                     while P <= SS'Last loop
-                        declare
-                           Opt : Item_Ptr := new Option_Item;
-                           Q   : Natural;
-
-                        begin
-                           --  Link new option item into options list
-
-                           if Last_Opt = null then
-                              Sw.Options := Opt;
-                           else
-                              Last_Opt.Next := Opt;
-                           end if;
-
-                           Last_Opt := Opt;
-
-                           --  Fill in fields of new option item
-
-                           Q := P;
-                           while SS (Q) /= ' ' loop
-                              Q := Q + 1;
-                           end loop;
-
-                           Opt.Name := new String'(SS (P .. Q - 1));
-                           Validate_Command_Or_Option (Opt.Name);
-
-                           P := Q + 1;
-                           Q := P;
-
-                           while Q <= SS'Last and then SS (Q) /= ' ' loop
-                              Q := Q + 1;
-                           end loop;
-
-                           Opt.Unix_String := new String'(SS (P .. Q - 1));
-                           Validate_Unix_Switch (Opt.Unix_String);
-                           P := Q + 1;
-                        end;
-                     end loop;
-                  end if;
+                  Setenv ("PATH", PATH);
                end;
-            end loop;
-         end;
-      end loop;
-
-      --  If no parameters, give complete list of commands
 
-      if Argument_Count = 0 then
-         Output_Version;
-         New_Line;
-         Put_Line ("List of available commands");
-         New_Line;
-
-         while Commands /= null loop
-            Put (Commands.Usage.all);
-            Set_Col (53);
-            Put_Line (Commands.Unix_String.all);
-            Commands := Commands.Next;
+               exit;
+            end if;
          end loop;
-
-         raise Normal_Exit;
-      end if;
-
-      Arg_Num := 1;
-
-      --  Loop through arguments
-
-      while Arg_Num <= Argument_Count loop
-
-         Process_Argument : declare
-            Argv    : String_Access;
-            Arg_Idx : Integer;
-
-            function Get_Arg_End
-              (Argv    : String;
-               Arg_Idx : Integer)
-               return    Integer;
-            --  Begins looking at Arg_Idx + 1 and returns the index of the
-            --  last character before a slash or else the index of the last
-            --  character in the string Argv.
-
-            -----------------
-            -- Get_Arg_End --
-            -----------------
-
-            function Get_Arg_End
-              (Argv    : String;
-               Arg_Idx : Integer)
-              return    Integer
-            is
-            begin
-               for J in Arg_Idx + 1 .. Argv'Last loop
-                  if Argv (J) = '/' then
-                     return J - 1;
-                  end if;
-               end loop;
-
-               return Argv'Last;
-            end Get_Arg_End;
-
-         --  Start of processing for Process_Argument
-
-         begin
-            Argv := new String'(Argument (Arg_Num));
-            Arg_Idx := Argv'First;
-
-            <<Tryagain_After_Coalesce>>
-               loop
-                  declare
-                     Next_Arg_Idx : Integer;
-                     Arg          : String_Access;
-
-                  begin
-                     Next_Arg_Idx := Get_Arg_End (Argv.all, Arg_Idx);
-                     Arg := new String'(Argv (Arg_Idx .. Next_Arg_Idx));
-
-                     --  The first one must be a command name
-
-                     if Arg_Num = 1 and then Arg_Idx = Argv'First then
-
-                        Command := Matching_Name (Arg.all, Commands);
-
-                        if Command = null then
-                           raise Error_Exit;
-                        end if;
-
-                        The_Command := Command.Command;
-
-                        --  Give usage information if only command given
-
-                        if Argument_Count = 1 and then Next_Arg_Idx = Argv'Last
-                          and then Command.Command /= Standard
-                        then
-                           Output_Version;
-                           New_Line;
-                           Put_Line
-                             ("List of available qualifiers and options");
-                           New_Line;
-
-                           Put (Command.Usage.all);
-                           Set_Col (53);
-                           Put_Line (Command.Unix_String.all);
-
-                           declare
-                              Sw : Item_Ptr := Command.Switches;
-
-                           begin
-                              while Sw /= null loop
-                                 Put ("   ");
-                                 Put (Sw.Name.all);
-
-                                 case Sw.Translation is
-
-                                    when T_Other =>
-                                       Set_Col (53);
-                                       Put_Line (Sw.Unix_String.all &
-                                                 "/<other>");
-
-                                    when T_Direct =>
-                                       Set_Col (53);
-                                       Put_Line (Sw.Unix_String.all);
-
-                                    when T_Directories =>
-                                       Put ("=(direc,direc,..direc)");
-                                       Set_Col (53);
-                                       Put (Sw.Unix_String.all);
-                                       Put (" direc ");
-                                       Put (Sw.Unix_String.all);
-                                       Put_Line (" direc ...");
-
-                                    when T_Directory =>
-                                       Put ("=directory");
-                                       Set_Col (53);
-                                       Put (Sw.Unix_String.all);
-
-                                       if Sw.Unix_String (Sw.Unix_String'Last)
-                                         /= '='
-                                       then
-                                          Put (' ');
-                                       end if;
-
-                                       Put_Line ("directory ");
-
-                                    when T_File | T_No_Space_File =>
-                                       Put ("=file");
-                                       Set_Col (53);
-                                       Put (Sw.Unix_String.all);
-
-                                       if Sw.Translation = T_File
-                                         and then Sw.Unix_String
-                                                   (Sw.Unix_String'Last)
-                                                     /= '='
-                                       then
-                                          Put (' ');
-                                       end if;
-
-                                       Put_Line ("file ");
-
-                                    when T_Numeric =>
-                                       Put ("=nnn");
-                                       Set_Col (53);
-
-                                       if Sw.Unix_String (Sw.Unix_String'First)
-                                         = '`'
-                                       then
-                                          Put (Sw.Unix_String
-                                               (Sw.Unix_String'First + 1
-                                                .. Sw.Unix_String'Last));
-                                       else
-                                          Put (Sw.Unix_String.all);
-                                       end if;
-
-                                       Put_Line ("nnn");
-
-                                    when T_Alphanumplus =>
-                                       Put ("=xyz");
-                                       Set_Col (53);
-
-                                       if Sw.Unix_String (Sw.Unix_String'First)
-                                         = '`'
-                                       then
-                                          Put (Sw.Unix_String
-                                               (Sw.Unix_String'First + 1
-                                                .. Sw.Unix_String'Last));
-                                       else
-                                          Put (Sw.Unix_String.all);
-                                       end if;
-
-                                       Put_Line ("xyz");
-
-                                    when T_String =>
-                                       Put ("=");
-                                       Put ('"');
-                                       Put ("<string>");
-                                       Put ('"');
-                                       Set_Col (53);
-
-                                       Put (Sw.Unix_String.all);
-
-                                       if Sw.Unix_String (Sw.Unix_String'Last)
-                                         /= '='
-                                       then
-                                          Put (' ');
-                                       end if;
-
-                                       Put ("<string>");
-                                       New_Line;
-
-                                    when T_Commands =>
-                                       Put (" (switches for ");
-                                       Put (Sw.Unix_String
-                                            (Sw.Unix_String'First + 7
-                                             .. Sw.Unix_String'Last));
-                                       Put (')');
-                                       Set_Col (53);
-                                       Put (Sw.Unix_String
-                                            (Sw.Unix_String'First
-                                             .. Sw.Unix_String'First + 5));
-                                       Put_Line (" switches");
-
-                                    when T_Options =>
-                                       declare
-                                          Opt : Item_Ptr := Sw.Options;
-
-                                       begin
-                                          Put_Line ("=(option,option..)");
-
-                                          while Opt /= null loop
-                                             Put ("      ");
-                                             Put (Opt.Name.all);
-
-                                             if Opt = Sw.Options then
-                                                Put (" (D)");
-                                             end if;
-
-                                             Set_Col (53);
-                                             Put_Line (Opt.Unix_String.all);
-                                             Opt := Opt.Next;
-                                          end loop;
-                                       end;
-
-                                 end case;
-
-                                 Sw := Sw.Next;
-                              end loop;
-                           end;
-
-                           raise Normal_Exit;
-                        end if;
-
-                        --  Place (Command.Unix_String.all);
-
-                        --  Special handling for internal debugging switch /?
-
-                     elsif Arg.all = "/?" then
-                        Display_Command := True;
-
-                        --  Copy -switch unchanged
-
-                     elsif Arg (Arg'First) = '-' then
-                        Place (' ');
-                        Place (Arg.all);
-
-                        --  Copy quoted switch with quotes stripped
-
-                     elsif Arg (Arg'First) = '"' then
-                        if Arg (Arg'Last) /= '"' then
-                           Put (Standard_Error, "misquoted argument: ");
-                           Put_Line (Standard_Error, Arg.all);
-                           Errors := Errors + 1;
-
-                        else
-                           Place (' ');
-                           Place (Arg (Arg'First + 1 .. Arg'Last - 1));
-                        end if;
-
-                        --  Parameter Argument
-
-                     elsif Arg (Arg'First) /= '/'
-                       and then Make_Commands_Active = null
-                     then
-                        Param_Count := Param_Count + 1;
-
-                        if Param_Count <= Command.Params'Length then
-
-                           case Command.Params (Param_Count) is
-
-                              when File | Optional_File =>
-                                 declare
-                                    Normal_File : String_Access
-                                      := To_Canonical_File_Spec (Arg.all);
-                                 begin
-                                    Place (' ');
-                                    Place_Lower (Normal_File.all);
-
-                                    if Is_Extensionless (Normal_File.all)
-                                      and then Command.Defext /= "   "
-                                    then
-                                       Place ('.');
-                                       Place (Command.Defext);
-                                    end if;
-                                 end;
-
-                              when Unlimited_Files =>
-                                 declare
-                                    Normal_File : String_Access
-                                      := To_Canonical_File_Spec (Arg.all);
-
-                                    File_Is_Wild  : Boolean := False;
-                                    File_List     : String_Access_List_Access;
-                                 begin
-                                    for I in Arg'Range loop
-                                       if Arg (I) = '*'
-                                         or else Arg (I) = '%'
-                                       then
-                                          File_Is_Wild := True;
-                                       end if;
-                                    end loop;
-
-                                    if File_Is_Wild then
-                                       File_List := To_Canonical_File_List
-                                         (Arg.all, False);
-
-                                       for I in File_List.all'Range loop
-                                          Place (' ');
-                                          Place_Lower (File_List.all (I).all);
-                                       end loop;
-                                    else
-                                       Place (' ');
-                                       Place_Lower (Normal_File.all);
-
-                                       if Is_Extensionless (Normal_File.all)
-                                         and then Command.Defext /= "   "
-                                       then
-                                          Place ('.');
-                                          Place (Command.Defext);
-                                       end if;
-                                    end if;
-
-                                    Param_Count := Param_Count - 1;
-                                 end;
-
-                              when Other_As_Is =>
-                                 Place (' ');
-                                 Place (Arg.all);
-
-                              when Unlimited_As_Is =>
-                                 Place (' ');
-                                 Place (Arg.all);
-                                 Param_Count := Param_Count - 1;
-
-                              when Files_Or_Wildcard =>
-
-                                 --  Remove spaces from a comma separated list
-                                 --  of file names and adjust control variables
-                                 --  accordingly.
-
-                                 while Arg_Num < Argument_Count and then
-                                   (Argv (Argv'Last) = ',' xor
-                                    Argument (Arg_Num + 1)
-                                      (Argument (Arg_Num + 1)'First) = ',')
-                                 loop
-                                    Argv := new String'
-                                           (Argv.all & Argument (Arg_Num + 1));
-                                    Arg_Num := Arg_Num + 1;
-                                    Arg_Idx := Argv'First;
-                                    Next_Arg_Idx :=
-                                      Get_Arg_End (Argv.all, Arg_Idx);
-                                    Arg := new String'
-                                            (Argv (Arg_Idx .. Next_Arg_Idx));
-                                 end loop;
-
-                                 --  Parse the comma separated list of VMS
-                                 --  filenames and place them on the command
-                                 --  line as space separated Unix style
-                                 --  filenames. Lower case and add default
-                                 --  extension as appropriate.
-
-                                 declare
-                                    Arg1_Idx : Integer := Arg'First;
-
-                                    function Get_Arg1_End
-                                      (Arg : String; Arg_Idx : Integer)
-                                      return Integer;
-                                    --  Begins looking at Arg_Idx + 1 and
-                                    --  returns the index of the last character
-                                    --  before a comma or else the index of the
-                                    --  last character in the string Arg.
-
-                                    function Get_Arg1_End
-                                      (Arg : String; Arg_Idx : Integer)
-                                      return Integer
-                                    is
-                                    begin
-                                       for I in Arg_Idx + 1 .. Arg'Last loop
-                                          if Arg (I) = ',' then
-                                             return I - 1;
-                                          end if;
-                                       end loop;
-
-                                       return Arg'Last;
-                                    end Get_Arg1_End;
-
-                                 begin
-                                    loop
-                                       declare
-                                          Next_Arg1_Idx : Integer :=
-                                            Get_Arg1_End (Arg.all, Arg1_Idx);
-
-                                          Arg1 : String :=
-                                            Arg (Arg1_Idx .. Next_Arg1_Idx);
-
-                                          Normal_File : String_Access :=
-                                            To_Canonical_File_Spec (Arg1);
-
-                                       begin
-                                          Place (' ');
-                                          Place_Lower (Normal_File.all);
-
-                                          if Is_Extensionless (Normal_File.all)
-                                            and then Command.Defext /= "   "
-                                          then
-                                             Place ('.');
-                                             Place (Command.Defext);
-                                          end if;
-
-                                          Arg1_Idx := Next_Arg1_Idx + 1;
-                                       end;
-
-                                       exit when Arg1_Idx > Arg'Last;
-
-                                       --  Don't allow two or more commas in
-                                       --  a row
-
-                                       if Arg (Arg1_Idx) = ',' then
-                                          Arg1_Idx := Arg1_Idx + 1;
-                                          if Arg1_Idx > Arg'Last or else
-                                            Arg (Arg1_Idx) = ','
-                                          then
-                                             Put_Line
-                                               (Standard_Error,
-                                                "Malformed Parameter: " &
-                                                Arg.all);
-                                             Put (Standard_Error, "usage: ");
-                                             Put_Line (Standard_Error,
-                                                       Command.Usage.all);
-                                             raise Error_Exit;
-                                          end if;
-                                       end if;
-
-                                    end loop;
-                                 end;
-                           end case;
-                        end if;
-
-                        --  Qualifier argument
-
-                     else
-                        declare
-                           Sw   : Item_Ptr;
-                           SwP  : Natural;
-                           P2   : Natural;
-                           Endp : Natural := 0; -- avoid warning!
-                           Opt  : Item_Ptr;
-
-                        begin
-                           SwP := Arg'First;
-                           while SwP < Arg'Last
-                             and then Arg (SwP + 1) /= '='
-                           loop
-                              SwP := SwP + 1;
-                           end loop;
-
-                           --  At this point, the switch name is in
-                           --  Arg (Arg'First..SwP) and if that is not the
-                           --  whole switch, then there is an equal sign at
-                           --  Arg (SwP + 1) and the rest of Arg is what comes
-                           --  after the equal sign.
-
-                           --  If make commands are active, see if we have
-                           --  another COMMANDS_TRANSLATION switch belonging
-                           --  to gnatmake.
-
-                           if Make_Commands_Active /= null then
-                              Sw :=
-                                Matching_Name
-                                (Arg (Arg'First .. SwP),
-                                 Command.Switches,
-                                 Quiet => True);
-
-                              if Sw /= null
-                                and then Sw.Translation = T_Commands
-                              then
-                                 null;
-
-                              else
-                                 Sw :=
-                                   Matching_Name
-                                   (Arg (Arg'First .. SwP),
-                                    Make_Commands_Active.Switches,
-                                    Quiet => False);
-                              end if;
-
-                              --  For case of GNAT MAKE or CHOP, if we cannot
-                              --  find the switch, then see if it is a
-                              --  recognized compiler switch instead, and if
-                              --  so process the compiler switch.
-
-                           elsif Command.Name.all = "MAKE"
-                             or else Command.Name.all = "CHOP" then
-                              Sw :=
-                                Matching_Name
-                                (Arg (Arg'First .. SwP),
-                                 Command.Switches,
-                                 Quiet => True);
-
-                              if Sw = null then
-                                 Sw :=
-                                   Matching_Name
-                                   (Arg (Arg'First .. SwP),
-                                    Matching_Name
-                                      ("COMPILE", Commands).Switches,
-                                    Quiet => False);
-                              end if;
-
-                              --  For all other cases, just search the relevant
-                              --  command.
-
-                           else
-                              Sw :=
-                                Matching_Name
-                                (Arg (Arg'First .. SwP),
-                                 Command.Switches,
-                                 Quiet => False);
-                           end if;
-
-                           if Sw /= null then
-                              case Sw.Translation is
-
-                                 when T_Direct =>
-                                    Place_Unix_Switches (Sw.Unix_String);
-                                    if SwP < Arg'Last
-                                      and then Arg (SwP + 1) = '='
-                                    then
-                                       Put (Standard_Error,
-                                            "qualifier options ignored: ");
-                                       Put_Line (Standard_Error, Arg.all);
-                                    end if;
-
-                                 when T_Directories =>
-                                    if SwP + 1 > Arg'Last then
-                                       Put (Standard_Error,
-                                            "missing directories for: ");
-                                       Put_Line (Standard_Error, Arg.all);
-                                       Errors := Errors + 1;
-
-                                    elsif Arg (SwP + 2) /= '(' then
-                                       SwP := SwP + 2;
-                                       Endp := Arg'Last;
-
-                                    elsif Arg (Arg'Last) /= ')' then
-
-                                       --  Remove spaces from a comma separated
-                                       --  list of file names and adjust
-                                       --  control variables accordingly.
-
-                                       if Arg_Num < Argument_Count and then
-                                         (Argv (Argv'Last) = ',' xor
-                                          Argument (Arg_Num + 1)
-                                          (Argument (Arg_Num + 1)'First) = ',')
-                                       then
-                                          Argv :=
-                                            new String'(Argv.all
-                                                        & Argument
-                                                           (Arg_Num + 1));
-                                          Arg_Num := Arg_Num + 1;
-                                          Arg_Idx := Argv'First;
-                                          Next_Arg_Idx
-                                            := Get_Arg_End (Argv.all, Arg_Idx);
-                                          Arg := new String'
-                                            (Argv (Arg_Idx .. Next_Arg_Idx));
-                                          goto Tryagain_After_Coalesce;
-                                       end if;
-
-                                       Put (Standard_Error,
-                                            "incorrectly parenthesized " &
-                                            "or malformed argument: ");
-                                       Put_Line (Standard_Error, Arg.all);
-                                       Errors := Errors + 1;
-
-                                    else
-                                       SwP := SwP + 3;
-                                       Endp := Arg'Last - 1;
-                                    end if;
-
-                                    while SwP <= Endp loop
-                                       declare
-                                          Dir_Is_Wild       : Boolean := False;
-                                          Dir_Maybe_Is_Wild : Boolean := False;
-                                          Dir_List : String_Access_List_Access;
-                                       begin
-                                          P2 := SwP;
-
-                                          while P2 < Endp
-                                            and then Arg (P2 + 1) /= ','
-                                          loop
-
-                                             --  A wildcard directory spec on
-                                             --  VMS will contain either * or
-                                             --  % or ...
-
-                                             if Arg (P2) = '*' then
-                                                Dir_Is_Wild := True;
-
-                                             elsif Arg (P2) = '%' then
-                                                Dir_Is_Wild := True;
-
-                                             elsif Dir_Maybe_Is_Wild
-                                               and then Arg (P2) = '.'
-                                               and then Arg (P2 + 1) = '.'
-                                             then
-                                                Dir_Is_Wild := True;
-                                                Dir_Maybe_Is_Wild := False;
-
-                                             elsif Dir_Maybe_Is_Wild then
-                                                Dir_Maybe_Is_Wild := False;
-
-                                             elsif Arg (P2) = '.'
-                                               and then Arg (P2 + 1) = '.'
-                                             then
-                                                Dir_Maybe_Is_Wild := True;
-
-                                             end if;
-
-                                             P2 := P2 + 1;
-                                          end loop;
-
-                                          if (Dir_Is_Wild) then
-                                             Dir_List := To_Canonical_File_List
-                                               (Arg (SwP .. P2), True);
-
-                                             for I in Dir_List.all'Range loop
-                                                Place_Unix_Switches
-                                                  (Sw.Unix_String);
-                                                Place_Lower
-                                                  (Dir_List.all (I).all);
-                                             end loop;
-                                          else
-                                             Place_Unix_Switches
-                                               (Sw.Unix_String);
-                                             Place_Lower
-                                               (To_Canonical_Dir_Spec
-                                                (Arg (SwP .. P2), False).all);
-                                          end if;
-
-                                          SwP := P2 + 2;
-                                       end;
-                                    end loop;
-
-                                 when T_Directory =>
-                                    if SwP + 1 > Arg'Last then
-                                       Put (Standard_Error,
-                                            "missing directory for: ");
-                                       Put_Line (Standard_Error, Arg.all);
-                                       Errors := Errors + 1;
-
-                                    else
-                                       Place_Unix_Switches (Sw.Unix_String);
-
-                                       --  Some switches end in "=". No space
-                                       --  here
-
-                                       if Sw.Unix_String
-                                         (Sw.Unix_String'Last) /= '='
-                                       then
-                                          Place (' ');
-                                       end if;
-
-                                       Place_Lower
-                                         (To_Canonical_Dir_Spec
-                                          (Arg (SwP + 2 .. Arg'Last),
-                                           False).all);
-                                    end if;
-
-                                 when T_File | T_No_Space_File =>
-                                    if SwP + 1 > Arg'Last then
-                                       Put (Standard_Error,
-                                            "missing file for: ");
-                                       Put_Line (Standard_Error, Arg.all);
-                                       Errors := Errors + 1;
-
-                                    else
-                                       Place_Unix_Switches (Sw.Unix_String);
-
-                                       --  Some switches end in "=". No space
-                                       --  here.
-
-                                       if Sw.Translation = T_File
-                                         and then Sw.Unix_String
-                                                   (Sw.Unix_String'Last) /= '='
-                                       then
-                                          Place (' ');
-                                       end if;
-
-                                       Place_Lower
-                                         (To_Canonical_File_Spec
-                                          (Arg (SwP + 2 .. Arg'Last)).all);
-                                    end if;
-
-                                 when T_Numeric =>
-                                    if
-                                      OK_Integer (Arg (SwP + 2 .. Arg'Last))
-                                    then
-                                       Place_Unix_Switches (Sw.Unix_String);
-                                       Place (Arg (SwP + 2 .. Arg'Last));
-
-                                    else
-                                       Put (Standard_Error, "argument for ");
-                                       Put (Standard_Error, Sw.Name.all);
-                                       Put_Line
-                                         (Standard_Error, " must be numeric");
-                                       Errors := Errors + 1;
-                                    end if;
-
-                                 when T_Alphanumplus =>
-                                    if
-                                      OK_Alphanumerplus
-                                        (Arg (SwP + 2 .. Arg'Last))
-                                    then
-                                       Place_Unix_Switches (Sw.Unix_String);
-                                       Place (Arg (SwP + 2 .. Arg'Last));
-
-                                    else
-                                       Put (Standard_Error, "argument for ");
-                                       Put (Standard_Error, Sw.Name.all);
-                                       Put_Line (Standard_Error,
-                                                 " must be alphanumeric");
-                                       Errors := Errors + 1;
-                                    end if;
-
-                                 when T_String =>
-
-                                    --  A String value must be extended to the
-                                    --  end of the Argv, otherwise strings like
-                                    --  "foo/bar" get split at the slash.
-                                    --
-                                    --  The begining and ending of the string
-                                    --  are flagged with embedded nulls which
-                                    --  are removed when building the Spawn
-                                    --  call. Nulls are use because they won't
-                                    --  show up in a /? output. Quotes aren't
-                                    --  used because that would make it
-                                    --  difficult to embed them.
-
-                                    Place_Unix_Switches (Sw.Unix_String);
-                                    if Next_Arg_Idx /= Argv'Last then
-                                       Next_Arg_Idx := Argv'Last;
-                                       Arg := new String'
-                                         (Argv (Arg_Idx .. Next_Arg_Idx));
-
-                                       SwP := Arg'First;
-                                       while SwP < Arg'Last and then
-                                         Arg (SwP + 1) /= '=' loop
-                                          SwP := SwP + 1;
-                                       end loop;
-                                    end if;
-                                    Place (ASCII.NUL);
-                                    Place (Arg (SwP + 2 .. Arg'Last));
-                                    Place (ASCII.NUL);
-
-                                 when T_Commands =>
-
-                                    --  Output -largs/-bargs/-cargs
-
-                                    Place (' ');
-                                    Place (Sw.Unix_String
-                                           (Sw.Unix_String'First ..
-                                            Sw.Unix_String'First + 5));
-
-                                    --  Set source of new commands, also
-                                    --  setting this non-null indicates that
-                                    --  we are in the special commands mode
-                                    --  for processing the -xargs case.
-
-                                    Make_Commands_Active :=
-                                      Matching_Name
-                                      (Sw.Unix_String
-                                       (Sw.Unix_String'First + 7 ..
-                                        Sw.Unix_String'Last),
-                                       Commands);
-
-                                 when T_Options =>
-                                    if SwP + 1 > Arg'Last then
-                                       Place_Unix_Switches
-                                         (Sw.Options.Unix_String);
-                                       SwP := Endp + 1;
-
-                                    elsif Arg (SwP + 2) /= '(' then
-                                       SwP := SwP + 2;
-                                       Endp := Arg'Last;
-
-                                    elsif Arg (Arg'Last) /= ')' then
-                                       Put
-                                         (Standard_Error,
-                                          "incorrectly parenthesized " &
-                                          "argument: ");
-                                       Put_Line (Standard_Error, Arg.all);
-                                       Errors := Errors + 1;
-                                       SwP := Endp + 1;
-
-                                    else
-                                       SwP := SwP + 3;
-                                       Endp := Arg'Last - 1;
-                                    end if;
-
-                                    while SwP <= Endp loop
-                                       P2 := SwP;
-
-                                       while P2 < Endp
-                                         and then Arg (P2 + 1) /= ','
-                                       loop
-                                          P2 := P2 + 1;
-                                       end loop;
-
-                                       --  Option name is in Arg (SwP .. P2)
-
-                                       Opt := Matching_Name (Arg (SwP .. P2),
-                                                             Sw.Options);
-
-                                       if Opt /= null then
-                                          Place_Unix_Switches
-                                            (Opt.Unix_String);
-                                       end if;
-
-                                       SwP := P2 + 2;
-                                    end loop;
-
-                                 when T_Other =>
-                                    Place_Unix_Switches
-                                      (new String'(Sw.Unix_String.all &
-                                                   Arg.all));
-
-                              end case;
-                           end if;
-                        end;
-                     end if;
-
-                     Arg_Idx := Next_Arg_Idx + 1;
-                  end;
-
-                  exit when Arg_Idx > Argv'Last;
-
-               end loop;
-         end Process_Argument;
-
-         Arg_Num := Arg_Num + 1;
-      end loop;
-
-      if Display_Command then
-         Put (Standard_Error, "generated command -->");
-         Put (Standard_Error, Command_List (The_Command).Unixcmd.all);
-
-         if Command_List (The_Command).Unixsws /= null then
-            for J in Command_List (The_Command).Unixsws'Range loop
-               Put (Standard_Error, " ");
-               Put (Standard_Error,
-                    Command_List (The_Command).Unixsws (J).all);
-            end loop;
-         end if;
-
-         Put (Standard_Error, " ");
-         Put (Standard_Error, String (Buffer.Table (1 .. Buffer.Last)));
-         Put (Standard_Error, "<--");
-         New_Line (Standard_Error);
-         raise Normal_Exit;
-      end if;
-
-      --  Gross error checking that the number of parameters is correct.
-      --  Not applicable to Unlimited_Files parameters.
-
-      if (Param_Count = Command.Params'Length - 1
-            and then Command.Params (Param_Count + 1) = Unlimited_Files)
-        or else Param_Count <= Command.Params'Length
-      then
-         null;
-
-      else
-         Put_Line (Standard_Error,
-                   "Parameter count of "
-                   & Integer'Image (Param_Count)
-                   & " not equal to expected "
-                   & Integer'Image (Command.Params'Length));
-         Put (Standard_Error, "usage: ");
-         Put_Line (Standard_Error, Command.Usage.all);
-         Errors := Errors + 1;
-      end if;
-
-      if Errors > 0 then
-         raise Error_Exit;
-      else
-         --  Prepare arguments for a call to spawn, filtering out
-         --  embedded nulls place there to delineate strings.
-
-         declare
-            P1, P2     : Natural;
-            Inside_Nul : Boolean := False;
-            Arg        : String (1 .. 1024);
-            Arg_Ctr    : Natural;
-
-         begin
-            P1 := 1;
-
-            while P1 <= Buffer.Last and then Buffer.Table (P1) = ' ' loop
-               P1 := P1 + 1;
-            end loop;
-
-            Arg_Ctr := 1;
-            Arg (Arg_Ctr) := Buffer.Table (P1);
-
-            while P1 <= Buffer.Last loop
-
-               if Buffer.Table (P1) = ASCII.NUL then
-                  if Inside_Nul then
-                     Inside_Nul := False;
-                  else
-                     Inside_Nul := True;
-                  end if;
-               end if;
-
-               if Buffer.Table (P1) = ' ' and then not Inside_Nul then
-                  P1 := P1 + 1;
-                  Arg_Ctr := Arg_Ctr + 1;
-                  Arg (Arg_Ctr) := Buffer.Table (P1);
-
-               else
-                  Last_Switches.Increment_Last;
-                  P2 := P1;
-
-                  while P2 < Buffer.Last
-                    and then (Buffer.Table (P2 + 1) /= ' ' or else
-                              Inside_Nul)
-                  loop
-                     P2 := P2 + 1;
-                     Arg_Ctr := Arg_Ctr + 1;
-                     Arg (Arg_Ctr) := Buffer.Table (P2);
-                     if Buffer.Table (P2) = ASCII.NUL then
-                        Arg_Ctr := Arg_Ctr - 1;
-                        if Inside_Nul then
-                           Inside_Nul := False;
-                        else
-                           Inside_Nul := True;
-                        end if;
-                     end if;
-                  end loop;
-
-                  Last_Switches.Table (Last_Switches.Last) :=
-                    new String'(String (Arg (1 .. Arg_Ctr)));
-                  P1 := P2 + 2;
-                  Arg_Ctr := 1;
-                  Arg (Arg_Ctr) := Buffer.Table (P1);
-               end if;
-            end loop;
-         end;
-      end if;
-   end VMS_Conversion;
-
-   -------------------------------------
-   -- Start of processing for GNATCmd --
-   -------------------------------------
-
-begin
-   --  Initializations
-
-   Namet.Initialize;
-   Csets.Initialize;
-
-   Snames.Initialize;
-
-   Prj.Initialize;
-
-   Last_Switches.Init;
-   Last_Switches.Set_Last (0);
-
-   First_Switches.Init;
-   First_Switches.Set_Last (0);
+      end;
+   end if;
 
    --  If on VMS, or if VMS emulation is on, convert VMS style /qualifiers,
    --  filenames and pathnames to Unix style.
@@ -3842,6 +1446,8 @@ begin
    then
       VMS_Conversion (The_Command);
 
+      B_Start := new String'("b__");
+
    --  If not on VMS, scan the command line directly
 
    else
@@ -3850,22 +1456,39 @@ begin
          return;
       else
          begin
-            if Argument_Count > 1 and then Argument (1) = "-v" then
-               Opt.Verbose_Mode := True;
-               Command_Arg := 2;
-            end if;
+            loop
+               if Argument_Count > Command_Arg
+                 and then Argument (Command_Arg) = "-v"
+               then
+                  Verbose_Mode := True;
+                  Command_Arg := Command_Arg + 1;
+
+               elsif Argument_Count > Command_Arg
+                 and then Argument (Command_Arg) = "-dn"
+               then
+                  Keep_Temporary_Files := True;
+                  Command_Arg := Command_Arg + 1;
+
+               else
+                  exit;
+               end if;
+            end loop;
 
             The_Command := Real_Command_Type'Value (Argument (Command_Arg));
 
             if Command_List (The_Command).VMS_Only then
                Non_VMS_Usage;
-               Fail ("Command """ & Command_List (The_Command).Cname.all &
-                     """ can only be used on VMS");
+               Fail
+                 ("Command """,
+                  Command_List (The_Command).Cname.all,
+                  """ can only be used on VMS");
             end if;
+
          exception
             when Constraint_Error =>
 
                --  Check if it is an alternate command
+
                declare
                   Alternate : Alternate_Command;
 
@@ -3877,31 +1500,96 @@ begin
                exception
                   when Constraint_Error =>
                      Non_VMS_Usage;
-                     Fail ("Unknown command: " & Argument (Command_Arg));
+                     Fail ("Unknown command: ", Argument (Command_Arg));
                end;
          end;
 
+         --  Get the arguments from the command line and from the eventual
+         --  argument file(s) specified on the command line.
+
          for Arg in Command_Arg + 1 .. Argument_Count loop
-            Last_Switches.Increment_Last;
-            Last_Switches.Table (Last_Switches.Last) :=
-              new String'(Argument (Arg));
+            declare
+               The_Arg : constant String := Argument (Arg);
+
+            begin
+               --  Check if an argument file is specified
+
+               if The_Arg (The_Arg'First) = '@' then
+                  declare
+                     Arg_File : Ada.Text_IO.File_Type;
+                     Line     : String (1 .. 256);
+                     Last     : Natural;
+
+                  begin
+                     --  Open the file and fail if the file cannot be found
+
+                     begin
+                        Open
+                          (Arg_File, In_File,
+                           The_Arg (The_Arg'First + 1 .. The_Arg'Last));
+
+                     exception
+                        when others =>
+                           Put
+                             (Standard_Error, "Cannot open argument file """);
+                           Put
+                             (Standard_Error,
+                              The_Arg (The_Arg'First + 1 .. The_Arg'Last));
+
+                           Put_Line (Standard_Error, """");
+                           raise Error_Exit;
+                     end;
+
+                     --  Read line by line and put the content of each non-
+                     --  empty line in the Last_Switches table.
+
+                     while not End_Of_File (Arg_File) loop
+                        Get_Line (Arg_File, Line, Last);
+
+                        if Last /= 0 then
+                           Last_Switches.Increment_Last;
+                           Last_Switches.Table (Last_Switches.Last) :=
+                             new String'(Line (1 .. Last));
+                        end if;
+                     end loop;
+
+                     Close (Arg_File);
+                  end;
+
+               else
+                  --  It is not an argument file; just put the argument in
+                  --  the Last_Switches table.
+
+                  Last_Switches.Increment_Last;
+                  Last_Switches.Table (Last_Switches.Last) :=
+                    new String'(The_Arg);
+               end if;
+            end;
          end loop;
       end if;
    end if;
 
    declare
-      Program : constant String :=
-        Program_Name (Command_List (The_Command).Unixcmd.all).all;
-
+      Program   : String_Access;
       Exec_Path : String_Access;
 
    begin
+      if The_Command = Stack then
+         --  Never call gnatstack with a prefix
+
+         Program := new String'(Command_List (The_Command).Unixcmd.all);
+
+      else
+         Program :=
+           Program_Name (Command_List (The_Command).Unixcmd.all, "gnat");
+      end if;
+
       --  Locate the executable for the command
 
-      Exec_Path := Locate_Exec_On_Path (Program);
+      Exec_Path := Locate_Exec_On_Path (Program.all);
 
       if Exec_Path = null then
-         Put_Line (Standard_Error, "Couldn't locate " & Program);
+         Put_Line (Standard_Error, "could not locate " & Program.all);
          raise Error_Exit;
       end if;
 
@@ -3915,30 +1603,67 @@ begin
          end loop;
       end if;
 
-      --  For BIND, FIND, LINK, LIST and XREF, look for project file related
-      --  switches.
+      --  For BIND, CHECK, ELIM, FIND, LINK, LIST, PRETTY, STACK, STUB,
+      --  METRIC ad  XREF, look for project file related switches.
 
       if The_Command = Bind
+        or else The_Command = Check
+        or else The_Command = Sync
+        or else The_Command = Elim
         or else The_Command = Find
         or else The_Command = Link
         or else The_Command = List
         or else The_Command = Xref
+        or else The_Command = Pretty
+        or else The_Command = Stack
+        or else The_Command = Stub
+        or else The_Command = Metric
       then
          case The_Command is
             when Bind =>
                Tool_Package_Name := Name_Binder;
+               Packages_To_Check := Packages_To_Check_By_Binder;
+            when Check =>
+               Tool_Package_Name := Name_Check;
+               Packages_To_Check := Packages_To_Check_By_Check;
+            when Sync =>
+               Tool_Package_Name := Name_Synchronize;
+               Packages_To_Check := Packages_To_Check_By_Sync;
+            when Elim =>
+               Tool_Package_Name := Name_Eliminate;
+               Packages_To_Check := Packages_To_Check_By_Eliminate;
             when Find =>
                Tool_Package_Name := Name_Finder;
+               Packages_To_Check := Packages_To_Check_By_Finder;
             when Link =>
                Tool_Package_Name := Name_Linker;
+               Packages_To_Check := Packages_To_Check_By_Linker;
             when List =>
                Tool_Package_Name := Name_Gnatls;
+               Packages_To_Check := Packages_To_Check_By_Gnatls;
+            when Metric =>
+               Tool_Package_Name := Name_Metrics;
+               Packages_To_Check := Packages_To_Check_By_Metric;
+            when Pretty =>
+               Tool_Package_Name := Name_Pretty_Printer;
+               Packages_To_Check := Packages_To_Check_By_Pretty;
+            when Stack =>
+               Tool_Package_Name := Name_Stack;
+               Packages_To_Check := Packages_To_Check_By_Stack;
+            when Stub =>
+               Tool_Package_Name := Name_Gnatstub;
+               Packages_To_Check := Packages_To_Check_By_Gnatstub;
             when Xref =>
                Tool_Package_Name := Name_Cross_Reference;
+               Packages_To_Check := Packages_To_Check_By_Xref;
             when others =>
                null;
          end case;
 
+         --  Check that the switches are consistent. Detect project file
+         --  related switches.
+
+         Inspect_Switches :
          declare
             Arg_Num : Positive := 1;
             Argv    : String_Access;
@@ -3957,7 +1682,7 @@ begin
                Last_Switches.Decrement_Last;
             end Remove_Switch;
 
-         --  Start of processing for ??? (need block name here)
+         --  Start of processing for Inspect_Switches
 
          begin
             while Arg_Num <= Last_Switches.Last loop
@@ -3965,7 +1690,8 @@ begin
 
                if Argv (Argv'First) = '-' then
                   if Argv'Length = 1 then
-                     Fail ("switch character cannot be followed by a blank");
+                     Fail
+                       ("switch character cannot be followed by a blank");
                   end if;
 
                   --  The two style project files (-p and -P) cannot be used
@@ -3980,9 +1706,40 @@ begin
                      end if;
                   end if;
 
+                  --  --subdirs=... Specify Subdirs
+
+                  if Argv'Length > Subdirs_Option'Length and then
+                    Argv
+                      (Argv'First .. Argv'First + Subdirs_Option'Length - 1) =
+                      Subdirs_Option
+                  then
+                     Subdirs :=
+                       new String'
+                         (Argv
+                            (Argv'First + Subdirs_Option'Length .. Argv'Last));
+
+                     Remove_Switch (Arg_Num);
+
+                  --  -aPdir  Add dir to the project search path
+
+                  elsif Argv'Length > 3
+                    and then Argv (Argv'First + 1 .. Argv'First + 2) = "aP"
+                  then
+                     Add_Search_Project_Directory
+                       (Argv (Argv'First + 3 .. Argv'Last));
+
+                     Remove_Switch (Arg_Num);
+
+                  --  -eL  Follow links for files
+
+                  elsif Argv.all = "-eL" then
+                     Follow_Links_For_Files := True;
+
+                     Remove_Switch (Arg_Num);
+
                   --  -vPx  Specify verbosity while parsing project files
 
-                  if Argv'Length = 4
+                  elsif Argv'Length = 4
                     and then Argv (Argv'First + 1 .. Argv'First + 2) = "vP"
                   then
                      case Argv (Argv'Last) is
@@ -3993,23 +1750,22 @@ begin
                         when '2' =>
                            Current_Verbosity := Prj.High;
                         when others =>
-                           Fail ("Invalid switch: " & Argv.all);
+                           Fail ("Invalid switch: ", Argv.all);
                      end case;
 
                      Remove_Switch (Arg_Num);
 
                   --  -Pproject_file  Specify project file to be used
 
-                  elsif Argv'Length >= 3
-                    and then Argv (Argv'First + 1) = 'P'
-                  then
+                  elsif Argv (Argv'First + 1) = 'P' then
 
                      --  Only one -P switch can be used
 
                      if Project_File /= null then
-                        Fail (Argv.all &
-                              ": second project file forbidden (first is """ &
-                              Project_File.all & """)");
+                        Fail
+                          (Argv.all,
+                           ": second project file forbidden (first is """,
+                           Project_File.all & """)");
 
                      --  The two style project files (-p and -P) cannot be
                      --  used together.
@@ -4017,7 +1773,32 @@ begin
                      elsif Old_Project_File_Used then
                         Fail ("-p and -P cannot be used together");
 
+                     elsif Argv'Length = 2 then
+
+                        --  There is space between -P and the project file
+                        --  name. -P cannot be the last option.
+
+                        if Arg_Num = Last_Switches.Last then
+                           Fail ("project file name missing after -P");
+
+                        else
+                           Remove_Switch (Arg_Num);
+                           Argv := Last_Switches.Table (Arg_Num);
+
+                           --  After -P, there must be a project file name,
+                           --  not another switch.
+
+                           if Argv (Argv'First) = '-' then
+                              Fail ("project file name missing after -P");
+
+                           else
+                              Project_File := new String'(Argv.all);
+                           end if;
+                        end if;
+
                      else
+                        --  No space between -P and project file name
+
                         Project_File :=
                           new String'(Argv (Argv'First + 2 .. Argv'Last));
                      end if;
@@ -4032,7 +1813,9 @@ begin
                   then
                      declare
                         Equal_Pos : constant Natural :=
-                          Index ('=', Argv (Argv'First + 2 .. Argv'Last));
+                                      Index
+                                        ('=',
+                                         Argv (Argv'First + 2 .. Argv'Last));
                      begin
                         if Equal_Pos >= Argv'First + 3 and then
                           Equal_Pos /= Argv'Last then
@@ -4040,22 +1823,50 @@ begin
                                   Argv (Argv'First + 2 .. Equal_Pos - 1),
                                 Value => Argv (Equal_Pos + 1 .. Argv'Last));
                         else
-                           Fail (Argv.all &
-                                 " is not a valid external assignment.");
+                           Fail
+                             (Argv.all,
+                              " is not a valid external assignment.");
                         end if;
                      end;
 
                      Remove_Switch (Arg_Num);
 
+                  elsif
+                    (The_Command = Check  or else
+                     The_Command = Sync   or else
+                     The_Command = Pretty or else
+                     The_Command = Metric or else
+                     The_Command = Stack  or else
+                     The_Command = List)
+                    and then Argv'Length = 2
+                    and then Argv (2) = 'U'
+                  then
+                     All_Projects := True;
+                     Remove_Switch (Arg_Num);
+
                   else
                      Arg_Num := Arg_Num + 1;
                   end if;
 
+               elsif ((The_Command = Check and then Argv (Argv'First) /= '+')
+                        or else The_Command = Sync
+                        or else The_Command = Metric
+                        or else The_Command = Pretty)
+                 and then Project_File /= null
+                 and then All_Projects
+               then
+                  if ASIS_Main /= null then
+                     Fail ("cannot specify more than one main after -U");
+                  else
+                     ASIS_Main := Argv;
+                     Remove_Switch (Arg_Num);
+                  end if;
+
                else
                   Arg_Num := Arg_Num + 1;
                end if;
             end loop;
-         end;
+         end Inspect_Switches;
       end if;
 
       --  If there is a project file specified, parse it, get the switches
@@ -4066,21 +1877,26 @@ begin
 
          Prj.Pars.Parse
            (Project           => Project,
-            Project_File_Name => Project_File.all);
+            In_Tree           => Project_Tree,
+            Project_File_Name => Project_File.all,
+            Packages_To_Check => Packages_To_Check);
 
          if Project = Prj.No_Project then
-            Fail ("""" & Project_File.all & """ processing failed");
+            Fail ("""", Project_File.all, """ processing failed");
          end if;
 
          --  Check if a package with the name of the tool is in the project
          --  file and if there is one, get the switches, if any, and scan them.
 
          declare
-            Data : Prj.Project_Data := Prj.Projects.Table (Project);
-            Pkg  : Prj.Package_Id :=
-                     Prj.Util.Value_Of
-                       (Name        => Tool_Package_Name,
-                        In_Packages => Data.Decl.Packages);
+            Data : constant Prj.Project_Data :=
+                     Project_Tree.Projects.Table (Project);
+
+            Pkg : constant Prj.Package_Id :=
+                    Prj.Util.Value_Of
+                      (Name        => Tool_Package_Name,
+                       In_Packages => Data.Decl.Packages,
+                       In_Tree     => Project_Tree);
 
             Element : Package_Element;
 
@@ -4092,31 +1908,41 @@ begin
 
          begin
             if Pkg /= No_Package then
-               Element := Packages.Table (Pkg);
+               Element := Project_Tree.Packages.Table (Pkg);
 
-               --  Packages Gnatls has a single attribute Switches, that is
-               --  not an associative array.
+               --  Packages Gnatls and Gnatstack have a single attribute
+               --  Switches, that is not an associative array.
 
-               if The_Command = List then
+               if The_Command = List or else The_Command = Stack then
                   The_Switches :=
                     Prj.Util.Value_Of
                     (Variable_Name => Snames.Name_Switches,
-                     In_Variables => Element.Decl.Attributes);
+                     In_Variables  => Element.Decl.Attributes,
+                     In_Tree       => Project_Tree);
 
                --  Packages Binder (for gnatbind), Cross_Reference (for
-               --  gnatxref), Linker (for gnatlink) and Finder
-               --  (for gnatfind) have an attributed Default_Switches,
-               --  an associative array, indexed by the name of the
-               --  programming language.
-               else
-                  Default_Switches_Array :=
-                    Prj.Util.Value_Of
-                    (Name => Name_Default_Switches,
-                     In_Arrays => Packages.Table (Pkg).Decl.Arrays);
-                  The_Switches := Prj.Util.Value_Of
-                    (Index => Name_Ada,
-                     In_Array => Default_Switches_Array);
+               --  gnatxref), Linker (for gnatlink), Finder (for gnatfind),
+               --  Pretty_Printer (for gnatpp), Eliminate (for gnatelim), Check
+               --  (for gnatcheck), and Metric (for gnatmetric) have an
+               --  attributed Switches, an associative array, indexed by the
+               --  name of the file.
+
+               --  They also have an attribute Default_Switches, indexed by the
+               --  name of the programming language.
 
+               else
+                  if The_Switches.Kind = Prj.Undefined then
+                     Default_Switches_Array :=
+                       Prj.Util.Value_Of
+                         (Name      => Name_Default_Switches,
+                          In_Arrays => Element.Decl.Arrays,
+                          In_Tree   => Project_Tree);
+                     The_Switches := Prj.Util.Value_Of
+                       (Index     => Name_Ada,
+                        Src_Index => 0,
+                        In_Array  => Default_Switches_Array,
+                        In_Tree   => Project_Tree);
+                  end if;
                end if;
 
                --  If there are switches specified in the package of the
@@ -4127,24 +1953,35 @@ begin
                      null;
 
                   when Prj.Single =>
-                     if String_Length (The_Switches.Value) > 0 then
-                        String_To_Name_Buffer (The_Switches.Value);
-                        First_Switches.Increment_Last;
-                        First_Switches.Table (First_Switches.Last) :=
-                          new String'(Name_Buffer (1 .. Name_Len));
-                     end if;
+                     declare
+                        Switch : constant String :=
+                                   Get_Name_String (The_Switches.Value);
+
+                     begin
+                        if Switch'Length > 0 then
+                           First_Switches.Increment_Last;
+                           First_Switches.Table (First_Switches.Last) :=
+                             new String'(Switch);
+                        end if;
+                     end;
 
                   when Prj.List =>
                      Current := The_Switches.Values;
                      while Current /= Prj.Nil_String loop
-                        The_String := String_Elements.Table (Current);
+                        The_String := Project_Tree.String_Elements.
+                                        Table (Current);
 
-                        if String_Length (The_String.Value) > 0 then
-                           String_To_Name_Buffer (The_String.Value);
-                           First_Switches.Increment_Last;
-                           First_Switches.Table (First_Switches.Last) :=
-                             new String'(Name_Buffer (1 .. Name_Len));
-                        end if;
+                        declare
+                           Switch : constant String :=
+                             Get_Name_String (The_String.Value);
+
+                        begin
+                           if Switch'Length > 0 then
+                              First_Switches.Increment_Last;
+                              First_Switches.Table (First_Switches.Last) :=
+                                new String'(Switch);
+                           end if;
+                        end;
 
                         Current := The_String.Next;
                      end loop;
@@ -4152,79 +1989,433 @@ begin
             end if;
          end;
 
-         --  Set up the environment variables ADA_INCLUDE_PATH and
-         --  ADA_OBJECTS_PATH.
-
-         Setenv
-           (Name  => Ada_Include_Path,
-            Value => Prj.Env.Ada_Include_Path (Project).all);
-         Setenv
-           (Name  => Ada_Objects_Path,
-            Value => Prj.Env.Ada_Objects_Path
-            (Project, Including_Libraries => False).all);
-
-         if The_Command = Bind or else The_Command = Link then
+         if The_Command = Bind
+           or else The_Command = Link
+           or else The_Command = Elim
+         then
             Change_Dir
               (Get_Name_String
-                 (Projects.Table (Project).Object_Directory));
+                 (Project_Tree.Projects.Table
+                    (Project).Object_Directory.Name));
          end if;
 
-         if The_Command = Link then
+         --  Set up the env vars for project path files
+
+         Prj.Env.Set_Ada_Paths
+           (Project, Project_Tree, Including_Libraries => False);
 
-            --  Add the default search directories, to be able to find
-            --  libgnat in call to MLib.Utl.Lib_Directory.
+         --  For gnatcheck, gnatstub, gnatmetric, gnatpp and gnatelim, create
+         --  a configuration pragmas file, if necessary.
 
-            Add_Default_Search_Dirs;
+         if The_Command = Pretty
+           or else The_Command = Metric
+           or else The_Command = Stub
+           or else The_Command = Elim
+           or else The_Command = Check
+           or else The_Command = Sync
+         then
+            --  If there are switches in package Compiler, put them in the
+            --  Carg_Switches table.
 
             declare
-               There_Are_Libraries  : Boolean := False;
+               Data : constant Prj.Project_Data :=
+                        Project_Tree.Projects.Table (Project);
+
+               Pkg  : constant Prj.Package_Id :=
+                        Prj.Util.Value_Of
+                          (Name        => Name_Compiler,
+                           In_Packages => Data.Decl.Packages,
+                           In_Tree     => Project_Tree);
+
+               Element : Package_Element;
+
+               Default_Switches_Array : Array_Element_Id;
+
+               The_Switches : Prj.Variable_Value;
+               Current      : Prj.String_List_Id;
+               The_String   : String_Element;
 
             begin
-               --  Check if there are library project files
+               if Pkg /= No_Package then
+                  Element := Project_Tree.Packages.Table (Pkg);
+
+                  Default_Switches_Array :=
+                    Prj.Util.Value_Of
+                      (Name      => Name_Default_Switches,
+                       In_Arrays => Element.Decl.Arrays,
+                       In_Tree   => Project_Tree);
+                  The_Switches := Prj.Util.Value_Of
+                    (Index     => Name_Ada,
+                     Src_Index => 0,
+                     In_Array  => Default_Switches_Array,
+                     In_Tree   => Project_Tree);
 
-               if MLib.Tgt.Libraries_Are_Supported then
-                  Set_Libraries (Project, There_Are_Libraries);
+                  --  If there are switches specified in the package of the
+                  --  project file corresponding to the tool, scan them.
+
+                  case The_Switches.Kind is
+                     when Prj.Undefined =>
+                        null;
+
+                     when Prj.Single =>
+                        declare
+                           Switch : constant String :=
+                                      Get_Name_String (The_Switches.Value);
+                        begin
+                           if Switch'Length > 0 then
+                              Add_To_Carg_Switches (new String'(Switch));
+                           end if;
+                        end;
+
+                     when Prj.List =>
+                        Current := The_Switches.Values;
+                        while Current /= Prj.Nil_String loop
+                           The_String :=
+                             Project_Tree.String_Elements.Table (Current);
+
+                           declare
+                              Switch : constant String :=
+                                         Get_Name_String (The_String.Value);
+                           begin
+                              if Switch'Length > 0 then
+                                 Add_To_Carg_Switches (new String'(Switch));
+                              end if;
+                           end;
+
+                           Current := The_String.Next;
+                        end loop;
+                  end case;
                end if;
+            end;
+
+            --  If -cargs is one of the switches, move the following switches
+            --  to the Carg_Switches table.
 
-               --  If there are, add the necessary additional switches
+            for J in 1 .. First_Switches.Last loop
+               if First_Switches.Table (J).all = "-cargs" then
+                  declare
+                     K    : Positive;
+                     Last : Natural;
 
-               if There_Are_Libraries then
+                  begin
+                     --  Move the switches that are before -rules when the
+                     --  command is CHECK.
+
+                     K := J + 1;
+                     while K <= First_Switches.Last
+                       and then
+                        (The_Command /= Check
+                           or else First_Switches.Table (K).all /= "-rules")
+                     loop
+                        Add_To_Carg_Switches (First_Switches.Table (K));
+                        K := K + 1;
+                     end loop;
 
-                  --  Add -L<lib_dir> -lgnarl -lgnat -Wl,-rpath,<lib_dir>
+                     if K > First_Switches.Last then
+                        First_Switches.Set_Last (J - 1);
 
-                  Last_Switches.Increment_Last;
-                  Last_Switches.Table (Last_Switches.Last) :=
-                    new String'("-L" & MLib.Utl.Lib_Directory);
-                  Last_Switches.Increment_Last;
-                  Last_Switches.Table (Last_Switches.Last) :=
-                    new String'("-lgnarl");
-                  Last_Switches.Increment_Last;
-                  Last_Switches.Table (Last_Switches.Last) :=
-                    new String'("-lgnat");
+                     else
+                        Last := J - 1;
+                        while K <= First_Switches.Last loop
+                           Last := Last + 1;
+                           First_Switches.Table (Last) :=
+                             First_Switches.Table (K);
+                           K := K + 1;
+                        end loop;
+
+                        First_Switches.Set_Last (Last);
+                     end if;
+                  end;
 
+                  exit;
+               end if;
+            end loop;
+
+            for J in 1 .. Last_Switches.Last loop
+               if Last_Switches.Table (J).all = "-cargs" then
                   declare
-                     Option : constant String_Access :=
-                       MLib.Tgt.Linker_Library_Path_Option
-                       (MLib.Utl.Lib_Directory);
+                     K    : Positive;
+                     Last : Natural;
 
                   begin
-                     if Option /= null then
-                        Last_Switches.Increment_Last;
-                        Last_Switches.Table (Last_Switches.Last) :=
-                          Option;
+                     --  Move the switches that are before -rules when the
+                     --  command is CHECK.
+
+                     K := J + 1;
+                     while K <= Last_Switches.Last
+                       and then
+                        (The_Command /= Check
+                         or else
+                         Last_Switches.Table (K).all /= "-rules")
+                     loop
+                        Add_To_Carg_Switches (Last_Switches.Table (K));
+                        K := K + 1;
+                     end loop;
+
+                     if K > Last_Switches.Last then
+                        Last_Switches.Set_Last (J - 1);
+
+                     else
+                        Last := J - 1;
+                        while K <= Last_Switches.Last loop
+                           Last := Last + 1;
+                           Last_Switches.Table (Last) :=
+                             Last_Switches.Table (K);
+                           K := K + 1;
+                        end loop;
+
+                        Last_Switches.Set_Last (Last);
                      end if;
                   end;
+
+                  exit;
+               end if;
+            end loop;
+
+            declare
+               CP_File : constant Path_Name_Type := Configuration_Pragmas_File;
+
+            begin
+               if CP_File /= No_Path then
+                  if The_Command = Elim then
+                     First_Switches.Increment_Last;
+                     First_Switches.Table (First_Switches.Last)  :=
+                       new String'("-C" & Get_Name_String (CP_File));
+
+                  else
+                     Add_To_Carg_Switches
+                       (new String'("-gnatec=" & Get_Name_String (CP_File)));
+                  end if;
+               end if;
+            end;
+         end if;
+
+         if The_Command = Link then
+            Process_Link;
+         end if;
+
+         if The_Command = Link or The_Command = Bind then
+
+            --  For files that are specified as relative paths with directory
+            --  information, we convert them to absolute paths, with parent
+            --  being the current working directory if specified on the command
+            --  line and the project directory if specified in the project
+            --  file. This is what gnatmake is doing for linker and binder
+            --  arguments.
+
+            for J in 1 .. Last_Switches.Last loop
+               Test_If_Relative_Path
+                 (Last_Switches.Table (J), Current_Work_Dir);
+            end loop;
+
+            Get_Name_String
+              (Project_Tree.Projects.Table (Project).Directory.Name);
+
+            declare
+               Project_Dir : constant String := Name_Buffer (1 .. Name_Len);
+            begin
+               for J in 1 .. First_Switches.Last loop
+                  Test_If_Relative_Path
+                    (First_Switches.Table (J), Project_Dir);
+               end loop;
+            end;
+
+         elsif The_Command = Stub then
+            declare
+               Data       : constant Prj.Project_Data :=
+                              Project_Tree.Projects.Table (Project);
+               File_Index : Integer := 0;
+               Dir_Index  : Integer := 0;
+               Last       : constant Integer := Last_Switches.Last;
+
+            begin
+               for Index in 1 .. Last loop
+                  if Last_Switches.Table (Index)
+                    (Last_Switches.Table (Index)'First) /= '-'
+                  then
+                     File_Index := Index;
+                     exit;
+                  end if;
+               end loop;
+
+               --  If the naming scheme of the project file is not standard,
+               --  and if the file name ends with the spec suffix, then
+               --  indicate to gnatstub the name of the body file with
+               --  a -o switch.
+
+               if Body_Suffix_Id_Of (Project_Tree, "ada", Data.Naming) /=
+                    Prj.Default_Ada_Spec_Suffix
+               then
+                  if File_Index /= 0 then
+                     declare
+                        Spec : constant String :=
+                          Base_Name (Last_Switches.Table (File_Index).all);
+                        Last : Natural := Spec'Last;
+
+                     begin
+                        Get_Name_String
+                          (Spec_Suffix_Id_Of
+                             (Project_Tree, "ada", Data.Naming));
+
+                        if Spec'Length > Name_Len
+                          and then Spec (Last - Name_Len + 1 .. Last) =
+                                                  Name_Buffer (1 .. Name_Len)
+                        then
+                           Last := Last - Name_Len;
+                           Get_Name_String
+                             (Body_Suffix_Id_Of
+                                (Project_Tree, "ada", Data.Naming));
+                           Last_Switches.Increment_Last;
+                           Last_Switches.Table (Last_Switches.Last) :=
+                             new String'("-o");
+                           Last_Switches.Increment_Last;
+                           Last_Switches.Table (Last_Switches.Last) :=
+                             new String'(Spec (Spec'First .. Last) &
+                                           Name_Buffer (1 .. Name_Len));
+                        end if;
+                     end;
+                  end if;
+               end if;
+
+               --  Add the directory of the spec as the destination directory
+               --  of the body, if there is no destination directory already
+               --  specified.
+
+               if File_Index /= 0 then
+                  for Index in File_Index + 1 .. Last loop
+                     if Last_Switches.Table (Index)
+                         (Last_Switches.Table (Index)'First) /= '-'
+                     then
+                        Dir_Index := Index;
+                        exit;
+                     end if;
+                  end loop;
+
+                  if Dir_Index = 0 then
+                     Last_Switches.Increment_Last;
+                     Last_Switches.Table (Last_Switches.Last) :=
+                       new String'
+                             (Dir_Name (Last_Switches.Table (File_Index).all));
+                  end if;
+               end if;
+            end;
+         end if;
+
+         --  For gnatmetric, the generated files should be put in the object
+         --  directory. This must be the first switch, because it may be
+         --  overridden by a switch in package Metrics in the project file or
+         --  by a command line option. Note that we don't add the -d= switch
+         --  if there is no object directory available.
+
+         if The_Command = Metric
+           and then
+             Project_Tree.Projects.Table (Project).Object_Directory /=
+               No_Path_Information
+         then
+            First_Switches.Increment_Last;
+            First_Switches.Table (2 .. First_Switches.Last) :=
+              First_Switches.Table (1 .. First_Switches.Last - 1);
+            First_Switches.Table (1) :=
+              new String'("-d=" &
+                          Get_Name_String
+                            (Project_Tree.Projects.Table
+                               (Project).Object_Directory.Name));
+         end if;
+
+         --  For gnat check, -rules and the following switches need to be the
+         --  last options. So, we move all these switches to table
+         --  Rules_Switches.
+
+         if The_Command = Check then
+            declare
+               New_Last : Natural;
+               --  Set to rank of options preceding "-rules"
+
+               In_Rules_Switches : Boolean;
+               --  Set to True when options "-rules" is found
+
+            begin
+               New_Last := First_Switches.Last;
+               In_Rules_Switches := False;
+
+               for J in 1 .. First_Switches.Last loop
+                  if In_Rules_Switches then
+                     Add_To_Rules_Switches (First_Switches.Table (J));
+
+                  elsif First_Switches.Table (J).all = "-rules" then
+                     New_Last := J - 1;
+                     In_Rules_Switches := True;
+                  end if;
+               end loop;
+
+               if In_Rules_Switches then
+                  First_Switches.Set_Last (New_Last);
+               end if;
+
+               New_Last := Last_Switches.Last;
+               In_Rules_Switches := False;
+
+               for J in 1 .. Last_Switches.Last loop
+                  if In_Rules_Switches then
+                     Add_To_Rules_Switches (Last_Switches.Table (J));
+
+                  elsif Last_Switches.Table (J).all = "-rules" then
+                     New_Last := J - 1;
+                     In_Rules_Switches := True;
+                  end if;
+               end loop;
+
+               if In_Rules_Switches then
+                  Last_Switches.Set_Last (New_Last);
                end if;
             end;
          end if;
+
+         --  For gnat check, sync, metric or pretty with -U + a main, get the
+         --  list of sources from the closure and add them to the arguments.
+
+         if ASIS_Main /= null then
+            Get_Closure;
+
+            --  On VMS, set up the env var again for source dirs file. This is
+            --  because the call to gnatmake has set this env var to another
+            --  file that has now been deleted.
+
+            if Hostparm.OpenVMS then
+
+               --  First make sure that the recorded file names are empty
+
+               Prj.Env.Initialize;
+
+               Prj.Env.Set_Ada_Paths
+                 (Project, Project_Tree, Including_Libraries => False);
+            end if;
+
+         --  For gnat check, gnat sync, gnat pretty, gnat metric, gnat list,
+         --  and gnat stack, if no file has been put on the command line, call
+         --  tool with all the sources of the main project.
+
+         elsif The_Command = Check  or else
+               The_Command = Sync   or else
+               The_Command = Pretty or else
+               The_Command = Metric or else
+               The_Command = List   or else
+               The_Command = Stack
+         then
+            Check_Files;
+         end if;
       end if;
 
       --  Gather all the arguments and invoke the executable
 
       declare
          The_Args : Argument_List
-           (1 .. First_Switches.Last + Last_Switches.Last);
-         Arg_Num : Natural := 0;
+                      (1 .. First_Switches.Last +
+                            Last_Switches.Last +
+                            Carg_Switches.Last +
+                            Rules_Switches.Last);
+         Arg_Num  : Natural := 0;
+
       begin
          for J in 1 .. First_Switches.Last loop
             Arg_Num := Arg_Num + 1;
@@ -4236,7 +2427,33 @@ begin
             The_Args (Arg_Num) := Last_Switches.Table (J);
          end loop;
 
-         if Opt.Verbose_Mode then
+         for J in 1 .. Carg_Switches.Last loop
+            Arg_Num := Arg_Num + 1;
+            The_Args (Arg_Num) := Carg_Switches.Table (J);
+         end loop;
+
+         for J in 1 .. Rules_Switches.Last loop
+            Arg_Num := Arg_Num + 1;
+            The_Args (Arg_Num) := Rules_Switches.Table (J);
+         end loop;
+
+         --  If Display_Command is on, only display the generated command
+
+         if Display_Command then
+            Put (Standard_Error, "generated command -->");
+            Put (Standard_Error, Exec_Path.all);
+
+            for Arg in The_Args'Range loop
+               Put (Standard_Error, " ");
+               Put (Standard_Error, The_Args (Arg).all);
+            end loop;
+
+            Put (Standard_Error, "<--");
+            New_Line (Standard_Error);
+            raise Normal_Exit;
+         end if;
+
+         if Verbose_Mode then
             Output.Write_Str (Exec_Path.all);
 
             for Arg in The_Args'Range loop
@@ -4247,17 +2464,35 @@ begin
             Output.Write_Eol;
          end if;
 
-         My_Exit_Status
-           := Exit_Status (Spawn (Exec_Path.all, The_Args));
+         My_Exit_Status :=
+           Exit_Status (Spawn (Exec_Path.all, The_Args));
          raise Normal_Exit;
       end;
    end;
 
 exception
    when Error_Exit =>
+      if not Keep_Temporary_Files then
+         Prj.Env.Delete_All_Path_Files (Project_Tree);
+         Delete_Temp_Config_Files;
+      end if;
+
       Set_Exit_Status (Failure);
 
    when Normal_Exit =>
-      Set_Exit_Status (My_Exit_Status);
+      if not Keep_Temporary_Files then
+         Prj.Env.Delete_All_Path_Files (Project_Tree);
+         Delete_Temp_Config_Files;
+      end if;
+
+      --  Since GNATCmd is normally called from DCL (the VMS shell), it must
+      --  return an understandable VMS exit status. However the exit status
+      --  returned *to* GNATCmd is a Posix style code, so we test it and return
+      --  just a simple success or failure on VMS.
 
+      if Hostparm.OpenVMS and then My_Exit_Status /= Success then
+         Set_Exit_Status (Failure);
+      else
+         Set_Exit_Status (My_Exit_Status);
+      end if;
 end GNATCmd;