------------------------------------------------------------------------------
--                                                                          --
--                     ASIS UTILITY LIBRARY COMPONENTS                      --
--                                                                          --
--                 A S I S _ U L . S O U R C E _ T A B L E                  --
--                                                                          --
--                                 S p e c                                  --
--                                                                          --
--                     Copyright (C) 2004-2011, AdaCore                     --
--                                                                          --
-- Asis Utility Library (ASIS UL) is free software; you can redistribute it --
-- and/or  modify  it  under  terms  of  the  GNU General Public License as --
-- published by the Free Software Foundation; either version 2, or (at your --
-- option)  any later version.  ASIS UL  is distributed in the hope that it --
-- will  be  useful,  but  WITHOUT  ANY  WARRANTY; without even the implied --
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --
-- GNU  General Public License for more details. You should have received a --
-- copy of the  GNU General Public License  distributed with GNAT; see file --
-- COPYING.  If not,  write  to the  Free Software Foundation,  51 Franklin --
-- Street, Fifth Floor, Boston, MA 02110-1301, USA.                         --
--                                                                          --
-- ASIS UL is maintained by AdaCore (http://www.adacore.com).               --
--                                                                          --
------------------------------------------------------------------------------

--  This package defines the source file table - the table containing the
--  information about the source files to be processed and the state of their
--  processing

with Asis;

package ASIS_UL.Source_Table is

   Low_SF_Bound  : constant := 0;
   High_SF_Bound : constant := 999_999;
   --  Almost 1_000_000 source files for one run of the tool

   type SF_Id is range Low_SF_Bound .. High_SF_Bound;

   No_SF_Id    : constant SF_Id := Low_SF_Bound;
   First_SF_Id : constant SF_Id := No_SF_Id + 1;

   Total_Sources : Natural;
   Sources_Left  : Natural;
   --  Counters used to form and output progress information.

   type SF_Status is (
      Waiting,
      --  Waiting for processing
      Not_A_Legal_Source,
      --  The file does not contain the compilable source

      Error_Detected,
      --  Some tool problem has been detected when processing this source
      --  so the results of processing may not be safe

      Out_File_Problem,
      --  The out file was not successfully created or opened

      ASIS_Processed,

      Non_ASIS_Processed,

      Processed);
      --  The source file has been successfully processed

   type SF_Info is new Integer;
   --  The type to be used for the integer values associate with each source in
   --  the source file table. The use of this value is client-specific

   function Present (SF : SF_Id) return Boolean;
   --  Checks that SF is not is equal to No_SF_Id

   function File_Find
     (SF_Name        : String;
      Use_Short_Name : Boolean := False)
      return           SF_Id;
   --  Returns the Id of the file with name SF_Name stored in the
   --  files table. Returns No_SF_Id if the table does not contain such file.
   --  In case if ASIS_UL.Common.Use_Project_File is set ON, or Use_Short_Name
   --  parameter is set ON, the short file name is used to locate the file, if
   --  the argument contains a directory information it is stripped out.
   --  Otherwise this function tries to locate the name with the full
   --  normalized name equal to SF_Name.

   function File_Find (El : Asis.Element) return SF_Id;
   --  Returns the Id of the file containing the argument Element enclosing
   --  compilation unit. Returns No_SF_Id if the argument is Nil_Element or
   --  if the source file table does not contain the given file.

   procedure Add_Source_To_Process
     (Fname              : String;
      No_Argument        : out Boolean;
      Duplication_Report : Boolean := True);
   --  Fname is treated as the name of the file to process by the tool.
   --  If it is an empty string, this procedure set No_Argument ON (to stop
   --  iteration through tool parameters) and does nothing more. Otherwise it
   --  tries to add this file to the table of files to process. The following
   --  checks are performed:
   --
   --  If ASIS_UL.Common.Use_Project_File is set ON:
   --
   --  - this routine checks if we have already stored a file with the same
   --    short(!) name. If we already have such a file, it generates a
   --    warning message (if Duplication_Report is set ON) and does nothing
   --    else.
   --
   --  If ASIS_UL.Common.Use_Project_File is set OFF:
   --
   --  - first, this routine checks if Fname is the name of some existing file,
   --    and if it is not, generates the corresponding diagnosis and does
   --    nothing more. When doing this check, this procedure takes into account
   --    the search path for the Ada sources only if
   --    ASIS_UL.Compiler_Options.Source_Search_Path is set, otherwise it just
   --    calls GNAT.OS_Lib.Is_Readable_File (Fname) and checks the result.
   --
   --  - then, it checks if we already have stored a file with the same name.
   --    If we have the file with the same name, but from a different
   --    directory, the corresponding warning is generated, but the file is
   --    added to the file table (the situation when the metric tool is called
   --    to process files with the same name but from different directories
   --    looks strange, but this may be quite legal and reasonable). But if we
   --    have already stored in the list the name of exactly the same file, we
   --    generate the error message and do not change anything in the list of
   --    files.
   --
   --  At this stage we do not know if Fname denotes a compilable Ada source
   --  file.
   --
   --  This procedure tries to detect if this source if the source of a
   --  body unit, and if so, strores this in the corresponding record of the
   --  source table. To define this, it checks the suffix of the file name.
   --  It treats suffixes '.adb' and '.2.ada' as suffixes of body files.
   --
   --  It is supposed to be used as a part of the tool parameter processing
   --  in the following way:
   --
   --      loop
   --         Add_Source_To_Process
   --           (Get_Argument (Do_Expansion => True), No_More_Args);
   --         exit when No_More_Args;
   --      end loop;

   procedure Store_Sources_To_Process
     (Fname              : String;
      No_Argument        : out Boolean);
   --  Fname is strored in internal database as the name of the file to
   --  process by the tool. No check is made if Fname denotes an existing file.
   --  No_Argument is set ON when Fname is an empty string and OFF otherwise.
   --  Similar to the previous Add_Source_To_Process routine, this procedure
   --  is supposed when processing tool parameters. The reason to use this
   --  procedure instead of Add_Source_To_Process is to do the checks if a file
   --  exists only when we already have the full seatch path for sources.
   --
   --  If Fname is not an empty string, stores the
   --  ASIS_UL.Options.No_Argument_File_Specified flag OFF

   procedure Read_Args_From_Temp_Storage (Duplication_Report : Boolean);
   --  Reads argument files from temporary storage (where they are placed by
   --  Store_Sources_To_Process/Store_Args_From_File routine(s)). Uses
   --  Add_Source_To_Process to read each file, so the check if a file exists
   --  is performed on the base of the source search path
   --  (ASIS_UL.Compiler_Options.Source_Search_Path). This procedure calls
   --  Add_Source_To_Process for each file to do the existance test and to
   --  store source in the source table. The temporary storage is cleaned up.
   --  The Duplication_Report parameter has the same meaning as for
   --  Add_Source_To_Process

   procedure Read_Args_From_File
     (Par_File_Name       : String;
      Store_With_No_Check : Boolean := False);
   --  Reads argument files from the file. If Store_With_No_Check is OFF,
   --  performs the same checks as when file names are read from the command
   --  line by Add_Source_To_Process. Otherwise only stores the file names in
   --  the temporary storage as Store_Sources_To_Process does. This procedure
   --  assumes that the file named by Par_File_Name contains argument file
   --  names separated by one or more white space (space character or HT), CR
   --  or LF.
   --
   --  This procedure sets the ASIS_UL.Options.No_Argument_File_Specified flag
   --  OFF.

   function Temp_Storage_Empty return Boolean;
   --  Checks if there are some files stored in the temporary storage

   function Arg_Source_File_Name return String;
   --  If the tool is called with all the argument sources specified in a
   --  single text file (using '-files=arg_files' option, returns the name of
   --  this file. Otherwise returns null string.
   --  If the tool is called from the GNAT driver, the result of this function
   --  corresponds to the call generated by the GNAT driver, but not to the
   --  call to the GNAT driver.

   Individual_Files_Specified : Boolean := False;
   --  Flag indicating if for the tool call there is at least one source file
   --  explicitely specified in the command line. Note that the tool has itself
   --  to take care of proper setting of this file.

   -------------------------------------------------------
   --  Recommended way of reading tool argument sources --
   -------------------------------------------------------

   --  If you would like to make sure that the search path specified by the
   --  tool '-I' options or by a project file (in case when the tool is called
   --  from the GNAT driver) is used when locating the arhument sources, use
   --  the following procedure:
   --
   --  - When processing tool parameters, use Store_Sources_To_Process instead
   --    of Add_Source_To_Process, and set Store_With_No_Check parameter ON
   --    when calling Read_Args_From_File;
   --
   --  - after reading all the tool arguments, use the following sequence of
   --    calls:
   --
   --      ASIS_UL.Compiler_Options.Process_ADA_PRJ_INCLUDE_FILE;
   --      ASIS_UL.Compiler_Options.Set_Source_Search_Path;
   --      ASIS_UL.Source_Table.Read_Args_From_Temp_Storage (...);'

   function Add_Needed_Source (Fname : String) return SF_Id;
   --  This function unconditionally stores the file with the name Fname in the
   --  source file table and returns the corresponding Id. Fname should be a
   --  full (???) name of existing file. This procedure is supposed to be
   --  called to store the name of the file that is not the argument of the
   --  tool, but that is detected as a file that is needed because of any
   --  reason for some argument file. For example, it may be a file containing
   --  a unit needed to be analyzed to build a full call graph. The caller is
   --  responsible for the fact that this source has not been already stored in
   --  the file table.

   procedure Add_Needed_Source (Fname : String);
   --  Same as the function Add_Needed_Source but does not return the result
   --  file ID.

   function Last_Source return SF_Id;
   --  Returns the Id of the last source stored in the source table. Returns
   --  No_SF_Id if there is no source file stored

   function Last_Argument_Source return SF_Id;
   --  Returns the Id of the last argument source stored in the source table.
   --  An argument source is the source set as the argument of the tool call.

   function Is_Argument_Source (SF : SF_Id) return Boolean;
   --  Checks if SF is from tool argument sources

   function Is_Needed_Source (SF : SF_Id) return Boolean;
   --  Checks if SF is a source that has been added as a needed source for some
   --  argument source

   function Already_Processed
     (Include_Needed_Sources : Boolean)
      return                   Natural;
   --  Returns the number of the currently processed sources (that is, sources
   --  having the status different from Waiting). If Include_Needed_Sources is
   --  set ON, all the sources are counted, otherwise - only argument sources

   procedure Reset_Source_Iterator;

   function Next_Non_Processed_Source
     (Only_Bodies            : Boolean := False;
      Include_Needed_Sources : Boolean := False)
      return                   SF_Id;
   --  These two routines provide the iterator through the sources stored in
   --  the sources table. Reset_Source_Iterator resets the iterator to the
   --  ID of the first source stored in the table. Next_Non_Processed_Source
   --  returns the Id if the next source file stored in the file table which
   --  has not been processed yet. If Only_Bodies parameter is set ON, only
   --  body files are considered. We are not 100% sure that this file indeed
   --  is an Ada body file, at this stage we consider any file which name has
   --  ".adb" suffix as a body file. No_SF_Id is returned if there is no such
   --  file in the file table. The idea behind is to process first all the body
   --  files and for each body to process as much specs as possible using this
   --  body tree file, to minimize a set of trees needed to be created to
   --  process all the sources.
   --  If Include_Needed_Sources parameter is set on, all the source files are
   --  considered, both argument files of the tool and the files added as a
   --  result of analyzing the global state of the program. Otherwise only
   --  argument sources are considered.

   procedure Init;
   --  Initializes the internal data structures for the source table

   procedure Create_Tree
     (SF               :     SF_Id;
      Success          : out Boolean;
      Compiler_Out     :     String  := "";
      All_Warnings_Off :     Boolean := True);
   --  Tries to create a tree file for SF. Sets Success ON if this attempt is
   --  successful. Otherwise sets Success OFF, generates the diagnostic
   --  information, sets the file status for SF to Not_A_Legal_Source and
   --  decreases the counter of the sources which have to be processed
   --  (Sources_Left)
   --  If Compiler_Out is a name of an existing file, this file is used
   --  to redirect the compiler output into. Otherwise the compiler output is
   --  sent to Stderr
   --  All_Warnings_Off ???

   procedure Output_Source (SF : SF_Id);
   --  Depending on the options set generates the trace of the units/sources
   --  processing. If Verbose_Mode is ON, outputs into Stderr the number of the
   --  units left and the name of the source being processed. Otherwise, if
   --  Quiet_Mode is OFF, outputs only the number of units left. If
   --  Progress_Indicator_Mode is ON, generates the output to be used for GPS
   --  progress indicator. (Unconditionally) decreases the counter of the
   --  sources which have to be processed (Sources_Left)

   procedure Source_Clean_Up
     (SF             : SF_Id;
      Keep_ALI_Files : Boolean := False);
   --  Minimal clean-up needed for one source (closing and dissociating the
   --  Context, removing the tree and ALI files created for this source in
   --  the temporary directory, if Keep_ALI_Files is set ON, ALI file(s) is
   --  (are) not deleted).

   procedure Set_Current_SF (SF : SF_Id);
   function Get_Current_SF return SF_Id;
   --  Set and retrieve the Id of the currently processed file to/from a global
   --  storage.

   ----------------------------------------
   -- Source file access/update routines --
   ----------------------------------------

   function Source_Name (SF : SF_Id) return String;
   --  If ASIS_UL.Common.Use_Project_File is set OFF, this function returns
   --  the full source file name in absolute normalized form, otherwise it
   --  result is the same as returned by Short_Source_Name for the same
   --  argument.

   function Short_Source_Name (SF : SF_Id) return String;
   --  Short file name with no directory information

   function Suffixless_Name (SF : SF_Id) return String;
   --  Returns the file name with no directory information and with
   --  no suffix (if any). Can be used to create the name of the tree and
   --  ALI file that correspond to SF.

   function CU_Name (SF : SF_Id) return String;
   procedure Set_CU_Name (SF : SF_Id; N : String);
   --  Returns (sets) the full expanded Ada name of the compilation unit that
   --  is contained in the source.
   --  ??? Should this function return Wide_String???

   function  Source_Status     (SF : SF_Id) return SF_Status;
   procedure Set_Source_Status (SF : SF_Id; S : SF_Status);
   --  Queries and updates the source status.

   function  Source_Info     (SF : SF_Id) return SF_Info;
   procedure Set_Source_Info (SF : SF_Id; Info : SF_Info);
   --  Queries and updates the source Info value. The use of this value is up
   --  to the client of the source file table. You can store some integer-coded
   --  information or you can use this value as an index value in some other
   --  structure.

   procedure Source_Table_Debug_Image;
   --  Prints into Stdout the debug image of the current state of source table
   --  if the corresponding debug flag is ON (or if ASIS_UL.Options.Debug_Mode
   --  is ON, but we have to get rid of this flag), otherwise does nothing.

   ----------------------
   -- Problem counters --
   ----------------------

   Illegal_Sources   : Natural := 0;
   Out_File_Problems : Natural := 0;

end ASIS_UL.Source_Table;
