blob: 7f85ed3041e12328f1c3091c02258d4b4afe9397 [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- P R J --
-- --
-- B o d y --
-- --
-- Copyright (C) 2001-2006, 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, 51 Franklin Street, Fifth Floor, --
-- Boston, MA 02110-1301, USA. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc. --
-- --
------------------------------------------------------------------------------
with Ada.Characters.Handling; use Ada.Characters.Handling;
with Namet; use Namet;
with Output; use Output;
with Osint; use Osint;
with Prj.Attr;
with Prj.Env;
with Prj.Err; use Prj.Err;
with Snames; use Snames;
with Uintp; use Uintp;
with GNAT.Case_Util; use GNAT.Case_Util;
package body Prj is
Initial_Buffer_Size : constant := 100;
-- Initial size for extensible buffer used in Add_To_Buffer
The_Empty_String : Name_Id;
Name_C_Plus_Plus : Name_Id;
Default_Ada_Spec_Suffix_Id : Name_Id;
Default_Ada_Body_Suffix_Id : Name_Id;
Slash_Id : Name_Id;
-- Initialized in Prj.Initialized, then never modified
subtype Known_Casing is Casing_Type range All_Upper_Case .. Mixed_Case;
The_Casing_Images : constant array (Known_Casing) of String_Access :=
(All_Lower_Case => new String'("lowercase"),
All_Upper_Case => new String'("UPPERCASE"),
Mixed_Case => new String'("MixedCase"));
Initialized : Boolean := False;
Standard_Dot_Replacement : constant Name_Id :=
First_Name_Id + Character'Pos ('-');
Std_Naming_Data : Naming_Data :=
(Dot_Replacement => Standard_Dot_Replacement,
Dot_Repl_Loc => No_Location,
Casing => All_Lower_Case,
Spec_Suffix => No_Array_Element,
Ada_Spec_Suffix => No_Name,
Spec_Suffix_Loc => No_Location,
Impl_Suffixes => No_Impl_Suffixes,
Supp_Suffixes => No_Supp_Language_Index,
Body_Suffix => No_Array_Element,
Ada_Body_Suffix => No_Name,
Body_Suffix_Loc => No_Location,
Separate_Suffix => No_Name,
Sep_Suffix_Loc => No_Location,
Specs => No_Array_Element,
Bodies => No_Array_Element,
Specification_Exceptions => No_Array_Element,
Implementation_Exceptions => No_Array_Element);
Project_Empty : Project_Data :=
(Externally_Built => False,
Languages => No_Languages,
Supp_Languages => No_Supp_Language_Index,
First_Referred_By => No_Project,
Name => No_Name,
Display_Name => No_Name,
Path_Name => No_Name,
Display_Path_Name => No_Name,
Virtual => False,
Location => No_Location,
Mains => Nil_String,
Directory => No_Name,
Display_Directory => No_Name,
Dir_Path => null,
Library => False,
Library_Dir => No_Name,
Display_Library_Dir => No_Name,
Library_Src_Dir => No_Name,
Display_Library_Src_Dir => No_Name,
Library_ALI_Dir => No_Name,
Display_Library_ALI_Dir => No_Name,
Library_Name => No_Name,
Library_Kind => Static,
Lib_Internal_Name => No_Name,
Standalone_Library => False,
Lib_Interface_ALIs => Nil_String,
Lib_Auto_Init => False,
Symbol_Data => No_Symbols,
Ada_Sources_Present => True,
Other_Sources_Present => True,
Sources => Nil_String,
First_Other_Source => No_Other_Source,
Last_Other_Source => No_Other_Source,
Imported_Directories_Switches => null,
Include_Path => null,
Include_Data_Set => False,
Source_Dirs => Nil_String,
Known_Order_Of_Source_Dirs => True,
Object_Directory => No_Name,
Display_Object_Dir => No_Name,
Library_TS => Empty_Time_Stamp,
Exec_Directory => No_Name,
Display_Exec_Dir => No_Name,
Extends => No_Project,
Extended_By => No_Project,
Naming => Std_Naming_Data,
First_Language_Processing => Default_First_Language_Processing_Data,
Supp_Language_Processing => No_Supp_Language_Index,
Default_Linker => No_Name,
Default_Linker_Path => No_Name,
Decl => No_Declarations,
Imported_Projects => Empty_Project_List,
All_Imported_Projects => Empty_Project_List,
Ada_Include_Path => null,
Ada_Objects_Path => null,
Include_Path_File => No_Name,
Objects_Path_File_With_Libs => No_Name,
Objects_Path_File_Without_Libs => No_Name,
Config_File_Name => No_Name,
Config_File_Temp => False,
Config_Checked => False,
Language_Independent_Checked => False,
Checked => False,
Seen => False,
Need_To_Build_Lib => False,
Depth => 0,
Unkept_Comments => False);
-----------------------
-- Add_Language_Name --
-----------------------
procedure Add_Language_Name (Name : Name_Id) is
begin
Last_Language_Index := Last_Language_Index + 1;
Language_Indexes.Set (Name, Last_Language_Index);
Language_Names.Increment_Last;
Language_Names.Table (Last_Language_Index) := Name;
end Add_Language_Name;
-------------------
-- Add_To_Buffer --
-------------------
procedure Add_To_Buffer
(S : String;
To : in out String_Access;
Last : in out Natural)
is
begin
if To = null then
To := new String (1 .. Initial_Buffer_Size);
Last := 0;
end if;
-- If Buffer is too small, double its size
while Last + S'Length > To'Last loop
declare
New_Buffer : constant String_Access :=
new String (1 .. 2 * Last);
begin
New_Buffer (1 .. Last) := To (1 .. Last);
Free (To);
To := New_Buffer;
end;
end loop;
To (Last + 1 .. Last + S'Length) := S;
Last := Last + S'Length;
end Add_To_Buffer;
-----------------------------
-- Default_Ada_Body_Suffix --
-----------------------------
function Default_Ada_Body_Suffix return Name_Id is
begin
return Default_Ada_Body_Suffix_Id;
end Default_Ada_Body_Suffix;
-----------------------------
-- Default_Ada_Spec_Suffix --
-----------------------------
function Default_Ada_Spec_Suffix return Name_Id is
begin
return Default_Ada_Spec_Suffix_Id;
end Default_Ada_Spec_Suffix;
---------------------------
-- Display_Language_Name --
---------------------------
procedure Display_Language_Name (Language : Language_Index) is
begin
Get_Name_String (Language_Names.Table (Language));
To_Upper (Name_Buffer (1 .. 1));
Write_Str (Name_Buffer (1 .. Name_Len));
end Display_Language_Name;
-------------------
-- Empty_Project --
-------------------
function Empty_Project (Tree : Project_Tree_Ref) return Project_Data is
Value : Project_Data;
begin
Prj.Initialize (Tree => No_Project_Tree);
Value := Project_Empty;
Value.Naming := Tree.Private_Part.Default_Naming;
return Value;
end Empty_Project;
------------------
-- Empty_String --
------------------
function Empty_String return Name_Id is
begin
return The_Empty_String;
end Empty_String;
------------
-- Expect --
------------
procedure Expect (The_Token : Token_Type; Token_Image : String) is
begin
if Token /= The_Token then
Error_Msg (Token_Image & " expected", Token_Ptr);
end if;
end Expect;
--------------------------------
-- For_Every_Project_Imported --
--------------------------------
procedure For_Every_Project_Imported
(By : Project_Id;
In_Tree : Project_Tree_Ref;
With_State : in out State)
is
procedure Recursive_Check (Project : Project_Id);
-- Check if a project has already been seen. If not seen, mark it as
-- Seen, Call Action, and check all its imported projects.
---------------------
-- Recursive_Check --
---------------------
procedure Recursive_Check (Project : Project_Id) is
List : Project_List;
begin
if not In_Tree.Projects.Table (Project).Seen then
In_Tree.Projects.Table (Project).Seen := True;
Action (Project, With_State);
List :=
In_Tree.Projects.Table (Project).Imported_Projects;
while List /= Empty_Project_List loop
Recursive_Check (In_Tree.Project_Lists.Table (List).Project);
List := In_Tree.Project_Lists.Table (List).Next;
end loop;
end if;
end Recursive_Check;
-- Start of processing for For_Every_Project_Imported
begin
for Project in Project_Table.First ..
Project_Table.Last (In_Tree.Projects)
loop
In_Tree.Projects.Table (Project).Seen := False;
end loop;
Recursive_Check (Project => By);
end For_Every_Project_Imported;
----------
-- Hash --
----------
function Hash (Name : Name_Id) return Header_Num is
begin
return Hash (Get_Name_String (Name));
end Hash;
-----------
-- Image --
-----------
function Image (Casing : Casing_Type) return String is
begin
return The_Casing_Images (Casing).all;
end Image;
----------------
-- Initialize --
----------------
procedure Initialize (Tree : Project_Tree_Ref) is
begin
if not Initialized then
Initialized := True;
Uintp.Initialize;
Name_Len := 0;
The_Empty_String := Name_Find;
Empty_Name := The_Empty_String;
Name_Len := 4;
Name_Buffer (1 .. 4) := ".ads";
Default_Ada_Spec_Suffix_Id := Name_Find;
Name_Len := 4;
Name_Buffer (1 .. 4) := ".adb";
Default_Ada_Body_Suffix_Id := Name_Find;
Name_Len := 1;
Name_Buffer (1) := '/';
Slash_Id := Name_Find;
Name_Len := 3;
Name_Buffer (1 .. 3) := "c++";
Name_C_Plus_Plus := Name_Find;
Std_Naming_Data.Ada_Spec_Suffix := Default_Ada_Spec_Suffix;
Std_Naming_Data.Ada_Body_Suffix := Default_Ada_Body_Suffix;
Std_Naming_Data.Separate_Suffix := Default_Ada_Body_Suffix;
Project_Empty.Naming := Std_Naming_Data;
Prj.Env.Initialize;
Prj.Attr.Initialize;
Set_Name_Table_Byte (Name_Project, Token_Type'Pos (Tok_Project));
Set_Name_Table_Byte (Name_Extends, Token_Type'Pos (Tok_Extends));
Set_Name_Table_Byte (Name_External, Token_Type'Pos (Tok_External));
Language_Indexes.Reset;
Last_Language_Index := No_Language_Index;
Language_Names.Init;
Add_Language_Name (Name_Ada);
Add_Language_Name (Name_C);
Add_Language_Name (Name_C_Plus_Plus);
end if;
if Tree /= No_Project_Tree then
Reset (Tree);
end if;
end Initialize;
----------------
-- Is_Present --
----------------
function Is_Present
(Language : Language_Index;
In_Project : Project_Data;
In_Tree : Project_Tree_Ref) return Boolean
is
begin
case Language is
when No_Language_Index =>
return False;
when First_Language_Indexes =>
return In_Project.Languages (Language);
when others =>
declare
Supp : Supp_Language;
Supp_Index : Supp_Language_Index := In_Project.Supp_Languages;
begin
while Supp_Index /= No_Supp_Language_Index loop
Supp := In_Tree.Present_Languages.Table (Supp_Index);
if Supp.Index = Language then
return Supp.Present;
end if;
Supp_Index := Supp.Next;
end loop;
return False;
end;
end case;
end Is_Present;
---------------------------------
-- Language_Processing_Data_Of --
---------------------------------
function Language_Processing_Data_Of
(Language : Language_Index;
In_Project : Project_Data;
In_Tree : Project_Tree_Ref) return Language_Processing_Data
is
begin
case Language is
when No_Language_Index =>
return Default_Language_Processing_Data;
when First_Language_Indexes =>
return In_Project.First_Language_Processing (Language);
when others =>
declare
Supp : Supp_Language_Data;
Supp_Index : Supp_Language_Index :=
In_Project.Supp_Language_Processing;
begin
while Supp_Index /= No_Supp_Language_Index loop
Supp := In_Tree.Supp_Languages.Table (Supp_Index);
if Supp.Index = Language then
return Supp.Data;
end if;
Supp_Index := Supp.Next;
end loop;
return Default_Language_Processing_Data;
end;
end case;
end Language_Processing_Data_Of;
------------------------------------
-- Register_Default_Naming_Scheme --
------------------------------------
procedure Register_Default_Naming_Scheme
(Language : Name_Id;
Default_Spec_Suffix : Name_Id;
Default_Body_Suffix : Name_Id;
In_Tree : Project_Tree_Ref)
is
Lang : Name_Id;
Suffix : Array_Element_Id;
Found : Boolean := False;
Element : Array_Element;
begin
-- Get the language name in small letters
Get_Name_String (Language);
Name_Buffer (1 .. Name_Len) := To_Lower (Name_Buffer (1 .. Name_Len));
Lang := Name_Find;
Suffix := In_Tree.Private_Part.Default_Naming.Spec_Suffix;
Found := False;
-- Look for an element of the spec sufix array indexed by the language
-- name. If one is found, put the default value.
while Suffix /= No_Array_Element and then not Found loop
Element := In_Tree.Array_Elements.Table (Suffix);
if Element.Index = Lang then
Found := True;
Element.Value.Value := Default_Spec_Suffix;
In_Tree.Array_Elements.Table (Suffix) := Element;
else
Suffix := Element.Next;
end if;
end loop;
-- If none can be found, create a new one
if not Found then
Element :=
(Index => Lang,
Src_Index => 0,
Index_Case_Sensitive => False,
Value => (Project => No_Project,
Kind => Single,
Location => No_Location,
Default => False,
Value => Default_Spec_Suffix,
Index => 0),
Next => In_Tree.Private_Part.Default_Naming.Spec_Suffix);
Array_Element_Table.Increment_Last (In_Tree.Array_Elements);
In_Tree.Array_Elements.Table
(Array_Element_Table.Last (In_Tree.Array_Elements)) :=
Element;
In_Tree.Private_Part.Default_Naming.Spec_Suffix :=
Array_Element_Table.Last (In_Tree.Array_Elements);
end if;
Suffix := In_Tree.Private_Part.Default_Naming.Body_Suffix;
Found := False;
-- Look for an element of the body sufix array indexed by the language
-- name. If one is found, put the default value.
while Suffix /= No_Array_Element and then not Found loop
Element := In_Tree.Array_Elements.Table (Suffix);
if Element.Index = Lang then
Found := True;
Element.Value.Value := Default_Body_Suffix;
In_Tree.Array_Elements.Table (Suffix) := Element;
else
Suffix := Element.Next;
end if;
end loop;
-- If none can be found, create a new one
if not Found then
Element :=
(Index => Lang,
Src_Index => 0,
Index_Case_Sensitive => False,
Value => (Project => No_Project,
Kind => Single,
Location => No_Location,
Default => False,
Value => Default_Body_Suffix,
Index => 0),
Next => In_Tree.Private_Part.Default_Naming.Body_Suffix);
Array_Element_Table.Increment_Last
(In_Tree.Array_Elements);
In_Tree.Array_Elements.Table
(Array_Element_Table.Last (In_Tree.Array_Elements))
:= Element;
In_Tree.Private_Part.Default_Naming.Body_Suffix :=
Array_Element_Table.Last (In_Tree.Array_Elements);
end if;
end Register_Default_Naming_Scheme;
-----------
-- Reset --
-----------
procedure Reset (Tree : Project_Tree_Ref) is
begin
Prj.Env.Initialize;
Present_Language_Table.Init (Tree.Present_Languages);
Supp_Suffix_Table.Init (Tree.Supp_Suffixes);
Name_List_Table.Init (Tree.Name_Lists);
Supp_Language_Table.Init (Tree.Supp_Languages);
Other_Source_Table.Init (Tree.Other_Sources);
String_Element_Table.Init (Tree.String_Elements);
Variable_Element_Table.Init (Tree.Variable_Elements);
Array_Element_Table.Init (Tree.Array_Elements);
Array_Table.Init (Tree.Arrays);
Package_Table.Init (Tree.Packages);
Project_List_Table.Init (Tree.Project_Lists);
Project_Table.Init (Tree.Projects);
Unit_Table.Init (Tree.Units);
Units_Htable.Reset (Tree.Units_HT);
Files_Htable.Reset (Tree.Files_HT);
Naming_Table.Init (Tree.Private_Part.Namings);
Naming_Table.Increment_Last (Tree.Private_Part.Namings);
Tree.Private_Part.Namings.Table
(Naming_Table.Last (Tree.Private_Part.Namings)) := Std_Naming_Data;
Path_File_Table.Init (Tree.Private_Part.Path_Files);
Source_Path_Table.Init (Tree.Private_Part.Source_Paths);
Object_Path_Table.Init (Tree.Private_Part.Object_Paths);
Tree.Private_Part.Default_Naming := Std_Naming_Data;
Register_Default_Naming_Scheme
(Language => Name_Ada,
Default_Spec_Suffix => Default_Ada_Spec_Suffix,
Default_Body_Suffix => Default_Ada_Body_Suffix,
In_Tree => Tree);
end Reset;
------------------------
-- Same_Naming_Scheme --
------------------------
function Same_Naming_Scheme
(Left, Right : Naming_Data) return Boolean
is
begin
return Left.Dot_Replacement = Right.Dot_Replacement
and then Left.Casing = Right.Casing
and then Left.Ada_Spec_Suffix = Right.Ada_Spec_Suffix
and then Left.Ada_Body_Suffix = Right.Ada_Body_Suffix
and then Left.Separate_Suffix = Right.Separate_Suffix;
end Same_Naming_Scheme;
---------
-- Set --
---------
procedure Set
(Language : Language_Index;
Present : Boolean;
In_Project : in out Project_Data;
In_Tree : Project_Tree_Ref)
is
begin
case Language is
when No_Language_Index =>
null;
when First_Language_Indexes =>
In_Project.Languages (Language) := Present;
when others =>
declare
Supp : Supp_Language;
Supp_Index : Supp_Language_Index := In_Project.Supp_Languages;
begin
while Supp_Index /= No_Supp_Language_Index loop
Supp := In_Tree.Present_Languages.Table
(Supp_Index);
if Supp.Index = Language then
In_Tree.Present_Languages.Table
(Supp_Index).Present := Present;
return;
end if;
Supp_Index := Supp.Next;
end loop;
Supp := (Index => Language, Present => Present,
Next => In_Project.Supp_Languages);
Present_Language_Table.Increment_Last
(In_Tree.Present_Languages);
Supp_Index := Present_Language_Table.Last
(In_Tree.Present_Languages);
In_Tree.Present_Languages.Table (Supp_Index) :=
Supp;
In_Project.Supp_Languages := Supp_Index;
end;
end case;
end Set;
procedure Set
(Language_Processing : Language_Processing_Data;
For_Language : Language_Index;
In_Project : in out Project_Data;
In_Tree : Project_Tree_Ref)
is
begin
case For_Language is
when No_Language_Index =>
null;
when First_Language_Indexes =>
In_Project.First_Language_Processing (For_Language) :=
Language_Processing;
when others =>
declare
Supp : Supp_Language_Data;
Supp_Index : Supp_Language_Index :=
In_Project.Supp_Language_Processing;
begin
while Supp_Index /= No_Supp_Language_Index loop
Supp := In_Tree.Supp_Languages.Table (Supp_Index);
if Supp.Index = For_Language then
In_Tree.Supp_Languages.Table
(Supp_Index).Data := Language_Processing;
return;
end if;
Supp_Index := Supp.Next;
end loop;
Supp := (Index => For_Language, Data => Language_Processing,
Next => In_Project.Supp_Language_Processing);
Supp_Language_Table.Increment_Last
(In_Tree.Supp_Languages);
Supp_Index := Supp_Language_Table.Last
(In_Tree.Supp_Languages);
In_Tree.Supp_Languages.Table (Supp_Index) := Supp;
In_Project.Supp_Language_Processing := Supp_Index;
end;
end case;
end Set;
procedure Set
(Suffix : Name_Id;
For_Language : Language_Index;
In_Project : in out Project_Data;
In_Tree : Project_Tree_Ref)
is
begin
case For_Language is
when No_Language_Index =>
null;
when First_Language_Indexes =>
In_Project.Naming.Impl_Suffixes (For_Language) := Suffix;
when others =>
declare
Supp : Supp_Suffix;
Supp_Index : Supp_Language_Index :=
In_Project.Naming.Supp_Suffixes;
begin
while Supp_Index /= No_Supp_Language_Index loop
Supp := In_Tree.Supp_Suffixes.Table
(Supp_Index);
if Supp.Index = For_Language then
In_Tree.Supp_Suffixes.Table
(Supp_Index).Suffix := Suffix;
return;
end if;
Supp_Index := Supp.Next;
end loop;
Supp := (Index => For_Language, Suffix => Suffix,
Next => In_Project.Naming.Supp_Suffixes);
Supp_Suffix_Table.Increment_Last
(In_Tree.Supp_Suffixes);
Supp_Index := Supp_Suffix_Table.Last
(In_Tree.Supp_Suffixes);
In_Tree.Supp_Suffixes.Table (Supp_Index) := Supp;
In_Project.Naming.Supp_Suffixes := Supp_Index;
end;
end case;
end Set;
-----------
-- Slash --
-----------
function Slash return Name_Id is
begin
return Slash_Id;
end Slash;
--------------------------
-- Standard_Naming_Data --
--------------------------
function Standard_Naming_Data
(Tree : Project_Tree_Ref := No_Project_Tree) return Naming_Data
is
begin
if Tree = No_Project_Tree then
Prj.Initialize (Tree => No_Project_Tree);
return Std_Naming_Data;
else
return Tree.Private_Part.Default_Naming;
end if;
end Standard_Naming_Data;
---------------
-- Suffix_Of --
---------------
function Suffix_Of
(Language : Language_Index;
In_Project : Project_Data;
In_Tree : Project_Tree_Ref) return Name_Id
is
begin
case Language is
when No_Language_Index =>
return No_Name;
when First_Language_Indexes =>
return In_Project.Naming.Impl_Suffixes (Language);
when others =>
declare
Supp : Supp_Suffix;
Supp_Index : Supp_Language_Index :=
In_Project.Naming.Supp_Suffixes;
begin
while Supp_Index /= No_Supp_Language_Index loop
Supp := In_Tree.Supp_Suffixes.Table (Supp_Index);
if Supp.Index = Language then
return Supp.Suffix;
end if;
Supp_Index := Supp.Next;
end loop;
return No_Name;
end;
end case;
end Suffix_Of;
-----------
-- Value --
-----------
function Value (Image : String) return Casing_Type is
begin
for Casing in The_Casing_Images'Range loop
if To_Lower (Image) = To_Lower (The_Casing_Images (Casing).all) then
return Casing;
end if;
end loop;
raise Constraint_Error;
end Value;
begin
-- Make sure that the standard project file extension is compatible
-- with canonical case file naming.
Canonical_Case_File_Name (Project_File_Extension);
end Prj;