OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [ada/] [clean.adb] - Rev 297

Go to most recent revision | Compare with Previous | Blame | View Log

------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                                C L E A N                                 --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--          Copyright (C) 2003-2009, 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 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 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 ALI;      use ALI;
with Csets;
with Makeutl;  use Makeutl;
with MLib.Tgt; use MLib.Tgt;
with Namet;    use Namet;
with Opt;      use Opt;
with Osint;    use Osint;
with Osint.M;  use Osint.M;
with Prj;      use Prj;
with Prj.Env;
with Prj.Ext;
with Prj.Pars;
with Prj.Tree; use Prj.Tree;
with Prj.Util; use Prj.Util;
with Snames;
with Switch;   use Switch;
with Table;
with Targparm; use Targparm;
with Types;    use Types;
 
with Ada.Command_Line;          use Ada.Command_Line;
 
with GNAT.Directory_Operations; use GNAT.Directory_Operations;
with GNAT.IO;                   use GNAT.IO;
with GNAT.OS_Lib;               use GNAT.OS_Lib;
 
package body Clean is
 
   Initialized : Boolean := False;
   --  Set to True by the first call to Initialize.
   --  To avoid reinitialization of some packages.
 
   --  Suffixes of various files
 
   Assembly_Suffix : constant String := ".s";
   ALI_Suffix      : constant String := ".ali";
   Tree_Suffix     : constant String := ".adt";
   Object_Suffix   : constant String := Get_Target_Object_Suffix.all;
   Debug_Suffix    : String          := ".dg";
   --  Changed to "_dg" for VMS in the body of the package
 
   Repinfo_Suffix  : String := ".rep";
   --  Changed to "_rep" for VMS in the body of the package
 
   B_Start : String_Ptr := new String'("b~");
   --  Prefix of binder generated file, and number of actual characters used.
   --  Changed to "b__" for VMS in the body of the package.
 
   Object_Directory_Path : String_Access := null;
   --  The path name of the object directory, set with switch -D
 
   Force_Deletions : Boolean := False;
   --  Set to True by switch -f. When True, attempts to delete non writable
   --  files will be done.
 
   Do_Nothing : Boolean := False;
   --  Set to True when switch -n is specified. When True, no file is deleted.
   --  gnatclean only lists the files that would have been deleted if the
   --  switch -n had not been specified.
 
   File_Deleted : Boolean := False;
   --  Set to True if at least one file has been deleted
 
   Copyright_Displayed : Boolean := False;
   Usage_Displayed     : Boolean := False;
 
   Project_File_Name : String_Access := null;
 
   Project_Node_Tree : Project_Node_Tree_Ref;
 
   Main_Project : Prj.Project_Id := Prj.No_Project;
 
   All_Projects : Boolean := False;
 
   --  Packages of project files where unknown attributes are errors
 
   Naming_String   : aliased String := "naming";
   Builder_String  : aliased String := "builder";
   Compiler_String : aliased String := "compiler";
   Binder_String   : aliased String := "binder";
   Linker_String   : aliased String := "linker";
 
   Gnatmake_Packages : aliased String_List :=
     (Naming_String   'Access,
      Builder_String  'Access,
      Compiler_String 'Access,
      Binder_String   'Access,
      Linker_String   'Access);
 
   Packages_To_Check_By_Gnatmake : constant String_List_Access :=
     Gnatmake_Packages'Access;
 
   package Processed_Projects is new Table.Table
     (Table_Component_Type => Project_Id,
      Table_Index_Type     => Natural,
      Table_Low_Bound      => 0,
      Table_Initial        => 10,
      Table_Increment      => 100,
      Table_Name           => "Clean.Processed_Projects");
   --  Table to keep track of what project files have been processed, when
   --  switch -r is specified.
 
   package Sources is new Table.Table
     (Table_Component_Type => File_Name_Type,
      Table_Index_Type     => Natural,
      Table_Low_Bound      => 0,
      Table_Initial        => 10,
      Table_Increment      => 100,
      Table_Name           => "Clean.Processed_Projects");
   --  Table to store all the source files of a library unit: spec, body and
   --  subunits, to detect .dg files and delete them.
 
   ----------------------------
   -- Queue (Q) manipulation --
   ----------------------------
 
   procedure Init_Q;
   --  Must be called to initialize the Q
 
   procedure Insert_Q (Lib_File  : File_Name_Type);
   --  If Lib_File is not marked, inserts it at the end of Q and mark it
 
   function Empty_Q return Boolean;
   --  Returns True if Q is empty
 
   procedure Extract_From_Q (Lib_File : out File_Name_Type);
   --  Extracts the first element from the Q
 
   Q_Front : Natural;
   --  Points to the first valid element in the Q
 
   package Q is new Table.Table (
     Table_Component_Type => File_Name_Type,
     Table_Index_Type     => Natural,
     Table_Low_Bound      => 0,
     Table_Initial        => 4000,
     Table_Increment      => 100,
     Table_Name           => "Clean.Q");
   --  This is the actual queue
 
   -----------------------------
   -- Other local subprograms --
   -----------------------------
 
   procedure Add_Source_Dir (N : String);
   --  Call Add_Src_Search_Dir and output one line when in verbose mode
 
   procedure Add_Source_Directories is
     new Prj.Env.For_All_Source_Dirs (Action => Add_Source_Dir);
 
   procedure Add_Object_Dir (N : String);
   --  Call Add_Lib_Search_Dir and output one line when in verbose mode
 
   procedure Add_Object_Directories is
     new Prj.Env.For_All_Object_Dirs (Action => Add_Object_Dir);
 
   function ALI_File_Name (Source : File_Name_Type) return String;
   --  Returns the name of the ALI file corresponding to Source
 
   function Assembly_File_Name (Source : File_Name_Type) return String;
   --  Returns the assembly file name corresponding to Source
 
   procedure Clean_Archive (Project : Project_Id; Global : Boolean);
   --  Delete a global archive or library project archive and the dependency
   --  file, if they exist.
 
   procedure Clean_Executables;
   --  Do the cleaning work when no project file is specified
 
   procedure Clean_Interface_Copy_Directory (Project : Project_Id);
   --  Delete files in an interface copy directory: any file that is a copy of
   --  a source of the project.
 
   procedure Clean_Library_Directory (Project : Project_Id);
   --  Delete the library file in a library directory and any ALI file of a
   --  source of the project in a library ALI directory.
 
   procedure Clean_Project (Project : Project_Id);
   --  Do the cleaning work when a project file is specified. This procedure
   --  calls itself recursively when there are several project files in the
   --  tree rooted at the main project file and switch -r has been specified.
 
   function Debug_File_Name (Source : File_Name_Type) return String;
   --  Name of the expanded source file corresponding to Source
 
   procedure Delete (In_Directory : String; File : String);
   --  Delete one file, or list the file name if switch -n is specified
 
   procedure Delete_Binder_Generated_Files
     (Dir    : String;
      Source : File_Name_Type);
   --  Delete the binder generated file in directory Dir for Source, if they
   --  exist: for Unix these are b~<source>.ads, b~<source>.adb,
   --  b~<source>.ali and b~<source>.o.
 
   procedure Display_Copyright;
   --  Display the Copyright notice. If called several times, display the
   --  Copyright notice only the first time.
 
   procedure Initialize;
   --  Call the necessary package initializations
 
   function Object_File_Name (Source : File_Name_Type) return String;
   --  Returns the object file name corresponding to Source
 
   procedure Parse_Cmd_Line;
   --  Parse the command line
 
   function Repinfo_File_Name (Source : File_Name_Type) return String;
   --  Returns the repinfo file name corresponding to Source
 
   function Tree_File_Name (Source : File_Name_Type) return String;
   --  Returns the tree file name corresponding to Source
 
   function In_Extension_Chain
     (Of_Project : Project_Id;
      Prj        : Project_Id) return Boolean;
   --  Returns True iff Prj is an extension of Of_Project or if Of_Project is
   --  an extension of Prj.
 
   procedure Usage;
   --  Display the usage. If called several times, the usage is displayed only
   --  the first time.
 
   --------------------
   -- Add_Object_Dir --
   --------------------
 
   procedure Add_Object_Dir (N : String) is
   begin
      Add_Lib_Search_Dir (N);
 
      if Opt.Verbose_Mode then
         Put ("Adding object directory """);
         Put (N);
         Put (""".");
         New_Line;
      end if;
   end Add_Object_Dir;
 
   --------------------
   -- Add_Source_Dir --
   --------------------
 
   procedure Add_Source_Dir (N : String) is
   begin
      Add_Src_Search_Dir (N);
 
      if Opt.Verbose_Mode then
         Put ("Adding source directory """);
         Put (N);
         Put (""".");
         New_Line;
      end if;
   end Add_Source_Dir;
 
   -------------------
   -- ALI_File_Name --
   -------------------
 
   function ALI_File_Name (Source : File_Name_Type) return String is
      Src : constant String := Get_Name_String (Source);
 
   begin
      --  If the source name has an extension, then replace it with
      --  the ALI suffix.
 
      for Index in reverse Src'First + 1 .. Src'Last loop
         if Src (Index) = '.' then
            return Src (Src'First .. Index - 1) & ALI_Suffix;
         end if;
      end loop;
 
      --  If there is no dot, or if it is the first character, just add the
      --  ALI suffix.
 
      return Src & ALI_Suffix;
   end ALI_File_Name;
 
   ------------------------
   -- Assembly_File_Name --
   ------------------------
 
   function Assembly_File_Name (Source : File_Name_Type) return String is
      Src : constant String := Get_Name_String (Source);
 
   begin
      --  If the source name has an extension, then replace it with
      --  the assembly suffix.
 
      for Index in reverse Src'First + 1 .. Src'Last loop
         if Src (Index) = '.' then
            return Src (Src'First .. Index - 1) & Assembly_Suffix;
         end if;
      end loop;
 
      --  If there is no dot, or if it is the first character, just add the
      --  assembly suffix.
 
      return Src & Assembly_Suffix;
   end Assembly_File_Name;
 
   -------------------
   -- Clean_Archive --
   -------------------
 
   procedure Clean_Archive (Project : Project_Id; Global : Boolean) is
      Current_Dir : constant Dir_Name_Str := Get_Current_Dir;
 
      Lib_Prefix : String_Access;
      Archive_Name : String_Access;
      --  The name of the archive file for this project
 
      Archive_Dep_Name : String_Access;
      --  The name of the archive dependency file for this project
 
      Obj_Dir : constant String :=
                  Get_Name_String (Project.Object_Directory.Display_Name);
 
   begin
      Change_Dir (Obj_Dir);
 
      --  First, get the lib prefix, the archive file name and the archive
      --  dependency file name.
 
      if Global then
         Lib_Prefix :=
           new String'("lib" & Get_Name_String (Project.Display_Name));
      else
         Lib_Prefix :=
           new String'("lib" & Get_Name_String (Project.Library_Name));
      end if;
 
      Archive_Name := new String'(Lib_Prefix.all & '.' & Archive_Ext);
      Archive_Dep_Name := new String'(Lib_Prefix.all & ".deps");
 
      --  Delete the archive file and the archive dependency file, if they
      --  exist.
 
      if Is_Regular_File (Archive_Name.all) then
         Delete (Obj_Dir, Archive_Name.all);
      end if;
 
      if Is_Regular_File (Archive_Dep_Name.all) then
         Delete (Obj_Dir, Archive_Dep_Name.all);
      end if;
 
      Change_Dir (Current_Dir);
   end Clean_Archive;
 
   -----------------------
   -- Clean_Executables --
   -----------------------
 
   procedure Clean_Executables is
      Main_Source_File : File_Name_Type;
      --  Current main source
 
      Main_Lib_File : File_Name_Type;
      --  ALI file of the current main
 
      Lib_File : File_Name_Type;
      --  Current ALI file
 
      Full_Lib_File : File_Name_Type;
      --  Full name of the current ALI file
 
      Text    : Text_Buffer_Ptr;
      The_ALI : ALI_Id;
 
   begin
      Init_Q;
 
      --  It does not really matter if there is or not an object file
      --  corresponding to an ALI file: if there is one, it will be deleted.
 
      Opt.Check_Object_Consistency := False;
 
      --  Proceed each executable one by one. Each source is marked as it is
      --  processed, so common sources between executables will not be
      --  processed several times.
 
      for N_File in 1 .. Osint.Number_Of_Files loop
         Main_Source_File := Next_Main_Source;
         Main_Lib_File := Osint.Lib_File_Name
                             (Main_Source_File, Current_File_Index);
         Insert_Q (Main_Lib_File);
 
         while not Empty_Q loop
            Sources.Set_Last (0);
            Extract_From_Q (Lib_File);
            Full_Lib_File := Osint.Full_Lib_File_Name (Lib_File);
 
            --  If we have existing ALI file that is not read-only, process it
 
            if Full_Lib_File /= No_File
              and then not Is_Readonly_Library (Full_Lib_File)
            then
               Text := Read_Library_Info (Lib_File);
 
               if Text /= null then
                  The_ALI :=
                    Scan_ALI (Lib_File, Text, Ignore_ED => False, Err => True);
                  Free (Text);
 
                  --  If no error was produced while loading this ALI file,
                  --  insert into the queue all the unmarked withed sources.
 
                  if The_ALI /= No_ALI_Id then
                     for J in ALIs.Table (The_ALI).First_Unit ..
                       ALIs.Table (The_ALI).Last_Unit
                     loop
                        Sources.Increment_Last;
                        Sources.Table (Sources.Last) :=
                          ALI.Units.Table (J).Sfile;
 
                        for K in ALI.Units.Table (J).First_With ..
                          ALI.Units.Table (J).Last_With
                        loop
                           Insert_Q (Withs.Table (K).Afile);
                        end loop;
                     end loop;
 
                     --  Look for subunits and put them in the Sources table
 
                     for J in ALIs.Table (The_ALI).First_Sdep ..
                       ALIs.Table (The_ALI).Last_Sdep
                     loop
                        if Sdep.Table (J).Subunit_Name /= No_Name then
                           Sources.Increment_Last;
                           Sources.Table (Sources.Last) :=
                             Sdep.Table (J).Sfile;
                        end if;
                     end loop;
                  end if;
               end if;
 
               --  Now delete all existing files corresponding to this ALI file
 
               declare
                  Obj_Dir : constant String :=
                              Dir_Name (Get_Name_String (Full_Lib_File));
                  Obj     : constant String := Object_File_Name (Lib_File);
                  Adt     : constant String := Tree_File_Name   (Lib_File);
                  Asm     : constant String := Assembly_File_Name (Lib_File);
 
               begin
                  Delete (Obj_Dir, Get_Name_String (Lib_File));
 
                  if Is_Regular_File (Obj_Dir & Dir_Separator & Obj) then
                     Delete (Obj_Dir, Obj);
                  end if;
 
                  if Is_Regular_File (Obj_Dir & Dir_Separator & Adt) then
                     Delete (Obj_Dir, Adt);
                  end if;
 
                  if Is_Regular_File (Obj_Dir & Dir_Separator & Asm) then
                     Delete (Obj_Dir, Asm);
                  end if;
 
                  --  Delete expanded source files (.dg) and/or repinfo files
                  --  (.rep) if any
 
                  for J in 1 .. Sources.Last loop
                     declare
                        Deb : constant String :=
                                Debug_File_Name (Sources.Table (J));
                        Rep : constant String :=
                                Repinfo_File_Name (Sources.Table (J));
 
                     begin
                        if Is_Regular_File (Obj_Dir & Dir_Separator & Deb) then
                           Delete (Obj_Dir, Deb);
                        end if;
 
                        if Is_Regular_File (Obj_Dir & Dir_Separator & Rep) then
                           Delete (Obj_Dir, Rep);
                        end if;
                     end;
                  end loop;
               end;
            end if;
         end loop;
 
         --  Delete the executable, if it exists, and the binder generated
         --  files, if any.
 
         if not Compile_Only then
            declare
               Source     : constant File_Name_Type :=
                              Strip_Suffix (Main_Lib_File);
               Executable : constant String :=
                              Get_Name_String (Executable_Name (Source));
            begin
               if Is_Regular_File (Executable) then
                  Delete ("", Executable);
               end if;
 
               Delete_Binder_Generated_Files (Get_Current_Dir, Source);
            end;
         end if;
      end loop;
   end Clean_Executables;
 
   ------------------------------------
   -- Clean_Interface_Copy_Directory --
   ------------------------------------
 
   procedure Clean_Interface_Copy_Directory (Project : Project_Id) is
      Current : constant String := Get_Current_Dir;
 
      Direc : Dir_Type;
 
      Name : String (1 .. 200);
      Last : Natural;
 
      Delete_File : Boolean;
      Unit        : Unit_Index;
 
   begin
      if Project.Library
        and then Project.Library_Src_Dir /= No_Path_Information
      then
         declare
            Directory : constant String :=
                        Get_Name_String (Project.Library_Src_Dir.Display_Name);
 
         begin
            Change_Dir (Directory);
            Open (Direc, ".");
 
            --  For each regular file in the directory, if switch -n has not
            --  been specified, make it writable and delete the file if it is
            --  a copy of a source of the project.
 
            loop
               Read (Direc, Name, Last);
               exit when Last = 0;
 
               declare
                  Filename : constant String := Name (1 .. Last);
 
               begin
                  if Is_Regular_File (Filename) then
                     Canonical_Case_File_Name (Name (1 .. Last));
                     Delete_File := False;
 
                     Unit := Units_Htable.Get_First (Project_Tree.Units_HT);
 
                     --  Compare with source file names of the project
 
                     while Unit /= No_Unit_Index loop
                        if Unit.File_Names (Impl) /= null
                          and then Ultimate_Extending_Project_Of
                                     (Unit.File_Names (Impl).Project) = Project
                          and then
                            Get_Name_String (Unit.File_Names (Impl).File) =
                                                              Name (1 .. Last)
                        then
                           Delete_File := True;
                           exit;
                        end if;
 
                        if Unit.File_Names (Spec) /= null
                          and then Ultimate_Extending_Project_Of
                                     (Unit.File_Names (Spec).Project) = Project
                          and then
                            Get_Name_String
                              (Unit.File_Names (Spec).File) = Name (1 .. Last)
                        then
                           Delete_File := True;
                           exit;
                        end if;
 
                        Unit := Units_Htable.Get_Next (Project_Tree.Units_HT);
                     end loop;
 
                     if Delete_File then
                        if not Do_Nothing then
                           Set_Writable (Filename);
                        end if;
 
                        Delete (Directory, Filename);
                     end if;
                  end if;
               end;
            end loop;
 
            Close (Direc);
 
            --  Restore the initial working directory
 
            Change_Dir (Current);
         end;
      end if;
   end Clean_Interface_Copy_Directory;
 
   -----------------------------
   -- Clean_Library_Directory --
   -----------------------------
 
   Empty_String : aliased String := "";
 
   procedure Clean_Library_Directory (Project : Project_Id) is
      Current : constant String := Get_Current_Dir;
 
      Lib_Filename : constant String := Get_Name_String (Project.Library_Name);
      DLL_Name     : String :=
                       DLL_Prefix & Lib_Filename & "." & DLL_Ext;
      Archive_Name : String :=
                       "lib" & Lib_Filename & "." & Archive_Ext;
      Direc        : Dir_Type;
 
      Name : String (1 .. 200);
      Last : Natural;
 
      Delete_File : Boolean;
 
      Minor : String_Access := Empty_String'Access;
      Major : String_Access := Empty_String'Access;
 
   begin
      if Project.Library then
         if Project.Library_Kind /= Static
           and then MLib.Tgt.Library_Major_Minor_Id_Supported
           and then Project.Lib_Internal_Name /= No_Name
         then
            Minor := new String'(Get_Name_String (Project.Lib_Internal_Name));
            Major := new String'(MLib.Major_Id_Name (DLL_Name, Minor.all));
         end if;
 
         declare
            Lib_Directory     : constant String :=
                                  Get_Name_String
                                    (Project.Library_Dir.Display_Name);
            Lib_ALI_Directory : constant String :=
                                  Get_Name_String
                                    (Project.Library_ALI_Dir.Display_Name);
 
         begin
            Canonical_Case_File_Name (Archive_Name);
            Canonical_Case_File_Name (DLL_Name);
 
            Change_Dir (Lib_Directory);
            Open (Direc, ".");
 
            --  For each regular file in the directory, if switch -n has not
            --  been specified, make it writable and delete the file if it is
            --  the library file.
 
            loop
               Read (Direc, Name, Last);
               exit when Last = 0;
 
               declare
                  Filename : constant String := Name (1 .. Last);
 
               begin
                  if Is_Regular_File (Filename)
                    or else Is_Symbolic_Link (Filename)
                  then
                     Canonical_Case_File_Name (Name (1 .. Last));
                     Delete_File := False;
 
                     if (Project.Library_Kind = Static
                          and then Name (1 .. Last) =  Archive_Name)
                       or else
                         ((Project.Library_Kind = Dynamic
                             or else
                           Project.Library_Kind = Relocatable)
                          and then
                            (Name (1 .. Last) = DLL_Name
                               or else
                             Name (1 .. Last) = Minor.all
                               or else
                             Name (1 .. Last) = Major.all))
                     then
                        if not Do_Nothing then
                           Set_Writable (Filename);
                        end if;
 
                        Delete (Lib_Directory, Filename);
                     end if;
                  end if;
               end;
            end loop;
 
            Close (Direc);
 
            Change_Dir (Lib_ALI_Directory);
            Open (Direc, ".");
 
            --  For each regular file in the directory, if switch -n has not
            --  been specified, make it writable and delete the file if it is
            --  any ALI file of a source of the project.
 
            loop
               Read (Direc, Name, Last);
               exit when Last = 0;
 
               declare
                  Filename : constant String := Name (1 .. Last);
               begin
                  if Is_Regular_File (Filename) then
                     Canonical_Case_File_Name (Name (1 .. Last));
                     Delete_File := False;
 
                     if Last > 4 and then Name (Last - 3 .. Last) = ".ali" then
                        declare
                           Unit : Unit_Index;
                        begin
                           --  Compare with ALI file names of the project
 
                           Unit := Units_Htable.Get_First
                             (Project_Tree.Units_HT);
                           while Unit /= No_Unit_Index loop
                              if Unit.File_Names (Impl) /= null
                                and then Unit.File_Names (Impl).Project /=
                                                                   No_Project
                              then
                                 if Ultimate_Extending_Project_Of
                                      (Unit.File_Names (Impl).Project) =
                                                                   Project
                                 then
                                    Get_Name_String
                                      (Unit.File_Names (Impl).File);
                                    Name_Len := Name_Len -
                                      File_Extension
                                        (Name (1 .. Name_Len))'Length;
                                    if Name_Buffer (1 .. Name_Len) =
                                         Name (1 .. Last - 4)
                                    then
                                       Delete_File := True;
                                       exit;
                                    end if;
                                 end if;
 
                              elsif Unit.File_Names (Spec) /= null
                                and then Ultimate_Extending_Project_Of
                                           (Unit.File_Names (Spec).Project) =
                                                                    Project
                              then
                                 Get_Name_String
                                   (Unit.File_Names (Spec).File);
                                 Name_Len :=
                                   Name_Len -
                                     File_Extension
                                       (Name (1 .. Name_Len))'Length;
 
                                 if Name_Buffer (1 .. Name_Len) =
                                      Name (1 .. Last - 4)
                                 then
                                    Delete_File := True;
                                    exit;
                                 end if;
                              end if;
 
                              Unit :=
                                Units_Htable.Get_Next (Project_Tree.Units_HT);
                           end loop;
                        end;
                     end if;
 
                     if Delete_File then
                        if not Do_Nothing then
                           Set_Writable (Filename);
                        end if;
 
                        Delete (Lib_ALI_Directory, Filename);
                     end if;
                  end if;
               end;
            end loop;
 
            Close (Direc);
 
            --  Restore the initial working directory
 
            Change_Dir (Current);
         end;
      end if;
   end Clean_Library_Directory;
 
   -------------------
   -- Clean_Project --
   -------------------
 
   procedure Clean_Project (Project : Project_Id) is
      Main_Source_File : File_Name_Type;
      --  Name of executable on the command line without directory info
 
      Executable : File_Name_Type;
      --  Name of the executable file
 
      Current_Dir : constant Dir_Name_Str := Get_Current_Dir;
      Unit        : Unit_Index;
      File_Name1  : File_Name_Type;
      Index1      : Int;
      File_Name2  : File_Name_Type;
      Index2      : Int;
      Lib_File    : File_Name_Type;
 
      Global_Archive : Boolean := False;
 
   begin
      --  Check that we don't specify executable on the command line for
      --  a main library project.
 
      if Project = Main_Project
        and then Osint.Number_Of_Files /= 0
        and then Project.Library
      then
         Osint.Fail
           ("Cannot specify executable(s) for a Library Project File");
      end if;
 
      --  Nothing to clean in an externally built project
 
      if Project.Externally_Built then
         if Verbose_Mode then
            Put ("Nothing to do to clean externally built project """);
            Put (Get_Name_String (Project.Name));
            Put_Line ("""");
         end if;
 
      else
         if Verbose_Mode then
            Put ("Cleaning project """);
            Put (Get_Name_String (Project.Name));
            Put_Line ("""");
         end if;
 
         --  Add project to the list of processed projects
 
         Processed_Projects.Increment_Last;
         Processed_Projects.Table (Processed_Projects.Last) := Project;
 
         if Project.Object_Directory /= No_Path_Information then
            declare
               Obj_Dir : constant String :=
                           Get_Name_String
                             (Project.Object_Directory.Display_Name);
 
            begin
               Change_Dir (Obj_Dir);
 
               --  First, deal with Ada
 
               --  Look through the units to find those that are either
               --  immediate sources or inherited sources of the project.
               --  Extending projects may have no language specified, if
               --  Source_Dirs or Source_Files is specified as an empty list,
               --  so always look for Ada units in extending projects.
 
               if Has_Ada_Sources (Project)
                 or else Project.Extends /= No_Project
               then
                  Unit := Units_Htable.Get_First (Project_Tree.Units_HT);
                  while Unit /= No_Unit_Index loop
                     File_Name1 := No_File;
                     File_Name2 := No_File;
 
                     --  If either the spec or the body is a source of the
                     --  project, check for the corresponding ALI file in the
                     --  object directory.
 
                     if (Unit.File_Names (Impl) /= null
                         and then
                           In_Extension_Chain
                             (Unit.File_Names (Impl).Project, Project))
                       or else
                         (Unit.File_Names (Spec) /= null
                          and then In_Extension_Chain
                            (Unit.File_Names (Spec).Project, Project))
                     then
                        if Unit.File_Names (Impl) /= null then
                           File_Name1 := Unit.File_Names (Impl).File;
                           Index1     := Unit.File_Names (Impl).Index;
                        else
                           File_Name1 := No_File;
                           Index1     := 0;
                        end if;
 
                        if Unit.File_Names (Spec) /= null then
                           File_Name2 := Unit.File_Names (Spec).File;
                           Index2     := Unit.File_Names (Spec).Index;
                        else
                           File_Name2 := No_File;
                           Index2     := 0;
                        end if;
 
                        --  If there is no body file name, then there may be
                        --  only a spec.
 
                        if File_Name1 = No_File then
                           File_Name1 := File_Name2;
                           Index1     := Index2;
                           File_Name2 := No_File;
                           Index2     := 0;
                        end if;
                     end if;
 
                     --  If there is either a spec or a body, look for files
                     --  in the object directory.
 
                     if File_Name1 /= No_File then
                        Lib_File := Osint.Lib_File_Name (File_Name1, Index1);
 
                        declare
                           Asm : constant String :=
                                   Assembly_File_Name (Lib_File);
                           ALI : constant String :=
                                   ALI_File_Name      (Lib_File);
                           Obj : constant String :=
                                   Object_File_Name   (Lib_File);
                           Adt : constant String :=
                                   Tree_File_Name     (Lib_File);
                           Deb : constant String :=
                                   Debug_File_Name    (File_Name1);
                           Rep : constant String :=
                                   Repinfo_File_Name  (File_Name1);
                           Del : Boolean := True;
 
                        begin
                           --  If the ALI file exists and is read-only, no file
                           --  is deleted.
 
                           if Is_Regular_File (ALI) then
                              if Is_Writable_File (ALI) then
                                 Delete (Obj_Dir, ALI);
 
                              else
                                 Del := False;
 
                                 if Verbose_Mode then
                                    Put ('"');
                                    Put (Obj_Dir);
 
                                    if Obj_Dir (Obj_Dir'Last) /=
                                      Dir_Separator
                                    then
                                       Put (Dir_Separator);
                                    end if;
 
                                    Put (ALI);
                                    Put_Line (""" is read-only");
                                 end if;
                              end if;
                           end if;
 
                           if Del then
 
                              --  Object file
 
                              if Is_Regular_File (Obj) then
                                 Delete (Obj_Dir, Obj);
                              end if;
 
                              --  Assembly file
 
                              if Is_Regular_File (Asm) then
                                 Delete (Obj_Dir, Asm);
                              end if;
 
                              --  Tree file
 
                              if Is_Regular_File (Adt) then
                                 Delete (Obj_Dir, Adt);
                              end if;
 
                              --  First expanded source file
 
                              if Is_Regular_File (Deb) then
                                 Delete (Obj_Dir, Deb);
                              end if;
 
                              --  Repinfo file
 
                              if Is_Regular_File (Rep) then
                                 Delete (Obj_Dir, Rep);
                              end if;
 
                              --  Second expanded source file
 
                              if File_Name2 /= No_File then
                                 declare
                                    Deb : constant String :=
                                            Debug_File_Name (File_Name2);
                                    Rep : constant String :=
                                            Repinfo_File_Name (File_Name2);
 
                                 begin
                                    if Is_Regular_File (Deb) then
                                       Delete (Obj_Dir, Deb);
                                    end if;
 
                                    if Is_Regular_File (Rep) then
                                       Delete (Obj_Dir, Rep);
                                    end if;
                                 end;
                              end if;
                           end if;
                        end;
                     end if;
 
                     Unit := Units_Htable.Get_Next (Project_Tree.Units_HT);
                  end loop;
               end if;
 
               --  Check if a global archive and it dependency file could have
               --  been created and, if they exist, delete them.
 
               if Project = Main_Project and then not Project.Library then
                  Global_Archive := False;
 
                  declare
                     Proj : Project_List;
 
                  begin
                     Proj := Project_Tree.Projects;
                     while Proj /= null loop
 
                        --  For gnatmake, when the project specifies more than
                        --  just Ada as a language (even if course we could not
                        --  find any source file for the other languages), we
                        --  will take all the object files found in the object
                        --  directories. Since we know the project supports at
                        --  least Ada, we just have to test whether it has at
                        --  least two languages, and we do not care about the
                        --  sources.
 
                        if Proj.Project.Languages /= null
                          and then Proj.Project.Languages.Next /= null
                        then
                           Global_Archive := True;
                           exit;
                        end if;
 
                        Proj := Proj.Next;
                     end loop;
                  end;
 
                  if Global_Archive then
                     Clean_Archive (Project, Global => True);
                  end if;
               end if;
 
            end;
         end if;
 
         --  If this is a library project, clean the library directory, the
         --  interface copy dir and, for a Stand-Alone Library, the binder
         --  generated files of the library.
 
         --  The directories are cleaned only if switch -c is not specified
 
         if Project.Library then
            if not Compile_Only then
               Clean_Library_Directory (Project);
 
               if Project.Library_Src_Dir /= No_Path_Information then
                  Clean_Interface_Copy_Directory (Project);
               end if;
            end if;
 
            if Project.Standalone_Library and then
              Project.Object_Directory /= No_Path_Information
            then
               Delete_Binder_Generated_Files
                 (Get_Name_String (Project.Object_Directory.Display_Name),
                  File_Name_Type (Project.Library_Name));
            end if;
         end if;
 
         if Verbose_Mode then
            New_Line;
         end if;
      end if;
 
      --  If switch -r is specified, call Clean_Project recursively for the
      --  imported projects and the project being extended.
 
      if All_Projects then
         declare
            Imported : Project_List;
            Process  : Boolean;
 
         begin
            --  For each imported project, call Clean_Project if the project
            --  has not been processed already.
 
            Imported := Project.Imported_Projects;
            while Imported /= null loop
               Process := True;
 
               for
                 J in Processed_Projects.First .. Processed_Projects.Last
               loop
                  if Imported.Project = Processed_Projects.Table (J) then
                     Process := False;
                     exit;
                  end if;
               end loop;
 
               if Process then
                  Clean_Project (Imported.Project);
               end if;
 
               Imported := Imported.Next;
            end loop;
 
            --  If this project extends another project, call Clean_Project for
            --  the project being extended. It is guaranteed that it has not
            --  called before, because no other project may import or extend
            --  this project.
 
            if Project.Extends /= No_Project then
               Clean_Project (Project.Extends);
            end if;
         end;
      end if;
 
         --  For the main project, delete the executables and the binder
         --  generated files.
 
         --  The executables are deleted only if switch -c is not specified
 
      if Project = Main_Project
        and then Project.Exec_Directory /= No_Path_Information
      then
         declare
            Exec_Dir : constant String :=
                         Get_Name_String (Project.Exec_Directory.Display_Name);
 
         begin
            Change_Dir (Exec_Dir);
 
            for N_File in 1 .. Osint.Number_Of_Files loop
               Main_Source_File := Next_Main_Source;
 
               if not Compile_Only then
                  Executable :=
                    Executable_Of
                      (Main_Project,
                       Project_Tree,
                       Main_Source_File,
                       Current_File_Index);
 
                  declare
                     Exec_File_Name : constant String :=
                                        Get_Name_String (Executable);
 
                  begin
                     if Is_Absolute_Path (Name => Exec_File_Name) then
                        if Is_Regular_File (Exec_File_Name) then
                           Delete ("", Exec_File_Name);
                        end if;
 
                     else
                        if Is_Regular_File (Exec_File_Name) then
                           Delete (Exec_Dir, Exec_File_Name);
                        end if;
                     end if;
                  end;
               end if;
 
               if Project.Object_Directory /= No_Path_Information then
                  Delete_Binder_Generated_Files
                    (Get_Name_String (Project.Object_Directory.Display_Name),
                     Strip_Suffix (Main_Source_File));
               end if;
            end loop;
         end;
      end if;
 
      --  Change back to previous directory
 
      Change_Dir (Current_Dir);
   end Clean_Project;
 
   ---------------------
   -- Debug_File_Name --
   ---------------------
 
   function Debug_File_Name (Source : File_Name_Type) return String is
   begin
      return Get_Name_String (Source) & Debug_Suffix;
   end Debug_File_Name;
 
   ------------
   -- Delete --
   ------------
 
   procedure Delete (In_Directory : String; File : String) is
      Full_Name : String (1 .. In_Directory'Length + File'Length + 1);
      Last      : Natural := 0;
      Success   : Boolean;
 
   begin
      --  Indicate that at least one file is deleted or is to be deleted
 
      File_Deleted := True;
 
      --  Build the path name of the file to delete
 
      Last := In_Directory'Length;
      Full_Name (1 .. Last) := In_Directory;
 
      if Last > 0 and then Full_Name (Last) /= Directory_Separator then
         Last := Last + 1;
         Full_Name (Last) := Directory_Separator;
      end if;
 
      Full_Name (Last + 1 .. Last + File'Length) := File;
      Last := Last + File'Length;
 
      --  If switch -n was used, simply output the path name
 
      if Do_Nothing then
         Put_Line (Full_Name (1 .. Last));
 
      --  Otherwise, delete the file if it is writable
 
      else
         if Force_Deletions
           or else Is_Writable_File (Full_Name (1 .. Last))
           or else Is_Symbolic_Link (Full_Name (1 .. Last))
         then
            Delete_File (Full_Name (1 .. Last), Success);
         else
            Success := False;
         end if;
 
         if Verbose_Mode or else not Quiet_Output then
            if not Success then
               Put ("Warning: """);
               Put (Full_Name (1 .. Last));
               Put_Line (""" could not be deleted");
 
            else
               Put ("""");
               Put (Full_Name (1 .. Last));
               Put_Line (""" has been deleted");
            end if;
         end if;
      end if;
   end Delete;
 
   -----------------------------------
   -- Delete_Binder_Generated_Files --
   -----------------------------------
 
   procedure Delete_Binder_Generated_Files
     (Dir    : String;
      Source : File_Name_Type)
   is
      Source_Name : constant String   := Get_Name_String (Source);
      Current     : constant String   := Get_Current_Dir;
      Last        : constant Positive := B_Start'Length + Source_Name'Length;
      File_Name   : String (1 .. Last + 4);
 
   begin
      Change_Dir (Dir);
 
      --  Build the file name (before the extension)
 
      File_Name (1 .. B_Start'Length) := B_Start.all;
      File_Name (B_Start'Length + 1 .. Last) := Source_Name;
 
      --  Spec
 
      File_Name (Last + 1 .. Last + 4) := ".ads";
 
      if Is_Regular_File (File_Name (1 .. Last + 4)) then
         Delete (Dir, File_Name (1 .. Last + 4));
      end if;
 
      --  Body
 
      File_Name (Last + 1 .. Last + 4) := ".adb";
 
      if Is_Regular_File (File_Name (1 .. Last + 4)) then
         Delete (Dir, File_Name (1 .. Last + 4));
      end if;
 
      --  ALI file
 
      File_Name (Last + 1 .. Last + 4) := ".ali";
 
      if Is_Regular_File (File_Name (1 .. Last + 4)) then
         Delete (Dir, File_Name (1 .. Last + 4));
      end if;
 
      --  Object file
 
      File_Name (Last + 1 .. Last + Object_Suffix'Length) := Object_Suffix;
 
      if Is_Regular_File (File_Name (1 .. Last + Object_Suffix'Length)) then
         Delete (Dir, File_Name (1 .. Last + Object_Suffix'Length));
      end if;
 
      --  Change back to previous directory
 
      Change_Dir (Current);
   end Delete_Binder_Generated_Files;
 
   -----------------------
   -- Display_Copyright --
   -----------------------
 
   procedure Display_Copyright is
   begin
      if not Copyright_Displayed then
         Copyright_Displayed := True;
         Display_Version ("GNATCLEAN", "2003");
      end if;
   end Display_Copyright;
 
   -------------
   -- Empty_Q --
   -------------
 
   function Empty_Q return Boolean is
   begin
      return Q_Front >= Q.Last;
   end Empty_Q;
 
   --------------------
   -- Extract_From_Q --
   --------------------
 
   procedure Extract_From_Q (Lib_File : out File_Name_Type) is
      Lib : constant File_Name_Type := Q.Table (Q_Front);
   begin
      Q_Front  := Q_Front + 1;
      Lib_File := Lib;
   end Extract_From_Q;
 
   ---------------
   -- Gnatclean --
   ---------------
 
   procedure Gnatclean is
   begin
      --  Do the necessary initializations
 
      Clean.Initialize;
 
      --  Parse the command line, getting the switches and the executable names
 
      Parse_Cmd_Line;
 
      if Verbose_Mode then
         Display_Copyright;
      end if;
 
      if Project_File_Name /= null then
 
         --  A project file was specified by a -P switch
 
         if Opt.Verbose_Mode then
            New_Line;
            Put ("Parsing Project File """);
            Put (Project_File_Name.all);
            Put_Line (""".");
            New_Line;
         end if;
 
         --  Set the project parsing verbosity to whatever was specified
         --  by a possible -vP switch.
 
         Prj.Pars.Set_Verbosity (To => Current_Verbosity);
 
         --  Parse the project file. If there is an error, Main_Project
         --  will still be No_Project.
 
         Prj.Pars.Parse
           (Project           => Main_Project,
            In_Tree           => Project_Tree,
            In_Node_Tree      => Project_Node_Tree,
            Project_File_Name => Project_File_Name.all,
            Flags             => Gnatmake_Flags,
            Packages_To_Check => Packages_To_Check_By_Gnatmake);
 
         if Main_Project = No_Project then
            Fail ("""" & Project_File_Name.all & """ processing failed");
         end if;
 
         if Opt.Verbose_Mode then
            New_Line;
            Put ("Parsing of Project File """);
            Put (Project_File_Name.all);
            Put (""" is finished.");
            New_Line;
         end if;
 
         --  Add source directories and object directories to the search paths
 
         Add_Source_Directories (Main_Project, Project_Tree);
         Add_Object_Directories (Main_Project);
      end if;
 
      Osint.Add_Default_Search_Dirs;
 
      --  If a project file was specified, but no executable name, put all
      --  the mains of the project file (if any) as if there were on the
      --  command line.
 
      if Main_Project /= No_Project and then Osint.Number_Of_Files = 0 then
         declare
            Main  : String_Element;
            Value : String_List_Id := Main_Project.Mains;
         begin
            while Value /= Prj.Nil_String loop
               Main := Project_Tree.String_Elements.Table (Value);
               Osint.Add_File
                 (File_Name => Get_Name_String (Main.Value),
                  Index     => Main.Index);
               Value := Main.Next;
            end loop;
         end;
      end if;
 
      --  If neither a project file nor an executable were specified, output
      --  the usage and exit.
 
      if Main_Project = No_Project and then Osint.Number_Of_Files = 0 then
         Usage;
         return;
      end if;
 
      if Verbose_Mode then
         New_Line;
      end if;
 
      if Main_Project /= No_Project then
 
         --  If a project file has been specified, call Clean_Project with the
         --  project id of this project file, after resetting the list of
         --  processed projects.
 
         Processed_Projects.Init;
         Clean_Project (Main_Project);
 
      else
         --  If no project file has been specified, the work is done in
         --  Clean_Executables.
 
         Clean_Executables;
      end if;
 
      --  In verbose mode, if Delete has not been called, indicate that no file
      --  needs to be deleted.
 
      if Verbose_Mode and (not File_Deleted) then
         New_Line;
 
         if Do_Nothing then
            Put_Line ("No file needs to be deleted");
         else
            Put_Line ("No file has been deleted");
         end if;
      end if;
   end Gnatclean;
 
   ------------------------
   -- In_Extension_Chain --
   ------------------------
 
   function In_Extension_Chain
     (Of_Project : Project_Id;
      Prj        : Project_Id) return Boolean
   is
      Proj : Project_Id;
 
   begin
      if Prj = No_Project or else Of_Project = No_Project then
         return False;
      end if;
 
      if Of_Project = Prj then
         return True;
      end if;
 
      Proj := Of_Project;
      while Proj.Extends /= No_Project loop
         if Proj.Extends = Prj then
            return True;
         end if;
 
         Proj := Proj.Extends;
      end loop;
 
      Proj := Prj;
      while Proj.Extends /= No_Project loop
         if Proj.Extends = Of_Project then
            return True;
         end if;
 
         Proj := Proj.Extends;
      end loop;
 
      return False;
   end In_Extension_Chain;
 
   ------------
   -- Init_Q --
   ------------
 
   procedure Init_Q is
   begin
      Q_Front := Q.First;
      Q.Set_Last (Q.First);
   end Init_Q;
 
   ----------------
   -- Initialize --
   ----------------
 
   procedure Initialize is
   begin
      if not Initialized then
         Initialized := True;
 
         --  Get default search directories to locate system.ads when calling
         --  Targparm.Get_Target_Parameters.
 
         Osint.Add_Default_Search_Dirs;
 
         --  Initialize some packages
 
         Csets.Initialize;
         Namet.Initialize;
         Snames.Initialize;
 
         Project_Node_Tree := new Project_Node_Tree_Data;
         Prj.Tree.Initialize (Project_Node_Tree);
 
         Prj.Initialize (Project_Tree);
 
         --  Check if the platform is VMS and, if it is, change some variables
 
         Targparm.Get_Target_Parameters;
 
         if OpenVMS_On_Target then
            Debug_Suffix (Debug_Suffix'First) := '_';
            Repinfo_Suffix (Repinfo_Suffix'First) := '_';
            B_Start := new String'("b__");
         end if;
      end if;
 
      --  Reset global variables
 
      Free (Object_Directory_Path);
      Do_Nothing := False;
      File_Deleted := False;
      Copyright_Displayed := False;
      Usage_Displayed := False;
      Free (Project_File_Name);
      Main_Project := Prj.No_Project;
      All_Projects := False;
   end Initialize;
 
   --------------
   -- Insert_Q --
   --------------
 
   procedure Insert_Q (Lib_File : File_Name_Type) is
   begin
      --  Do not insert an empty name or an already marked source
 
      if Lib_File /= No_File and then not Makeutl.Is_Marked (Lib_File) then
         Q.Table (Q.Last) := Lib_File;
         Q.Increment_Last;
 
         --  Mark the source that has been just added to the Q
 
         Makeutl.Mark (Lib_File);
      end if;
   end Insert_Q;
 
   ----------------------
   -- Object_File_Name --
   ----------------------
 
   function Object_File_Name (Source : File_Name_Type) return String is
      Src : constant String := Get_Name_String (Source);
 
   begin
      --  If the source name has an extension, then replace it with
      --  the Object suffix.
 
      for Index in reverse Src'First + 1 .. Src'Last loop
         if Src (Index) = '.' then
            return Src (Src'First .. Index - 1) & Object_Suffix;
         end if;
      end loop;
 
      --  If there is no dot, or if it is the first character, just add the
      --  ALI suffix.
 
      return Src & Object_Suffix;
   end Object_File_Name;
 
   --------------------
   -- Parse_Cmd_Line --
   --------------------
 
   procedure Parse_Cmd_Line is
      Last         : constant Natural := Argument_Count;
      Source_Index : Int := 0;
      Index        : Positive;
 
      procedure Check_Version_And_Help is new Check_Version_And_Help_G (Usage);
 
   begin
      --  First, check for --version and --help
 
      Check_Version_And_Help ("GNATCLEAN", "2003");
 
      Index := 1;
      while Index <= Last loop
         declare
            Arg : constant String := Argument (Index);
 
            procedure Bad_Argument;
            --  Signal bad argument
 
            ------------------
            -- Bad_Argument --
            ------------------
 
            procedure Bad_Argument is
            begin
               Fail ("invalid argument """ & Arg & """");
            end Bad_Argument;
 
         begin
            if Arg'Length /= 0 then
               if Arg (1) = '-' then
                  if Arg'Length = 1 then
                     Bad_Argument;
                  end if;
 
                  case Arg (2) is
                     when '-' =>
                        if Arg'Length > Subdirs_Option'Length and then
                          Arg (1 .. Subdirs_Option'Length) = Subdirs_Option
                        then
                           Subdirs :=
                             new String'
                               (Arg (Subdirs_Option'Length + 1 .. Arg'Last));
 
                        else
                           Bad_Argument;
                        end if;
 
                     when 'a' =>
                        if Arg'Length < 4 then
                           Bad_Argument;
                        end if;
 
                        if Arg (3) = 'O' then
                           Add_Lib_Search_Dir (Arg (4 .. Arg'Last));
 
                        elsif Arg (3) = 'P' then
                           Prj.Ext.Add_Search_Project_Directory
                             (Project_Node_Tree, Arg (4 .. Arg'Last));
 
                        else
                           Bad_Argument;
                        end if;
 
                     when 'c'    =>
                        Compile_Only := True;
 
                     when 'D'    =>
                        if Object_Directory_Path /= null then
                           Fail ("duplicate -D switch");
 
                        elsif Project_File_Name /= null then
                           Fail ("-P and -D cannot be used simultaneously");
                        end if;
 
                        if Arg'Length > 2 then
                           declare
                              Dir : constant String := Arg (3 .. Arg'Last);
                           begin
                              if not Is_Directory (Dir) then
                                 Fail (Dir & " is not a directory");
                              else
                                 Add_Lib_Search_Dir (Dir);
                              end if;
                           end;
 
                        else
                           if Index = Last then
                              Fail ("no directory specified after -D");
                           end if;
 
                           Index := Index + 1;
 
                           declare
                              Dir : constant String := Argument (Index);
                           begin
                              if not Is_Directory (Dir) then
                                 Fail (Dir & " is not a directory");
                              else
                                 Add_Lib_Search_Dir (Dir);
                              end if;
                           end;
                        end if;
 
                     when 'e' =>
                        if Arg = "-eL" then
                           Follow_Links_For_Files := True;
                           Follow_Links_For_Dirs  := True;
 
                        else
                           Bad_Argument;
                        end if;
 
                     when 'f' =>
                        Force_Deletions := True;
 
                     when 'F' =>
                        Full_Path_Name_For_Brief_Errors := True;
 
                     when 'h' =>
                        Usage;
 
                     when 'i' =>
                        if Arg'Length = 2 then
                           Bad_Argument;
                        end if;
 
                        Source_Index := 0;
 
                        for J in 3 .. Arg'Last loop
                           if Arg (J) not in '0' .. '9' then
                              Bad_Argument;
                           end if;
 
                           Source_Index :=
                             (20 * Source_Index) +
                             (Character'Pos (Arg (J)) - Character'Pos ('0'));
                        end loop;
 
                     when 'I' =>
                        if Arg = "-I-" then
                           Opt.Look_In_Primary_Dir := False;
 
                        else
                           if Arg'Length = 2 then
                              Bad_Argument;
                           end if;
 
                           Add_Lib_Search_Dir (Arg (3 .. Arg'Last));
                        end if;
 
                     when 'n' =>
                        Do_Nothing := True;
 
                     when 'P' =>
                        if Project_File_Name /= null then
                           Fail ("multiple -P switches");
 
                        elsif Object_Directory_Path /= null then
                           Fail ("-D and -P cannot be used simultaneously");
 
                        end if;
 
                        if Arg'Length > 2 then
                           declare
                              Prj : constant String := Arg (3 .. Arg'Last);
                           begin
                              if Prj'Length > 1 and then
                                Prj (Prj'First) = '='
                              then
                                 Project_File_Name :=
                                   new String'
                                     (Prj (Prj'First + 1 ..  Prj'Last));
                              else
                                 Project_File_Name := new String'(Prj);
                              end if;
                           end;
 
                        else
                           if Index = Last then
                              Fail ("no project specified after -P");
                           end if;
 
                           Index := Index + 1;
                           Project_File_Name := new String'(Argument (Index));
                        end if;
 
                     when 'q' =>
                        Quiet_Output := True;
 
                     when 'r' =>
                        All_Projects := True;
 
                     when 'v' =>
                        if Arg = "-v" then
                           Verbose_Mode := True;
 
                        elsif Arg = "-vP0" then
                           Current_Verbosity := Prj.Default;
 
                        elsif Arg = "-vP1" then
                           Current_Verbosity := Prj.Medium;
 
                        elsif Arg = "-vP2" then
                           Current_Verbosity := Prj.High;
 
                        else
                           Bad_Argument;
                        end if;
 
                     when 'X' =>
                        if Arg'Length = 2 then
                           Bad_Argument;
                        end if;
 
                        declare
                           Ext_Asgn  : constant String := Arg (3 .. Arg'Last);
                           Start     : Positive := Ext_Asgn'First;
                           Stop      : Natural  := Ext_Asgn'Last;
                           Equal_Pos : Natural;
                           OK        : Boolean  := True;
 
                        begin
                           if Ext_Asgn (Start) = '"' then
                              if Ext_Asgn (Stop) = '"' then
                                 Start := Start + 1;
                                 Stop  := Stop - 1;
 
                              else
                                 OK := False;
                              end if;
                           end if;
 
                           Equal_Pos := Start;
 
                           while Equal_Pos <= Stop
                             and then Ext_Asgn (Equal_Pos) /= '='
                           loop
                              Equal_Pos := Equal_Pos + 1;
                           end loop;
 
                           if Equal_Pos = Start or else Equal_Pos > Stop then
                              OK := False;
                           end if;
 
                           if OK then
                              Prj.Ext.Add
                                (Project_Node_Tree,
                                 External_Name =>
                                   Ext_Asgn (Start .. Equal_Pos - 1),
                                 Value         =>
                                   Ext_Asgn (Equal_Pos + 1 .. Stop));
 
                           else
                              Fail
                                ("illegal external assignment '"
                                 & Ext_Asgn
                                 & "'");
                           end if;
                        end;
 
                     when others =>
                        Bad_Argument;
                  end case;
 
               else
                  Add_File (Arg, Source_Index);
               end if;
            end if;
         end;
 
         Index := Index + 1;
      end loop;
   end Parse_Cmd_Line;
 
   -----------------------
   -- Repinfo_File_Name --
   -----------------------
 
   function Repinfo_File_Name (Source : File_Name_Type) return String is
   begin
      return Get_Name_String (Source) & Repinfo_Suffix;
   end Repinfo_File_Name;
 
   --------------------
   -- Tree_File_Name --
   --------------------
 
   function Tree_File_Name (Source : File_Name_Type) return String is
      Src : constant String := Get_Name_String (Source);
 
   begin
      --  If source name has an extension, then replace it with the tree suffix
 
      for Index in reverse Src'First + 1 .. Src'Last loop
         if Src (Index) = '.' then
            return Src (Src'First .. Index - 1) & Tree_Suffix;
         end if;
      end loop;
 
      --  If there is no dot, or if it is the first character, just add the
      --  tree suffix.
 
      return Src & Tree_Suffix;
   end Tree_File_Name;
 
   -----------
   -- Usage --
   -----------
 
   procedure Usage is
   begin
      if not Usage_Displayed then
         Usage_Displayed := True;
         Display_Copyright;
         Put_Line ("Usage: gnatclean [switches] {[-innn] name}");
         New_Line;
 
         Put_Line ("  names is one or more file names from which " &
                   "the .adb or .ads suffix may be omitted");
         Put_Line ("  names may be omitted if -P<project> is specified");
         New_Line;
 
         Put_Line ("  --subdirs=dir real obj/lib/exec dirs are subdirs");
         New_Line;
 
         Put_Line ("  -c       Only delete compiler generated files");
         Put_Line ("  -D dir   Specify dir as the object library");
         Put_Line ("  -eL      Follow symbolic links when processing " &
                   "project files");
         Put_Line ("  -f       Force deletions of unwritable files");
         Put_Line ("  -F       Full project path name " &
                   "in brief error messages");
         Put_Line ("  -h       Display this message");
         Put_Line ("  -innn    Index of unit in source for following names");
         Put_Line ("  -n       Nothing to do: only list files to delete");
         Put_Line ("  -Pproj   Use GNAT Project File proj");
         Put_Line ("  -q       Be quiet/terse");
         Put_Line ("  -r       Clean all projects recursively");
         Put_Line ("  -v       Verbose mode");
         Put_Line ("  -vPx     Specify verbosity when parsing " &
                   "GNAT Project Files");
         Put_Line ("  -Xnm=val Specify an external reference " &
                   "for GNAT Project Files");
         New_Line;
 
         Put_Line ("  -aPdir   Add directory dir to project search path");
         New_Line;
 
         Put_Line ("  -aOdir   Specify ALI/object files search path");
         Put_Line ("  -Idir    Like -aOdir");
         Put_Line ("  -I-      Don't look for source/library files " &
                   "in the default directory");
         New_Line;
      end if;
   end Usage;
 
end Clean;
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.