| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT COMPILER COMPONENTS -- |
| -- -- |
| -- P R J . E N V -- |
| -- -- |
| -- B o d y -- |
| -- -- |
| -- $Revision$ |
| -- -- |
| -- Copyright (C) 2001 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- -- |
| -- 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. -- |
| -- -- |
| -- GNAT was originally developed by the GNAT team at New York University. -- |
| -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| with GNAT.OS_Lib; use GNAT.OS_Lib; |
| with Namet; use Namet; |
| with Opt; |
| with Osint; use Osint; |
| with Output; use Output; |
| with Prj.Com; use Prj.Com; |
| with Prj.Util; |
| with Snames; use Snames; |
| with Stringt; use Stringt; |
| with Table; |
| |
| package body Prj.Env is |
| |
| type Naming_Id is new Nat; |
| No_Naming : constant Naming_Id := 0; |
| |
| Ada_Path_Buffer : String_Access := new String (1 .. 1_000); |
| -- A buffer where values for ADA_INCLUDE_PATH |
| -- and ADA_OBJECTS_PATH are stored. |
| |
| Ada_Path_Length : Natural := 0; |
| -- Index of the last valid character in Ada_Path_Buffer. |
| |
| package Namings is new Table.Table ( |
| Table_Component_Type => Naming_Data, |
| Table_Index_Type => Naming_Id, |
| Table_Low_Bound => 1, |
| Table_Initial => 5, |
| Table_Increment => 100, |
| Table_Name => "Prj.Env.Namings"); |
| |
| Default_Naming : constant Naming_Id := Namings.First; |
| |
| Global_Configuration_Pragmas : Name_Id; |
| Local_Configuration_Pragmas : Name_Id; |
| |
| ----------------------- |
| -- Local Subprograms -- |
| ----------------------- |
| |
| function Body_Path_Name_Of (Unit : Unit_Id) return String; |
| -- Returns the path name of the body of a unit. |
| -- Compute it first, if necessary. |
| |
| function Spec_Path_Name_Of (Unit : Unit_Id) return String; |
| -- Returns the path name of the spec of a unit. |
| -- Compute it first, if necessary. |
| |
| procedure Add_To_Path (Path : String); |
| -- Add Path to global variable Ada_Path_Buffer |
| -- Increment Ada_Path_Length |
| |
| ---------------------- |
| -- Ada_Include_Path -- |
| ---------------------- |
| |
| function Ada_Include_Path (Project : Project_Id) return String_Access is |
| |
| procedure Add (Project : Project_Id); |
| -- Add all the source directories of a project to the path, |
| -- only if this project has not been visited. |
| -- Call itself recursively for projects being modified, |
| -- and imported projects. |
| -- Add the project to the list Seen if this is the first time |
| -- we call Add for this project. |
| |
| --------- |
| -- Add -- |
| --------- |
| |
| procedure Add (Project : Project_Id) is |
| begin |
| -- If Seen is empty, then the project cannot have been |
| -- visited. |
| |
| if not Projects.Table (Project).Seen then |
| Projects.Table (Project).Seen := True; |
| |
| declare |
| Data : Project_Data := Projects.Table (Project); |
| List : Project_List := Data.Imported_Projects; |
| |
| Current : String_List_Id := Data.Source_Dirs; |
| Source_Dir : String_Element; |
| |
| begin |
| -- Add to path all source directories of this project |
| |
| while Current /= Nil_String loop |
| if Ada_Path_Length > 0 then |
| Add_To_Path (Path => (1 => Path_Separator)); |
| end if; |
| |
| Source_Dir := String_Elements.Table (Current); |
| String_To_Name_Buffer (Source_Dir.Value); |
| |
| declare |
| New_Path : constant String := |
| Name_Buffer (1 .. Name_Len); |
| begin |
| Add_To_Path (New_Path); |
| end; |
| |
| Current := Source_Dir.Next; |
| end loop; |
| |
| -- Call Add to the project being modified, if any |
| |
| if Data.Modifies /= No_Project then |
| Add (Data.Modifies); |
| end if; |
| |
| -- Call Add for each imported project, if any |
| |
| while List /= Empty_Project_List loop |
| Add (Project_Lists.Table (List).Project); |
| List := Project_Lists.Table (List).Next; |
| end loop; |
| end; |
| end if; |
| |
| end Add; |
| |
| -- Start of processing for Ada_Include_Path |
| |
| begin |
| -- If it is the first time we call this function for |
| -- this project, compute the source path |
| |
| if Projects.Table (Project).Include_Path = null then |
| Ada_Path_Length := 0; |
| |
| for Index in 1 .. Projects.Last loop |
| Projects.Table (Index).Seen := False; |
| end loop; |
| |
| Add (Project); |
| Projects.Table (Project).Include_Path := |
| new String'(Ada_Path_Buffer (1 .. Ada_Path_Length)); |
| end if; |
| |
| return Projects.Table (Project).Include_Path; |
| end Ada_Include_Path; |
| |
| ---------------------- |
| -- Ada_Objects_Path -- |
| ---------------------- |
| |
| function Ada_Objects_Path |
| (Project : Project_Id; |
| Including_Libraries : Boolean := True) |
| return String_Access is |
| |
| procedure Add (Project : Project_Id); |
| -- Add all the object directory of a project to the path, |
| -- only if this project has not been visited. |
| -- Call itself recursively for projects being modified, |
| -- and imported projects. |
| -- Add the project to the list Seen if this is the first time |
| -- we call Add for this project. |
| |
| --------- |
| -- Add -- |
| --------- |
| |
| procedure Add (Project : Project_Id) is |
| begin |
| |
| -- If this project has not been seen yet |
| |
| if not Projects.Table (Project).Seen then |
| Projects.Table (Project).Seen := True; |
| |
| declare |
| Data : Project_Data := Projects.Table (Project); |
| List : Project_List := Data.Imported_Projects; |
| |
| begin |
| -- Add to path the object directory of this project |
| -- except if we don't include library project and |
| -- this is a library project. |
| |
| if (Data.Library and then Including_Libraries) |
| or else |
| (Data.Object_Directory /= No_Name |
| and then |
| (not Including_Libraries or else not Data.Library)) |
| then |
| if Ada_Path_Length > 0 then |
| Add_To_Path (Path => (1 => Path_Separator)); |
| end if; |
| |
| -- For a library project, att the library directory |
| |
| if Data.Library then |
| declare |
| New_Path : constant String := |
| Get_Name_String (Data.Library_Dir); |
| begin |
| Add_To_Path (New_Path); |
| end; |
| else |
| |
| -- For a non library project, add the object directory |
| declare |
| New_Path : constant String := |
| Get_Name_String (Data.Object_Directory); |
| begin |
| Add_To_Path (New_Path); |
| end; |
| end if; |
| end if; |
| |
| -- Call Add to the project being modified, if any |
| |
| if Data.Modifies /= No_Project then |
| Add (Data.Modifies); |
| end if; |
| |
| -- Call Add for each imported project, if any |
| |
| while List /= Empty_Project_List loop |
| Add (Project_Lists.Table (List).Project); |
| List := Project_Lists.Table (List).Next; |
| end loop; |
| end; |
| |
| end if; |
| end Add; |
| |
| -- Start of processing for Ada_Objects_Path |
| |
| begin |
| -- If it is the first time we call this function for |
| -- this project, compute the objects path |
| |
| if Projects.Table (Project).Objects_Path = null then |
| Ada_Path_Length := 0; |
| |
| for Index in 1 .. Projects.Last loop |
| Projects.Table (Index).Seen := False; |
| end loop; |
| |
| Add (Project); |
| Projects.Table (Project).Objects_Path := |
| new String'(Ada_Path_Buffer (1 .. Ada_Path_Length)); |
| end if; |
| |
| return Projects.Table (Project).Objects_Path; |
| end Ada_Objects_Path; |
| |
| ----------------- |
| -- Add_To_Path -- |
| ----------------- |
| |
| procedure Add_To_Path (Path : String) is |
| begin |
| -- If Ada_Path_Buffer is too small, double it |
| |
| if Ada_Path_Length + Path'Length > Ada_Path_Buffer'Last then |
| declare |
| New_Ada_Path_Buffer : constant String_Access := |
| new String |
| (1 .. Ada_Path_Buffer'Last + |
| Ada_Path_Buffer'Last); |
| |
| begin |
| New_Ada_Path_Buffer (1 .. Ada_Path_Length) := |
| Ada_Path_Buffer (1 .. Ada_Path_Length); |
| Ada_Path_Buffer := New_Ada_Path_Buffer; |
| end; |
| end if; |
| |
| Ada_Path_Buffer |
| (Ada_Path_Length + 1 .. Ada_Path_Length + Path'Length) := Path; |
| Ada_Path_Length := Ada_Path_Length + Path'Length; |
| end Add_To_Path; |
| |
| ----------------------- |
| -- Body_Path_Name_Of -- |
| ----------------------- |
| |
| function Body_Path_Name_Of (Unit : Unit_Id) return String is |
| Data : Unit_Data := Units.Table (Unit); |
| |
| begin |
| -- If we don't know the path name of the body of this unit, |
| -- we compute it, and we store it. |
| |
| if Data.File_Names (Body_Part).Path = No_Name then |
| declare |
| Current_Source : String_List_Id := |
| Projects.Table (Data.File_Names (Body_Part).Project).Sources; |
| Path : GNAT.OS_Lib.String_Access; |
| |
| begin |
| -- By default, put the file name |
| |
| Data.File_Names (Body_Part).Path := |
| Data.File_Names (Body_Part).Name; |
| |
| -- For each source directory |
| |
| while Current_Source /= Nil_String loop |
| String_To_Name_Buffer |
| (String_Elements.Table (Current_Source).Value); |
| Path := |
| Locate_Regular_File |
| (Namet.Get_Name_String |
| (Data.File_Names (Body_Part).Name), |
| Name_Buffer (1 .. Name_Len)); |
| |
| -- If the file is in this directory, |
| -- then we store the path, and we are done. |
| |
| if Path /= null then |
| Name_Len := Path'Length; |
| Name_Buffer (1 .. Name_Len) := Path.all; |
| Data.File_Names (Body_Part).Path := Name_Enter; |
| exit; |
| |
| else |
| Current_Source := |
| String_Elements.Table (Current_Source).Next; |
| end if; |
| end loop; |
| |
| Units.Table (Unit) := Data; |
| end; |
| end if; |
| |
| -- Returned the value stored |
| |
| return Namet.Get_Name_String (Data.File_Names (Body_Part).Path); |
| end Body_Path_Name_Of; |
| |
| -------------------------------- |
| -- Create_Config_Pragmas_File -- |
| -------------------------------- |
| |
| procedure Create_Config_Pragmas_File |
| (For_Project : Project_Id; |
| Main_Project : Project_Id) |
| is |
| File_Name : Temp_File_Name; |
| File : File_Descriptor := Invalid_FD; |
| |
| The_Packages : Package_Id; |
| Gnatmake : Prj.Package_Id; |
| Compiler : Prj.Package_Id; |
| |
| Current_Unit : Unit_Id := Units.First; |
| |
| First_Project : Project_List := Empty_Project_List; |
| |
| Current_Project : Project_List; |
| Current_Naming : Naming_Id; |
| |
| Global_Attribute : Variable_Value := Nil_Variable_Value; |
| Local_Attribute : Variable_Value := Nil_Variable_Value; |
| |
| Global_Attribute_Present : Boolean := False; |
| Local_Attribute_Present : Boolean := False; |
| |
| procedure Check (Project : Project_Id); |
| |
| procedure Check_Temp_File; |
| -- Check that a temporary file has been opened. |
| -- If not, create one, and put its name in the project data, |
| -- with the indication that it is a temporary file. |
| |
| procedure Copy_File (Name : String_Id); |
| -- Copy a configuration pragmas file into the temp file. |
| |
| procedure Put |
| (Unit_Name : Name_Id; |
| File_Name : Name_Id; |
| Unit_Kind : Spec_Or_Body); |
| -- Put an SFN pragma in the temporary file. |
| |
| procedure Put (File : File_Descriptor; S : String); |
| |
| procedure Put_Line (File : File_Descriptor; S : String); |
| |
| ----------- |
| -- Check -- |
| ----------- |
| |
| procedure Check (Project : Project_Id) is |
| Data : constant Project_Data := Projects.Table (Project); |
| |
| begin |
| if Current_Verbosity = High then |
| Write_Str ("Checking project file """); |
| Write_Str (Namet.Get_Name_String (Data.Name)); |
| Write_Str ("""."); |
| Write_Eol; |
| end if; |
| |
| -- Is this project in the list of the visited project? |
| |
| Current_Project := First_Project; |
| while Current_Project /= Empty_Project_List |
| and then Project_Lists.Table (Current_Project).Project /= Project |
| loop |
| Current_Project := Project_Lists.Table (Current_Project).Next; |
| end loop; |
| |
| -- If it is not, put it in the list, and visit it |
| |
| if Current_Project = Empty_Project_List then |
| Project_Lists.Increment_Last; |
| Project_Lists.Table (Project_Lists.Last) := |
| (Project => Project, Next => First_Project); |
| First_Project := Project_Lists.Last; |
| |
| -- Is the naming scheme of this project one that we know? |
| |
| Current_Naming := Default_Naming; |
| while Current_Naming <= Namings.Last and then |
| not Same_Naming_Scheme |
| (Left => Namings.Table (Current_Naming), |
| Right => Data.Naming) loop |
| Current_Naming := Current_Naming + 1; |
| end loop; |
| |
| -- If we don't know it, add it |
| |
| if Current_Naming > Namings.Last then |
| Namings.Increment_Last; |
| Namings.Table (Namings.Last) := Data.Naming; |
| |
| -- We need a temporary file to be created |
| |
| Check_Temp_File; |
| |
| -- Put the SFN pragmas for the naming scheme |
| |
| -- Spec |
| |
| Put_Line |
| (File, "pragma Source_File_Name"); |
| Put_Line |
| (File, " (Spec_File_Name => ""*" & |
| Namet.Get_Name_String (Data.Naming.Current_Spec_Suffix) & |
| ""","); |
| Put_Line |
| (File, " Casing => " & |
| Image (Data.Naming.Casing) & ","); |
| Put_Line |
| (File, " Dot_Replacement => """ & |
| Namet.Get_Name_String (Data.Naming.Dot_Replacement) & |
| """);"); |
| |
| -- and body |
| |
| Put_Line |
| (File, "pragma Source_File_Name"); |
| Put_Line |
| (File, " (Body_File_Name => ""*" & |
| Namet.Get_Name_String (Data.Naming.Current_Impl_Suffix) & |
| ""","); |
| Put_Line |
| (File, " Casing => " & |
| Image (Data.Naming.Casing) & ","); |
| Put_Line |
| (File, " Dot_Replacement => """ & |
| Namet.Get_Name_String (Data.Naming.Dot_Replacement) & |
| """);"); |
| |
| -- and maybe separate |
| |
| if |
| Data.Naming.Current_Impl_Suffix /= Data.Naming.Separate_Suffix |
| then |
| Put_Line |
| (File, "pragma Source_File_Name"); |
| Put_Line |
| (File, " (Subunit_File_Name => ""*" & |
| Namet.Get_Name_String (Data.Naming.Separate_Suffix) & |
| ""","); |
| Put_Line |
| (File, " Casing => " & |
| Image (Data.Naming.Casing) & |
| ","); |
| Put_Line |
| (File, " Dot_Replacement => """ & |
| Namet.Get_Name_String (Data.Naming.Dot_Replacement) & |
| """);"); |
| end if; |
| end if; |
| |
| if Data.Modifies /= No_Project then |
| Check (Data.Modifies); |
| end if; |
| |
| declare |
| Current : Project_List := Data.Imported_Projects; |
| |
| begin |
| while Current /= Empty_Project_List loop |
| Check (Project_Lists.Table (Current).Project); |
| Current := Project_Lists.Table (Current).Next; |
| end loop; |
| end; |
| end if; |
| end Check; |
| |
| --------------------- |
| -- Check_Temp_File -- |
| --------------------- |
| |
| procedure Check_Temp_File is |
| begin |
| if File = Invalid_FD then |
| GNAT.OS_Lib.Create_Temp_File (File, Name => File_Name); |
| if File = Invalid_FD then |
| Osint.Fail |
| ("unable to create temporary configuration pragmas file"); |
| elsif Opt.Verbose_Mode then |
| Write_Str ("Creating temp file """); |
| Write_Str (File_Name); |
| Write_Line (""""); |
| end if; |
| end if; |
| end Check_Temp_File; |
| |
| --------------- |
| -- Copy_File -- |
| --------------- |
| |
| procedure Copy_File (Name : in String_Id) is |
| Input : File_Descriptor; |
| Buffer : String (1 .. 1_000); |
| Input_Length : Integer; |
| Output_Length : Integer; |
| |
| begin |
| Check_Temp_File; |
| String_To_Name_Buffer (Name); |
| |
| if Opt.Verbose_Mode then |
| Write_Str ("Copying config pragmas file """); |
| Write_Str (Name_Buffer (1 .. Name_Len)); |
| Write_Line (""" into temp file"); |
| end if; |
| |
| declare |
| Name : constant String := |
| Name_Buffer (1 .. Name_Len) & ASCII.NUL; |
| begin |
| Input := Open_Read (Name'Address, Binary); |
| end; |
| |
| if Input = Invalid_FD then |
| Osint.Fail |
| ("cannot open configuration pragmas file " & |
| Name_Buffer (1 .. Name_Len)); |
| end if; |
| |
| loop |
| Input_Length := Read (Input, Buffer'Address, Buffer'Length); |
| Output_Length := Write (File, Buffer'Address, Input_Length); |
| |
| if Output_Length /= Input_Length then |
| Osint.Fail ("disk full"); |
| end if; |
| |
| exit when Input_Length < Buffer'Length; |
| end loop; |
| |
| Close (Input); |
| |
| end Copy_File; |
| |
| --------- |
| -- Put -- |
| --------- |
| |
| procedure Put |
| (Unit_Name : Name_Id; |
| File_Name : Name_Id; |
| Unit_Kind : Spec_Or_Body) |
| is |
| begin |
| -- A temporary file needs to be open |
| |
| Check_Temp_File; |
| |
| -- Put the pragma SFN for the unit kind (spec or body) |
| |
| Put (File, "pragma Source_File_Name ("); |
| Put (File, Namet.Get_Name_String (Unit_Name)); |
| |
| if Unit_Kind = Specification then |
| Put (File, ", Spec_File_Name => """); |
| else |
| Put (File, ", Body_File_Name => """); |
| end if; |
| |
| Put (File, Namet.Get_Name_String (File_Name)); |
| Put_Line (File, """);"); |
| end Put; |
| |
| procedure Put (File : File_Descriptor; S : String) is |
| Last : Natural; |
| |
| begin |
| Last := Write (File, S (S'First)'Address, S'Length); |
| |
| if Last /= S'Length then |
| Osint.Fail ("Disk full"); |
| end if; |
| |
| if Current_Verbosity = High then |
| Write_Str (S); |
| end if; |
| end Put; |
| |
| -------------- |
| -- Put_Line -- |
| -------------- |
| |
| procedure Put_Line (File : File_Descriptor; S : String) is |
| S0 : String (1 .. S'Length + 1); |
| Last : Natural; |
| |
| begin |
| -- Add an ASCII.LF to the string. As this gnat.adc |
| -- is supposed to be used only by the compiler, we don't |
| -- care about the characters for the end of line. |
| -- The truth is we could have put a space, but it is |
| -- more convenient to be able to read gnat.adc during |
| -- development. And the development was done under UNIX. |
| -- Hence the ASCII.LF. |
| |
| S0 (1 .. S'Length) := S; |
| S0 (S0'Last) := ASCII.LF; |
| Last := Write (File, S0'Address, S0'Length); |
| |
| if Last /= S'Length + 1 then |
| Osint.Fail ("Disk full"); |
| end if; |
| |
| if Current_Verbosity = High then |
| Write_Line (S); |
| end if; |
| end Put_Line; |
| |
| -- Start of processing for Create_Config_Pragmas_File |
| |
| begin |
| |
| if not Projects.Table (For_Project).Config_Checked then |
| |
| -- Remove any memory of processed naming schemes, if any |
| |
| Namings.Set_Last (Default_Naming); |
| |
| -- Check the naming schemes |
| |
| Check (For_Project); |
| |
| -- Visit all the units and process those that need an SFN pragma |
| |
| while Current_Unit <= Units.Last loop |
| declare |
| Unit : constant Unit_Data := |
| Units.Table (Current_Unit); |
| |
| begin |
| if Unit.File_Names (Specification).Needs_Pragma then |
| Put (Unit.Name, |
| Unit.File_Names (Specification).Name, |
| Specification); |
| end if; |
| |
| if Unit.File_Names (Body_Part).Needs_Pragma then |
| Put (Unit.Name, |
| Unit.File_Names (Body_Part).Name, |
| Body_Part); |
| end if; |
| |
| Current_Unit := Current_Unit + 1; |
| end; |
| end loop; |
| |
| The_Packages := Projects.Table (Main_Project).Decl.Packages; |
| Gnatmake := |
| Prj.Util.Value_Of |
| (Name => Name_Builder, |
| In_Packages => The_Packages); |
| |
| if Gnatmake /= No_Package then |
| Global_Attribute := Prj.Util.Value_Of |
| (Variable_Name => Global_Configuration_Pragmas, |
| In_Variables => Packages.Table (Gnatmake).Decl.Attributes); |
| Global_Attribute_Present := |
| Global_Attribute /= Nil_Variable_Value |
| and then String_Length (Global_Attribute.Value) > 0; |
| end if; |
| |
| The_Packages := Projects.Table (For_Project).Decl.Packages; |
| Compiler := |
| Prj.Util.Value_Of |
| (Name => Name_Compiler, |
| In_Packages => The_Packages); |
| |
| if Compiler /= No_Package then |
| Local_Attribute := Prj.Util.Value_Of |
| (Variable_Name => Local_Configuration_Pragmas, |
| In_Variables => Packages.Table (Compiler).Decl.Attributes); |
| Local_Attribute_Present := |
| Local_Attribute /= Nil_Variable_Value |
| and then String_Length (Local_Attribute.Value) > 0; |
| end if; |
| |
| if Global_Attribute_Present then |
| |
| if File /= Invalid_FD |
| or else Local_Attribute_Present |
| then |
| Copy_File (Global_Attribute.Value); |
| else |
| String_To_Name_Buffer (Global_Attribute.Value); |
| Projects.Table (For_Project).Config_File_Name := Name_Find; |
| end if; |
| end if; |
| |
| if Local_Attribute_Present then |
| |
| if File /= Invalid_FD then |
| Copy_File (Local_Attribute.Value); |
| |
| else |
| String_To_Name_Buffer (Local_Attribute.Value); |
| Projects.Table (For_Project).Config_File_Name := Name_Find; |
| end if; |
| |
| end if; |
| |
| if File /= Invalid_FD then |
| GNAT.OS_Lib.Close (File); |
| |
| if Opt.Verbose_Mode then |
| Write_Str ("Closing configuration file """); |
| Write_Str (File_Name); |
| Write_Line (""""); |
| end if; |
| |
| Name_Len := File_Name'Length; |
| Name_Buffer (1 .. Name_Len) := File_Name; |
| Projects.Table (For_Project).Config_File_Name := Name_Find; |
| Projects.Table (For_Project).Config_File_Temp := True; |
| end if; |
| |
| Projects.Table (For_Project).Config_Checked := True; |
| |
| end if; |
| |
| end Create_Config_Pragmas_File; |
| |
| ------------------------- |
| -- Create_Mapping_File -- |
| ------------------------- |
| |
| procedure Create_Mapping_File (Name : in out Temp_File_Name) is |
| File : File_Descriptor := Invalid_FD; |
| The_Unit_Data : Unit_Data; |
| Data : File_Name_Data; |
| |
| procedure Put (S : String); |
| -- Put a line in the mapping file |
| |
| procedure Put_Data (Spec : Boolean); |
| -- Put the mapping of the spec or body contained in Data in the file |
| -- (3 lines). |
| |
| procedure Put (S : String) is |
| Last : Natural; |
| |
| begin |
| Last := Write (File, S'Address, S'Length); |
| |
| if Last /= S'Length then |
| Osint.Fail ("Disk full"); |
| end if; |
| |
| end Put; |
| |
| procedure Put_Data (Spec : Boolean) is |
| begin |
| Put (Get_Name_String (The_Unit_Data.Name)); |
| |
| if Spec then |
| Put ("%s"); |
| else |
| Put ("%b"); |
| end if; |
| |
| Put (S => (1 => ASCII.LF)); |
| Put (Get_Name_String (Data.Name)); |
| Put (S => (1 => ASCII.LF)); |
| Put (Get_Name_String (Data.Path)); |
| Put (S => (1 => ASCII.LF)); |
| end Put_Data; |
| |
| begin |
| GNAT.OS_Lib.Create_Temp_File (File, Name => Name); |
| |
| if File = Invalid_FD then |
| Osint.Fail |
| ("unable to create temporary mapping file"); |
| |
| elsif Opt.Verbose_Mode then |
| Write_Str ("Creating temp mapping file """); |
| Write_Str (Name); |
| Write_Line (""""); |
| end if; |
| |
| -- For all units in table Units |
| |
| for Unit in 1 .. Units.Last loop |
| The_Unit_Data := Units.Table (Unit); |
| |
| -- If the unit has a valid name |
| |
| if The_Unit_Data.Name /= No_Name then |
| Data := The_Unit_Data.File_Names (Specification); |
| |
| -- If there is a spec, put it mapping in the file |
| |
| if Data.Name /= No_Name then |
| Put_Data (Spec => True); |
| end if; |
| |
| Data := The_Unit_Data.File_Names (Body_Part); |
| |
| -- If there is a body (or subunit) put its mapping in the file |
| |
| if Data.Name /= No_Name then |
| Put_Data (Spec => False); |
| end if; |
| |
| end if; |
| end loop; |
| |
| GNAT.OS_Lib.Close (File); |
| |
| end Create_Mapping_File; |
| |
| ------------------------------------ |
| -- File_Name_Of_Library_Unit_Body -- |
| ------------------------------------ |
| |
| function File_Name_Of_Library_Unit_Body |
| (Name : String; |
| Project : Project_Id) |
| return String |
| is |
| Data : constant Project_Data := Projects.Table (Project); |
| Original_Name : String := Name; |
| |
| Extended_Spec_Name : String := |
| Name & Namet.Get_Name_String |
| (Data.Naming.Current_Spec_Suffix); |
| Extended_Body_Name : String := |
| Name & Namet.Get_Name_String |
| (Data.Naming.Current_Impl_Suffix); |
| |
| Unit : Unit_Data; |
| |
| The_Original_Name : Name_Id; |
| The_Spec_Name : Name_Id; |
| The_Body_Name : Name_Id; |
| |
| begin |
| Canonical_Case_File_Name (Original_Name); |
| Name_Len := Original_Name'Length; |
| Name_Buffer (1 .. Name_Len) := Original_Name; |
| The_Original_Name := Name_Find; |
| |
| Canonical_Case_File_Name (Extended_Spec_Name); |
| Name_Len := Extended_Spec_Name'Length; |
| Name_Buffer (1 .. Name_Len) := Extended_Spec_Name; |
| The_Spec_Name := Name_Find; |
| |
| Canonical_Case_File_Name (Extended_Body_Name); |
| Name_Len := Extended_Body_Name'Length; |
| Name_Buffer (1 .. Name_Len) := Extended_Body_Name; |
| The_Body_Name := Name_Find; |
| |
| if Current_Verbosity = High then |
| Write_Str ("Looking for file name of """); |
| Write_Str (Name); |
| Write_Char ('"'); |
| Write_Eol; |
| Write_Str (" Extended Spec Name = """); |
| Write_Str (Extended_Spec_Name); |
| Write_Char ('"'); |
| Write_Eol; |
| Write_Str (" Extended Body Name = """); |
| Write_Str (Extended_Body_Name); |
| Write_Char ('"'); |
| Write_Eol; |
| end if; |
| |
| -- For every unit |
| |
| for Current in reverse Units.First .. Units.Last loop |
| Unit := Units.Table (Current); |
| |
| -- If it is a unit of the same project |
| |
| if Unit.File_Names (Body_Part).Project = Project then |
| declare |
| Current_Name : constant Name_Id := |
| Unit.File_Names (Body_Part).Name; |
| |
| begin |
| -- If there is a body |
| |
| if Current_Name /= No_Name then |
| if Current_Verbosity = High then |
| Write_Str (" Comparing with """); |
| Write_Str (Get_Name_String (Current_Name)); |
| Write_Char ('"'); |
| Write_Eol; |
| end if; |
| |
| -- If it has the name of the original name, |
| -- return the original name |
| |
| if Unit.Name = The_Original_Name |
| or else Current_Name = The_Original_Name |
| then |
| if Current_Verbosity = High then |
| Write_Line (" OK"); |
| end if; |
| |
| return Get_Name_String (Current_Name); |
| |
| -- If it has the name of the extended body name, |
| -- return the extended body name |
| |
| elsif Current_Name = The_Body_Name then |
| if Current_Verbosity = High then |
| Write_Line (" OK"); |
| end if; |
| |
| return Extended_Body_Name; |
| |
| else |
| if Current_Verbosity = High then |
| Write_Line (" not good"); |
| end if; |
| end if; |
| end if; |
| end; |
| end if; |
| |
| -- If it is a unit of the same project |
| |
| if Units.Table (Current).File_Names (Specification).Project = |
| Project |
| then |
| declare |
| Current_Name : constant Name_Id := |
| Unit.File_Names (Specification).Name; |
| |
| begin |
| -- If there is a spec |
| |
| if Current_Name /= No_Name then |
| if Current_Verbosity = High then |
| Write_Str (" Comparing with """); |
| Write_Str (Get_Name_String (Current_Name)); |
| Write_Char ('"'); |
| Write_Eol; |
| end if; |
| |
| -- If it has the same name as the original name, |
| -- return the original name |
| |
| if Unit.Name = The_Original_Name |
| or else Current_Name = The_Original_Name |
| then |
| if Current_Verbosity = High then |
| Write_Line (" OK"); |
| end if; |
| |
| return Get_Name_String (Current_Name); |
| |
| -- If it has the same name as the extended spec name, |
| -- return the extended spec name |
| |
| elsif Current_Name = The_Spec_Name then |
| if Current_Verbosity = High then |
| Write_Line (" OK"); |
| end if; |
| |
| return Extended_Spec_Name; |
| |
| else |
| if Current_Verbosity = High then |
| Write_Line (" not good"); |
| end if; |
| end if; |
| end if; |
| end; |
| end if; |
| |
| end loop; |
| |
| -- We don't know this file name, return an empty string |
| |
| return ""; |
| end File_Name_Of_Library_Unit_Body; |
| |
| ------------------------- |
| -- For_All_Object_Dirs -- |
| ------------------------- |
| |
| procedure For_All_Object_Dirs (Project : Project_Id) is |
| Seen : Project_List := Empty_Project_List; |
| |
| procedure Add (Project : Project_Id); |
| -- Process a project. Remember the processes visited to avoid |
| -- processing a project twice. Recursively process an eventual |
| -- modified project, and all imported projects. |
| |
| --------- |
| -- Add -- |
| --------- |
| |
| procedure Add (Project : Project_Id) is |
| Data : constant Project_Data := Projects.Table (Project); |
| List : Project_List := Data.Imported_Projects; |
| |
| begin |
| -- If the list of visited project is empty, then |
| -- for sure we never visited this project. |
| |
| if Seen = Empty_Project_List then |
| Project_Lists.Increment_Last; |
| Seen := Project_Lists.Last; |
| Project_Lists.Table (Seen) := |
| (Project => Project, Next => Empty_Project_List); |
| |
| else |
| -- Check if the project is in the list |
| |
| declare |
| Current : Project_List := Seen; |
| |
| begin |
| loop |
| -- If it is, then there is nothing else to do |
| |
| if Project_Lists.Table (Current).Project = Project then |
| return; |
| end if; |
| |
| exit when Project_Lists.Table (Current).Next = |
| Empty_Project_List; |
| Current := Project_Lists.Table (Current).Next; |
| end loop; |
| |
| -- This project has never been visited, add it |
| -- to the list. |
| |
| Project_Lists.Increment_Last; |
| Project_Lists.Table (Current).Next := Project_Lists.Last; |
| Project_Lists.Table (Project_Lists.Last) := |
| (Project => Project, Next => Empty_Project_List); |
| end; |
| end if; |
| |
| -- If there is an object directory, call Action |
| -- with its name |
| |
| if Data.Object_Directory /= No_Name then |
| Get_Name_String (Data.Object_Directory); |
| Action (Name_Buffer (1 .. Name_Len)); |
| end if; |
| |
| -- If we are extending a project, visit it |
| |
| if Data.Modifies /= No_Project then |
| Add (Data.Modifies); |
| end if; |
| |
| -- And visit all imported projects |
| |
| while List /= Empty_Project_List loop |
| Add (Project_Lists.Table (List).Project); |
| List := Project_Lists.Table (List).Next; |
| end loop; |
| end Add; |
| |
| -- Start of processing for For_All_Object_Dirs |
| |
| begin |
| -- Visit this project, and its imported projects, |
| -- recursively |
| |
| Add (Project); |
| end For_All_Object_Dirs; |
| |
| ------------------------- |
| -- For_All_Source_Dirs -- |
| ------------------------- |
| |
| procedure For_All_Source_Dirs (Project : Project_Id) is |
| Seen : Project_List := Empty_Project_List; |
| |
| procedure Add (Project : Project_Id); |
| -- Process a project. Remember the processes visited to avoid |
| -- processing a project twice. Recursively process an eventual |
| -- modified project, and all imported projects. |
| |
| --------- |
| -- Add -- |
| --------- |
| |
| procedure Add (Project : Project_Id) is |
| Data : constant Project_Data := Projects.Table (Project); |
| List : Project_List := Data.Imported_Projects; |
| |
| begin |
| -- If the list of visited project is empty, then |
| -- for sure we never visited this project. |
| |
| if Seen = Empty_Project_List then |
| Project_Lists.Increment_Last; |
| Seen := Project_Lists.Last; |
| Project_Lists.Table (Seen) := |
| (Project => Project, Next => Empty_Project_List); |
| |
| else |
| -- Check if the project is in the list |
| |
| declare |
| Current : Project_List := Seen; |
| |
| begin |
| loop |
| -- If it is, then there is nothing else to do |
| |
| if Project_Lists.Table (Current).Project = Project then |
| return; |
| end if; |
| |
| exit when Project_Lists.Table (Current).Next = |
| Empty_Project_List; |
| Current := Project_Lists.Table (Current).Next; |
| end loop; |
| |
| -- This project has never been visited, add it |
| -- to the list. |
| |
| Project_Lists.Increment_Last; |
| Project_Lists.Table (Current).Next := Project_Lists.Last; |
| Project_Lists.Table (Project_Lists.Last) := |
| (Project => Project, Next => Empty_Project_List); |
| end; |
| end if; |
| |
| declare |
| Current : String_List_Id := Data.Source_Dirs; |
| The_String : String_Element; |
| |
| begin |
| -- Call action with the name of every source directorie |
| |
| while Current /= Nil_String loop |
| The_String := String_Elements.Table (Current); |
| String_To_Name_Buffer (The_String.Value); |
| Action (Name_Buffer (1 .. Name_Len)); |
| Current := The_String.Next; |
| end loop; |
| end; |
| |
| -- If we are extending a project, visit it |
| |
| if Data.Modifies /= No_Project then |
| Add (Data.Modifies); |
| end if; |
| |
| -- And visit all imported projects |
| |
| while List /= Empty_Project_List loop |
| Add (Project_Lists.Table (List).Project); |
| List := Project_Lists.Table (List).Next; |
| end loop; |
| end Add; |
| |
| -- Start of processing for For_All_Source_Dirs |
| |
| begin |
| -- Visit this project, and its imported projects recursively |
| |
| Add (Project); |
| end For_All_Source_Dirs; |
| |
| ------------------- |
| -- Get_Reference -- |
| ------------------- |
| |
| procedure Get_Reference |
| (Source_File_Name : String; |
| Project : out Project_Id; |
| Path : out Name_Id) |
| is |
| begin |
| if Current_Verbosity > Default then |
| Write_Str ("Getting Reference_Of ("""); |
| Write_Str (Source_File_Name); |
| Write_Str (""") ... "); |
| end if; |
| |
| declare |
| Original_Name : String := Source_File_Name; |
| Unit : Unit_Data; |
| |
| begin |
| Canonical_Case_File_Name (Original_Name); |
| |
| for Id in Units.First .. Units.Last loop |
| Unit := Units.Table (Id); |
| |
| if (Unit.File_Names (Specification).Name /= No_Name |
| and then |
| Namet.Get_Name_String |
| (Unit.File_Names (Specification).Name) = Original_Name) |
| or else (Unit.File_Names (Specification).Path /= No_Name |
| and then |
| Namet.Get_Name_String |
| (Unit.File_Names (Specification).Path) = |
| Original_Name) |
| then |
| Project := Unit.File_Names (Specification).Project; |
| Path := Unit.File_Names (Specification).Path; |
| |
| if Current_Verbosity > Default then |
| Write_Str ("Done: Specification."); |
| Write_Eol; |
| end if; |
| |
| return; |
| |
| elsif (Unit.File_Names (Body_Part).Name /= No_Name |
| and then |
| Namet.Get_Name_String |
| (Unit.File_Names (Body_Part).Name) = Original_Name) |
| or else (Unit.File_Names (Body_Part).Path /= No_Name |
| and then Namet.Get_Name_String |
| (Unit.File_Names (Body_Part).Path) = |
| Original_Name) |
| then |
| Project := Unit.File_Names (Body_Part).Project; |
| Path := Unit.File_Names (Body_Part).Path; |
| |
| if Current_Verbosity > Default then |
| Write_Str ("Done: Body."); |
| Write_Eol; |
| end if; |
| |
| return; |
| end if; |
| |
| end loop; |
| end; |
| |
| Project := No_Project; |
| Path := No_Name; |
| |
| if Current_Verbosity > Default then |
| Write_Str ("Cannot be found."); |
| Write_Eol; |
| end if; |
| end Get_Reference; |
| |
| ---------------- |
| -- Initialize -- |
| ---------------- |
| |
| procedure Initialize is |
| Global : constant String := "global_configuration_pragmas"; |
| Local : constant String := "local_configuration_pragmas"; |
| begin |
| -- Put the standard GNAT naming scheme in the Namings table |
| |
| Namings.Increment_Last; |
| Namings.Table (Namings.Last) := Standard_Naming_Data; |
| Name_Len := Global'Length; |
| Name_Buffer (1 .. Name_Len) := Global; |
| Global_Configuration_Pragmas := Name_Find; |
| Name_Len := Local'Length; |
| Name_Buffer (1 .. Name_Len) := Local; |
| Local_Configuration_Pragmas := Name_Find; |
| end Initialize; |
| |
| ------------------------------------ |
| -- Path_Name_Of_Library_Unit_Body -- |
| ------------------------------------ |
| |
| function Path_Name_Of_Library_Unit_Body |
| (Name : String; |
| Project : Project_Id) |
| return String |
| is |
| Data : constant Project_Data := Projects.Table (Project); |
| Original_Name : String := Name; |
| |
| Extended_Spec_Name : String := |
| Name & Namet.Get_Name_String |
| (Data.Naming.Current_Spec_Suffix); |
| Extended_Body_Name : String := |
| Name & Namet.Get_Name_String |
| (Data.Naming.Current_Impl_Suffix); |
| |
| First : Unit_Id := Units.First; |
| Current : Unit_Id; |
| Unit : Unit_Data; |
| |
| begin |
| Canonical_Case_File_Name (Original_Name); |
| Canonical_Case_File_Name (Extended_Spec_Name); |
| Canonical_Case_File_Name (Extended_Spec_Name); |
| |
| if Current_Verbosity = High then |
| Write_Str ("Looking for path name of """); |
| Write_Str (Name); |
| Write_Char ('"'); |
| Write_Eol; |
| Write_Str (" Extended Spec Name = """); |
| Write_Str (Extended_Spec_Name); |
| Write_Char ('"'); |
| Write_Eol; |
| Write_Str (" Extended Body Name = """); |
| Write_Str (Extended_Body_Name); |
| Write_Char ('"'); |
| Write_Eol; |
| end if; |
| |
| while First <= Units.Last |
| and then Units.Table (First).File_Names (Body_Part).Project /= Project |
| loop |
| First := First + 1; |
| end loop; |
| |
| Current := First; |
| while Current <= Units.Last loop |
| Unit := Units.Table (Current); |
| |
| if Unit.File_Names (Body_Part).Project = Project |
| and then Unit.File_Names (Body_Part).Name /= No_Name |
| then |
| declare |
| Current_Name : constant String := |
| Namet.Get_Name_String (Unit.File_Names (Body_Part).Name); |
| begin |
| if Current_Verbosity = High then |
| Write_Str (" Comparing with """); |
| Write_Str (Current_Name); |
| Write_Char ('"'); |
| Write_Eol; |
| end if; |
| |
| if Current_Name = Original_Name then |
| if Current_Verbosity = High then |
| Write_Line (" OK"); |
| end if; |
| |
| return Body_Path_Name_Of (Current); |
| |
| elsif Current_Name = Extended_Body_Name then |
| if Current_Verbosity = High then |
| Write_Line (" OK"); |
| end if; |
| |
| return Body_Path_Name_Of (Current); |
| |
| else |
| if Current_Verbosity = High then |
| Write_Line (" not good"); |
| end if; |
| end if; |
| end; |
| |
| elsif Unit.File_Names (Specification).Name /= No_Name then |
| declare |
| Current_Name : constant String := |
| Namet.Get_Name_String |
| (Unit.File_Names (Specification).Name); |
| |
| begin |
| if Current_Verbosity = High then |
| Write_Str (" Comparing with """); |
| Write_Str (Current_Name); |
| Write_Char ('"'); |
| Write_Eol; |
| end if; |
| |
| if Current_Name = Original_Name then |
| if Current_Verbosity = High then |
| Write_Line (" OK"); |
| end if; |
| |
| return Spec_Path_Name_Of (Current); |
| |
| elsif Current_Name = Extended_Spec_Name then |
| |
| if Current_Verbosity = High then |
| Write_Line (" OK"); |
| end if; |
| |
| return Spec_Path_Name_Of (Current); |
| |
| else |
| if Current_Verbosity = High then |
| Write_Line (" not good"); |
| end if; |
| end if; |
| end; |
| end if; |
| Current := Current + 1; |
| end loop; |
| |
| return ""; |
| end Path_Name_Of_Library_Unit_Body; |
| |
| ------------------- |
| -- Print_Sources -- |
| ------------------- |
| |
| procedure Print_Sources is |
| Unit : Unit_Data; |
| |
| begin |
| Write_Line ("List of Sources:"); |
| |
| for Id in Units.First .. Units.Last loop |
| Unit := Units.Table (Id); |
| Write_Str (" "); |
| Write_Line (Namet.Get_Name_String (Unit.Name)); |
| |
| if Unit.File_Names (Specification).Name /= No_Name then |
| if Unit.File_Names (Specification).Project = No_Project then |
| Write_Line (" No project"); |
| |
| else |
| Write_Str (" Project: "); |
| Get_Name_String |
| (Projects.Table |
| (Unit.File_Names (Specification).Project).Path_Name); |
| Write_Line (Name_Buffer (1 .. Name_Len)); |
| end if; |
| |
| Write_Str (" spec: "); |
| Write_Line |
| (Namet.Get_Name_String |
| (Unit.File_Names (Specification).Name)); |
| end if; |
| |
| if Unit.File_Names (Body_Part).Name /= No_Name then |
| if Unit.File_Names (Body_Part).Project = No_Project then |
| Write_Line (" No project"); |
| |
| else |
| Write_Str (" Project: "); |
| Get_Name_String |
| (Projects.Table |
| (Unit.File_Names (Body_Part).Project).Path_Name); |
| Write_Line (Name_Buffer (1 .. Name_Len)); |
| end if; |
| |
| Write_Str (" body: "); |
| Write_Line |
| (Namet.Get_Name_String |
| (Unit.File_Names (Body_Part).Name)); |
| end if; |
| |
| end loop; |
| |
| Write_Line ("end of List of Sources."); |
| end Print_Sources; |
| |
| ----------------------- |
| -- Spec_Path_Name_Of -- |
| ----------------------- |
| |
| function Spec_Path_Name_Of (Unit : Unit_Id) return String is |
| Data : Unit_Data := Units.Table (Unit); |
| |
| begin |
| if Data.File_Names (Specification).Path = No_Name then |
| declare |
| Current_Source : String_List_Id := |
| Projects.Table (Data.File_Names (Specification).Project).Sources; |
| Path : GNAT.OS_Lib.String_Access; |
| |
| begin |
| Data.File_Names (Specification).Path := |
| Data.File_Names (Specification).Name; |
| |
| while Current_Source /= Nil_String loop |
| String_To_Name_Buffer |
| (String_Elements.Table (Current_Source).Value); |
| Path := Locate_Regular_File |
| (Namet.Get_Name_String |
| (Data.File_Names (Specification).Name), |
| Name_Buffer (1 .. Name_Len)); |
| |
| if Path /= null then |
| Name_Len := Path'Length; |
| Name_Buffer (1 .. Name_Len) := Path.all; |
| Data.File_Names (Specification).Path := Name_Enter; |
| exit; |
| else |
| Current_Source := |
| String_Elements.Table (Current_Source).Next; |
| end if; |
| end loop; |
| |
| Units.Table (Unit) := Data; |
| end; |
| end if; |
| |
| return Namet.Get_Name_String (Data.File_Names (Specification).Path); |
| end Spec_Path_Name_Of; |
| |
| end Prj.Env; |