1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2010, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
27 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
29 with Makeutl; use Makeutl;
31 with Osint; use Osint;
32 with Output; use Output;
33 with Prj.Com; use Prj.Com;
37 package body Prj.Env is
39 Buffer_Initial : constant := 1_000;
40 -- Initial size of Buffer
42 Uninitialized_Prefix : constant String := '#' & Path_Separator;
43 -- Prefix to indicate that the project path has not been initilized yet.
44 -- Must be two characters long
46 No_Project_Default_Dir : constant String := "-";
47 -- Indicator in the project path to indicate that the default search
48 -- directories should not be added to the path
50 -----------------------
51 -- Local Subprograms --
52 -----------------------
54 package Source_Path_Table is new GNAT.Dynamic_Tables
55 (Table_Component_Type => Name_Id,
56 Table_Index_Type => Natural,
59 Table_Increment => 100);
60 -- A table to store the source dirs before creating the source path file
62 package Object_Path_Table is new GNAT.Dynamic_Tables
63 (Table_Component_Type => Path_Name_Type,
64 Table_Index_Type => Natural,
67 Table_Increment => 100);
68 -- A table to store the object dirs, before creating the object path file
70 procedure Add_To_Buffer
72 Buffer : in out String_Access;
73 Buffer_Last : in out Natural);
74 -- Add a string to Buffer, extending Buffer if needed
77 (Source_Dirs : String_List_Id;
78 In_Tree : Project_Tree_Ref;
79 Buffer : in out String_Access;
80 Buffer_Last : in out Natural);
81 -- Add to Ada_Path_Buffer all the source directories in string list
82 -- Source_Dirs, if any.
86 Buffer : in out String_Access;
87 Buffer_Last : in out Natural);
88 -- If Dir is not already in the global variable Ada_Path_Buffer, add it.
89 -- If Buffer_Last /= 0, prepend a Path_Separator character to Path.
91 procedure Add_To_Source_Path
92 (Source_Dirs : String_List_Id;
93 In_Tree : Project_Tree_Ref;
94 Source_Paths : in out Source_Path_Table.Instance);
95 -- Add to Ada_Path_B all the source directories in string list
96 -- Source_Dirs, if any. Increment Ada_Path_Length.
98 procedure Add_To_Object_Path
99 (Object_Dir : Path_Name_Type;
100 Object_Paths : in out Object_Path_Table.Instance);
101 -- Add Object_Dir to object path table. Make sure it is not duplicate
102 -- and it is the last one in the current table.
104 procedure Set_Path_File_Var (Name : String; Value : String);
105 -- Call Setenv, after calling To_Host_File_Spec
107 function Ultimate_Extension_Of
108 (Project : Project_Id) return Project_Id;
109 -- Return a project that is either Project or an extended ancestor of
110 -- Project that itself is not extended.
112 procedure Initialize_Project_Path
113 (Self : in out Project_Search_Path; Target_Name : String);
114 -- Initialize Current_Project_Path.
115 -- Does nothing if the path has already been initialized properly
117 ----------------------
118 -- Ada_Include_Path --
119 ----------------------
121 function Ada_Include_Path
122 (Project : Project_Id;
123 In_Tree : Project_Tree_Ref;
124 Recursive : Boolean := False) return String
126 Buffer : String_Access;
127 Buffer_Last : Natural := 0;
129 procedure Add (Project : Project_Id; Dummy : in out Boolean);
130 -- Add source dirs of Project to the path
136 procedure Add (Project : Project_Id; Dummy : in out Boolean) is
137 pragma Unreferenced (Dummy);
139 Add_To_Path (Project.Source_Dirs, In_Tree, Buffer, Buffer_Last);
142 procedure For_All_Projects is
143 new For_Every_Project_Imported (Boolean, Add);
145 Dummy : Boolean := False;
147 -- Start of processing for Ada_Include_Path
152 -- If it is the first time we call this function for
153 -- this project, compute the source path
155 if Project.Ada_Include_Path = null then
156 Buffer := new String (1 .. 4096);
157 For_All_Projects (Project, Dummy);
158 Project.Ada_Include_Path := new String'(Buffer (1 .. Buffer_Last));
162 return Project.Ada_Include_Path.all;
165 Buffer := new String (1 .. 4096);
166 Add_To_Path (Project.Source_Dirs, In_Tree, Buffer, Buffer_Last);
169 Result : constant String := Buffer (1 .. Buffer_Last);
175 end Ada_Include_Path;
177 ----------------------
178 -- Ada_Objects_Path --
179 ----------------------
181 function Ada_Objects_Path
182 (Project : Project_Id;
183 Including_Libraries : Boolean := True) return String_Access
185 Buffer : String_Access;
186 Buffer_Last : Natural := 0;
188 procedure Add (Project : Project_Id; Dummy : in out Boolean);
189 -- Add all the object directories of a project to the path
195 procedure Add (Project : Project_Id; Dummy : in out Boolean) is
196 pragma Unreferenced (Dummy);
197 Path : constant Path_Name_Type :=
200 Including_Libraries => Including_Libraries,
201 Only_If_Ada => False);
203 if Path /= No_Path then
204 Add_To_Path (Get_Name_String (Path), Buffer, Buffer_Last);
208 procedure For_All_Projects is
209 new For_Every_Project_Imported (Boolean, Add);
211 Dummy : Boolean := False;
213 -- Start of processing for Ada_Objects_Path
216 -- If it is the first time we call this function for
217 -- this project, compute the objects path
219 if Project.Ada_Objects_Path = null then
220 Buffer := new String (1 .. 4096);
221 For_All_Projects (Project, Dummy);
223 Project.Ada_Objects_Path := new String'(Buffer (1 .. Buffer_Last));
227 return Project.Ada_Objects_Path;
228 end Ada_Objects_Path;
234 procedure Add_To_Buffer
236 Buffer : in out String_Access;
237 Buffer_Last : in out Natural)
239 Last : constant Natural := Buffer_Last + S'Length;
242 while Last > Buffer'Last loop
244 New_Buffer : constant String_Access :=
245 new String (1 .. 2 * Buffer'Last);
247 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
249 Buffer := New_Buffer;
253 Buffer (Buffer_Last + 1 .. Last) := S;
257 ------------------------
258 -- Add_To_Object_Path --
259 ------------------------
261 procedure Add_To_Object_Path
262 (Object_Dir : Path_Name_Type;
263 Object_Paths : in out Object_Path_Table.Instance)
266 -- Check if the directory is already in the table
268 for Index in Object_Path_Table.First ..
269 Object_Path_Table.Last (Object_Paths)
272 -- If it is, remove it, and add it as the last one
274 if Object_Paths.Table (Index) = Object_Dir then
275 for Index2 in Index + 1 ..
276 Object_Path_Table.Last (Object_Paths)
278 Object_Paths.Table (Index2 - 1) := Object_Paths.Table (Index2);
282 (Object_Path_Table.Last (Object_Paths)) := Object_Dir;
287 -- The directory is not already in the table, add it
289 Object_Path_Table.Append (Object_Paths, Object_Dir);
290 end Add_To_Object_Path;
296 procedure Add_To_Path
297 (Source_Dirs : String_List_Id;
298 In_Tree : Project_Tree_Ref;
299 Buffer : in out String_Access;
300 Buffer_Last : in out Natural)
302 Current : String_List_Id := Source_Dirs;
303 Source_Dir : String_Element;
305 while Current /= Nil_String loop
306 Source_Dir := In_Tree.String_Elements.Table (Current);
307 Add_To_Path (Get_Name_String (Source_Dir.Display_Value),
308 Buffer, Buffer_Last);
309 Current := Source_Dir.Next;
313 procedure Add_To_Path
315 Buffer : in out String_Access;
316 Buffer_Last : in out Natural)
319 New_Buffer : String_Access;
322 function Is_Present (Path : String; Dir : String) return Boolean;
323 -- Return True if Dir is part of Path
329 function Is_Present (Path : String; Dir : String) return Boolean is
330 Last : constant Integer := Path'Last - Dir'Length + 1;
333 for J in Path'First .. Last loop
335 -- Note: the order of the conditions below is important, since
336 -- it ensures a minimal number of string comparisons.
339 or else Path (J - 1) = Path_Separator)
341 (J + Dir'Length > Path'Last
342 or else Path (J + Dir'Length) = Path_Separator)
343 and then Dir = Path (J .. J + Dir'Length - 1)
352 -- Start of processing for Add_To_Path
355 if Is_Present (Buffer (1 .. Buffer_Last), Dir) then
357 -- Dir is already in the path, nothing to do
362 Min_Len := Buffer_Last + Dir'Length;
364 if Buffer_Last > 0 then
366 -- Add 1 for the Path_Separator character
368 Min_Len := Min_Len + 1;
371 -- If Ada_Path_Buffer is too small, increase it
375 if Len < Min_Len then
378 exit when Len >= Min_Len;
381 New_Buffer := new String (1 .. Len);
382 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
384 Buffer := New_Buffer;
387 if Buffer_Last > 0 then
388 Buffer_Last := Buffer_Last + 1;
389 Buffer (Buffer_Last) := Path_Separator;
392 Buffer (Buffer_Last + 1 .. Buffer_Last + Dir'Length) := Dir;
393 Buffer_Last := Buffer_Last + Dir'Length;
396 ------------------------
397 -- Add_To_Source_Path --
398 ------------------------
400 procedure Add_To_Source_Path
401 (Source_Dirs : String_List_Id;
402 In_Tree : Project_Tree_Ref;
403 Source_Paths : in out Source_Path_Table.Instance)
405 Current : String_List_Id := Source_Dirs;
406 Source_Dir : String_Element;
410 -- Add each source directory
412 while Current /= Nil_String loop
413 Source_Dir := In_Tree.String_Elements.Table (Current);
416 -- Check if the source directory is already in the table
418 for Index in Source_Path_Table.First ..
419 Source_Path_Table.Last (Source_Paths)
421 -- If it is already, no need to add it
423 if Source_Paths.Table (Index) = Source_Dir.Value then
430 Source_Path_Table.Append (Source_Paths, Source_Dir.Display_Value);
433 -- Next source directory
435 Current := Source_Dir.Next;
437 end Add_To_Source_Path;
439 --------------------------------
440 -- Create_Config_Pragmas_File --
441 --------------------------------
443 procedure Create_Config_Pragmas_File
444 (For_Project : Project_Id;
445 In_Tree : Project_Tree_Ref)
447 type Naming_Id is new Nat;
448 package Naming_Table is new GNAT.Dynamic_Tables
449 (Table_Component_Type => Lang_Naming_Data,
450 Table_Index_Type => Naming_Id,
451 Table_Low_Bound => 1,
453 Table_Increment => 100);
454 Default_Naming : constant Naming_Id := Naming_Table.First;
455 Namings : Naming_Table.Instance;
456 -- Table storing the naming data for gnatmake/gprmake
458 Buffer : String_Access := new String (1 .. Buffer_Initial);
459 Buffer_Last : Natural := 0;
461 File_Name : Path_Name_Type := No_Path;
462 File : File_Descriptor := Invalid_FD;
464 Current_Naming : Naming_Id;
465 Iter : Source_Iterator;
468 procedure Check (Project : Project_Id; State : in out Integer);
469 -- Recursive procedure that put in the config pragmas file any non
470 -- standard naming schemes, if it is not already in the file, then call
471 -- itself for any imported project.
473 procedure Put (Source : Source_Id);
474 -- Put an SFN pragma in the temporary file
476 procedure Put (S : String);
477 procedure Put_Line (S : String);
478 -- Output procedures, analogous to normal Text_IO procs of same name.
479 -- The text is put in Buffer, then it will be writen into a temporary
480 -- file with procedure Write_Temp_File below.
482 procedure Write_Temp_File;
483 -- Create a temporary file and put the content of the buffer in it
489 procedure Check (Project : Project_Id; State : in out Integer) is
490 pragma Unreferenced (State);
491 Lang : constant Language_Ptr :=
492 Get_Language_From_Name (Project, "ada");
493 Naming : Lang_Naming_Data;
496 if Current_Verbosity = High then
497 Write_Str ("Checking project file """);
498 Write_Str (Namet.Get_Name_String (Project.Name));
504 if Current_Verbosity = High then
505 Write_Line (" Languages does not contain Ada, nothing to do");
511 Naming := Lang.Config.Naming_Data;
513 -- Is the naming scheme of this project one that we know?
515 Current_Naming := Default_Naming;
516 while Current_Naming <= Naming_Table.Last (Namings)
517 and then Namings.Table (Current_Naming).Dot_Replacement =
518 Naming.Dot_Replacement
519 and then Namings.Table (Current_Naming).Casing =
521 and then Namings.Table (Current_Naming).Separate_Suffix =
522 Naming.Separate_Suffix
524 Current_Naming := Current_Naming + 1;
527 -- If we don't know it, add it
529 if Current_Naming > Naming_Table.Last (Namings) then
530 Naming_Table.Increment_Last (Namings);
531 Namings.Table (Naming_Table.Last (Namings)) := Naming;
533 -- Put the SFN pragmas for the naming scheme
538 ("pragma Source_File_Name_Project");
540 (" (Spec_File_Name => ""*" &
541 Get_Name_String (Naming.Spec_Suffix) & """,");
544 Image (Naming.Casing) & ",");
546 (" Dot_Replacement => """ &
547 Get_Name_String (Naming.Dot_Replacement) & """);");
552 ("pragma Source_File_Name_Project");
554 (" (Body_File_Name => ""*" &
555 Get_Name_String (Naming.Body_Suffix) & """,");
558 Image (Naming.Casing) & ",");
560 (" Dot_Replacement => """ &
561 Get_Name_String (Naming.Dot_Replacement) &
564 -- and maybe separate
566 if Naming.Body_Suffix /= Naming.Separate_Suffix then
567 Put_Line ("pragma Source_File_Name_Project");
569 (" (Subunit_File_Name => ""*" &
570 Get_Name_String (Naming.Separate_Suffix) & """,");
573 Image (Naming.Casing) & ",");
575 (" Dot_Replacement => """ &
576 Get_Name_String (Naming.Dot_Replacement) &
586 procedure Put (Source : Source_Id) is
588 -- Put the pragma SFN for the unit kind (spec or body)
590 Put ("pragma Source_File_Name_Project (");
591 Put (Namet.Get_Name_String (Source.Unit.Name));
593 if Source.Kind = Spec then
594 Put (", Spec_File_Name => """);
596 Put (", Body_File_Name => """);
599 Put (Namet.Get_Name_String (Source.File));
602 if Source.Index /= 0 then
604 Put (Source.Index'Img);
610 procedure Put (S : String) is
612 Add_To_Buffer (S, Buffer, Buffer_Last);
614 if Current_Verbosity = High then
623 procedure Put_Line (S : String) is
625 -- Add an ASCII.LF to the string. As this config file is supposed to
626 -- be used only by the compiler, we don't care about the characters
627 -- for the end of line. In fact we could have put a space, but
628 -- it is more convenient to be able to read gnat.adc during
629 -- development, for which the ASCII.LF is fine.
632 Put (S => (1 => ASCII.LF));
635 ---------------------
636 -- Write_Temp_File --
637 ---------------------
639 procedure Write_Temp_File is
640 Status : Boolean := False;
644 Tempdir.Create_Temp_File (File, File_Name);
646 if File /= Invalid_FD then
647 Last := Write (File, Buffer (1)'Address, Buffer_Last);
649 if Last = Buffer_Last then
650 Close (File, Status);
655 Prj.Com.Fail ("unable to create temporary file");
659 procedure Check_Imported_Projects is
660 new For_Every_Project_Imported (Integer, Check);
662 Dummy : Integer := 0;
664 -- Start of processing for Create_Config_Pragmas_File
667 if not For_Project.Config_Checked then
668 Naming_Table.Init (Namings);
670 -- Check the naming schemes
672 Check_Imported_Projects (For_Project, Dummy, Imported_First => False);
674 -- Visit all the files and process those that need an SFN pragma
676 Iter := For_Each_Source (In_Tree, For_Project);
677 while Element (Iter) /= No_Source loop
678 Source := Element (Iter);
681 and then not Source.Locally_Removed
682 and then Source.Unit /= null
690 -- If there are no non standard naming scheme, issue the GNAT
691 -- standard naming scheme. This will tell the compiler that
692 -- a project file is used and will forbid any pragma SFN.
694 if Buffer_Last = 0 then
696 Put_Line ("pragma Source_File_Name_Project");
697 Put_Line (" (Spec_File_Name => ""*.ads"",");
698 Put_Line (" Dot_Replacement => ""-"",");
699 Put_Line (" Casing => lowercase);");
701 Put_Line ("pragma Source_File_Name_Project");
702 Put_Line (" (Body_File_Name => ""*.adb"",");
703 Put_Line (" Dot_Replacement => ""-"",");
704 Put_Line (" Casing => lowercase);");
707 -- Close the temporary file
711 if Opt.Verbose_Mode then
712 Write_Str ("Created configuration file """);
713 Write_Str (Get_Name_String (File_Name));
717 For_Project.Config_File_Name := File_Name;
718 For_Project.Config_File_Temp := True;
719 For_Project.Config_Checked := True;
723 end Create_Config_Pragmas_File;
729 procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
731 Iter : Source_Iterator;
736 Iter := For_Each_Source (In_Tree);
738 Data := Element (Iter);
739 exit when Data = No_Source;
741 if Data.Unit /= No_Unit_Index then
742 if Data.Locally_Removed then
743 Fmap.Add_Forbidden_File_Name (Data.File);
746 (Unit_Name => Unit_Name_Type (Data.Unit.Name),
747 File_Name => Data.File,
748 Path_Name => File_Name_Type (Data.Path.Display_Name));
756 -------------------------
757 -- Create_Mapping_File --
758 -------------------------
760 procedure Create_Mapping_File
761 (Project : Project_Id;
763 In_Tree : Project_Tree_Ref;
764 Name : out Path_Name_Type)
766 File : File_Descriptor := Invalid_FD;
768 Buffer : String_Access := new String (1 .. Buffer_Initial);
769 Buffer_Last : Natural := 0;
771 procedure Put_Name_Buffer;
772 -- Put the line contained in the Name_Buffer in the global buffer
774 procedure Process (Project : Project_Id; State : in out Integer);
775 -- Generate the mapping file for Project (not recursively)
777 ---------------------
778 -- Put_Name_Buffer --
779 ---------------------
781 procedure Put_Name_Buffer is
783 Name_Len := Name_Len + 1;
784 Name_Buffer (Name_Len) := ASCII.LF;
786 if Current_Verbosity = High then
787 Write_Str ("Mapping file: " & Name_Buffer (1 .. Name_Len));
790 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
797 procedure Process (Project : Project_Id; State : in out Integer) is
798 pragma Unreferenced (State);
800 Suffix : File_Name_Type;
801 Iter : Source_Iterator;
804 Iter := For_Each_Source (In_Tree, Project, Language => Language);
807 Source := Prj.Element (Iter);
808 exit when Source = No_Source;
810 if Source.Replaced_By = No_Source
811 and then Source.Path.Name /= No_Path
813 (Source.Language.Config.Kind = File_Based
814 or else Source.Unit /= No_Unit_Index)
816 if Source.Unit /= No_Unit_Index then
817 Get_Name_String (Source.Unit.Name);
819 if Source.Language.Config.Kind = Unit_Based then
821 -- ??? Mapping_Spec_Suffix could be set in the case of
824 Add_Char_To_Name_Buffer ('%');
826 if Source.Kind = Spec then
827 Add_Char_To_Name_Buffer ('s');
829 Add_Char_To_Name_Buffer ('b');
836 Source.Language.Config.Mapping_Spec_Suffix;
839 Source.Language.Config.Mapping_Body_Suffix;
842 if Suffix /= No_File then
843 Add_Str_To_Name_Buffer
844 (Get_Name_String (Suffix));
851 Get_Name_String (Source.Display_File);
854 if Source.Locally_Removed then
856 Name_Buffer (1) := '/';
858 Get_Name_String (Source.Path.Display_Name);
868 procedure For_Every_Imported_Project is new
869 For_Every_Project_Imported (State => Integer, Action => Process);
871 Dummy : Integer := 0;
873 -- Start of processing for Create_Mapping_File
876 For_Every_Imported_Project (Project, Dummy);
880 Status : Boolean := False;
883 Create_Temp_File (In_Tree, File, Name, "mapping");
885 if File /= Invalid_FD then
886 Last := Write (File, Buffer (1)'Address, Buffer_Last);
888 if Last = Buffer_Last then
889 GNAT.OS_Lib.Close (File, Status);
894 Prj.Com.Fail ("could not write mapping file");
899 end Create_Mapping_File;
901 ----------------------
902 -- Create_Temp_File --
903 ----------------------
905 procedure Create_Temp_File
906 (In_Tree : Project_Tree_Ref;
907 Path_FD : out File_Descriptor;
908 Path_Name : out Path_Name_Type;
912 Tempdir.Create_Temp_File (Path_FD, Path_Name);
914 if Path_Name /= No_Path then
915 if Current_Verbosity = High then
916 Write_Line ("Create temp file (" & File_Use & ") "
917 & Get_Name_String (Path_Name));
920 Record_Temp_File (In_Tree, Path_Name);
924 ("unable to create temporary " & File_Use & " file");
926 end Create_Temp_File;
928 --------------------------
929 -- Create_New_Path_File --
930 --------------------------
932 procedure Create_New_Path_File
933 (In_Tree : Project_Tree_Ref;
934 Path_FD : out File_Descriptor;
935 Path_Name : out Path_Name_Type)
938 Create_Temp_File (In_Tree, Path_FD, Path_Name, "path file");
939 end Create_New_Path_File;
941 ------------------------------------
942 -- File_Name_Of_Library_Unit_Body --
943 ------------------------------------
945 function File_Name_Of_Library_Unit_Body
947 Project : Project_Id;
948 In_Tree : Project_Tree_Ref;
949 Main_Project_Only : Boolean := True;
950 Full_Path : Boolean := False) return String
952 The_Project : Project_Id := Project;
953 Original_Name : String := Name;
955 Lang : constant Language_Ptr :=
956 Get_Language_From_Name (Project, "ada");
959 The_Original_Name : Name_Id;
960 The_Spec_Name : Name_Id;
961 The_Body_Name : Name_Id;
964 -- ??? Same block in Project_Of
965 Canonical_Case_File_Name (Original_Name);
966 Name_Len := Original_Name'Length;
967 Name_Buffer (1 .. Name_Len) := Original_Name;
968 The_Original_Name := Name_Find;
972 Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
973 Extended_Spec_Name : String :=
974 Name & Namet.Get_Name_String
975 (Naming.Spec_Suffix);
976 Extended_Body_Name : String :=
977 Name & Namet.Get_Name_String
978 (Naming.Body_Suffix);
981 Canonical_Case_File_Name (Extended_Spec_Name);
982 Name_Len := Extended_Spec_Name'Length;
983 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
984 The_Spec_Name := Name_Find;
986 Canonical_Case_File_Name (Extended_Body_Name);
987 Name_Len := Extended_Body_Name'Length;
988 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
989 The_Body_Name := Name_Find;
993 Name_Len := Name'Length;
994 Name_Buffer (1 .. Name_Len) := Name;
995 Canonical_Case_File_Name (Name_Buffer);
996 The_Spec_Name := Name_Find;
997 The_Body_Name := The_Spec_Name;
1000 if Current_Verbosity = High then
1001 Write_Str ("Looking for file name of """);
1005 Write_Str (" Extended Spec Name = """);
1006 Write_Str (Get_Name_String (The_Spec_Name));
1009 Write_Str (" Extended Body Name = """);
1010 Write_Str (Get_Name_String (The_Body_Name));
1015 -- For extending project, search in the extended project if the source
1016 -- is not found. For non extending projects, this loop will be run only
1020 -- Loop through units
1022 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1023 while Unit /= null loop
1026 if not Main_Project_Only
1028 (Unit.File_Names (Impl) /= null
1029 and then Unit.File_Names (Impl).Project = The_Project)
1032 Current_Name : File_Name_Type;
1034 -- Case of a body present
1036 if Unit.File_Names (Impl) /= null then
1037 Current_Name := Unit.File_Names (Impl).File;
1039 if Current_Verbosity = High then
1040 Write_Str (" Comparing with """);
1041 Write_Str (Get_Name_String (Current_Name));
1046 -- If it has the name of the original name, return the
1049 if Unit.Name = The_Original_Name
1051 Current_Name = File_Name_Type (The_Original_Name)
1053 if Current_Verbosity = High then
1058 return Get_Name_String
1059 (Unit.File_Names (Impl).Path.Name);
1062 return Get_Name_String (Current_Name);
1065 -- If it has the name of the extended body name,
1066 -- return the extended body name
1068 elsif Current_Name = File_Name_Type (The_Body_Name) then
1069 if Current_Verbosity = High then
1074 return Get_Name_String
1075 (Unit.File_Names (Impl).Path.Name);
1078 return Get_Name_String (The_Body_Name);
1082 if Current_Verbosity = High then
1083 Write_Line (" not good");
1092 if not Main_Project_Only
1094 (Unit.File_Names (Spec) /= null
1095 and then Unit.File_Names (Spec).Project =
1099 Current_Name : File_Name_Type;
1102 -- Case of spec present
1104 if Unit.File_Names (Spec) /= null then
1105 Current_Name := Unit.File_Names (Spec).File;
1106 if Current_Verbosity = High then
1107 Write_Str (" Comparing with """);
1108 Write_Str (Get_Name_String (Current_Name));
1113 -- If name same as original name, return original name
1115 if Unit.Name = The_Original_Name
1117 Current_Name = File_Name_Type (The_Original_Name)
1119 if Current_Verbosity = High then
1124 return Get_Name_String
1125 (Unit.File_Names (Spec).Path.Name);
1127 return Get_Name_String (Current_Name);
1130 -- If it has the same name as the extended spec name,
1131 -- return the extended spec name.
1133 elsif Current_Name = File_Name_Type (The_Spec_Name) then
1134 if Current_Verbosity = High then
1139 return Get_Name_String
1140 (Unit.File_Names (Spec).Path.Name);
1142 return Get_Name_String (The_Spec_Name);
1146 if Current_Verbosity = High then
1147 Write_Line (" not good");
1154 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1157 -- If we are not in an extending project, give up
1159 exit when not Main_Project_Only
1160 or else The_Project.Extends = No_Project;
1162 -- Otherwise, look in the project we are extending
1164 The_Project := The_Project.Extends;
1167 -- We don't know this file name, return an empty string
1170 end File_Name_Of_Library_Unit_Body;
1172 -------------------------
1173 -- For_All_Object_Dirs --
1174 -------------------------
1176 procedure For_All_Object_Dirs (Project : Project_Id) is
1177 procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1178 -- Get all object directories of Prj
1184 procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1185 pragma Unreferenced (Dummy);
1187 -- ??? Set_Ada_Paths has a different behavior for library project
1188 -- files, should we have the same ?
1190 if Prj.Object_Directory /= No_Path_Information then
1191 Get_Name_String (Prj.Object_Directory.Display_Name);
1192 Action (Name_Buffer (1 .. Name_Len));
1196 procedure Get_Object_Dirs is
1197 new For_Every_Project_Imported (Integer, For_Project);
1198 Dummy : Integer := 1;
1200 -- Start of processing for For_All_Object_Dirs
1203 Get_Object_Dirs (Project, Dummy);
1204 end For_All_Object_Dirs;
1206 -------------------------
1207 -- For_All_Source_Dirs --
1208 -------------------------
1210 procedure For_All_Source_Dirs
1211 (Project : Project_Id;
1212 In_Tree : Project_Tree_Ref)
1214 procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1215 -- Get all object directories of Prj
1221 procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1222 pragma Unreferenced (Dummy);
1223 Current : String_List_Id := Prj.Source_Dirs;
1224 The_String : String_Element;
1227 -- If there are Ada sources, call action with the name of every
1228 -- source directory.
1230 if Has_Ada_Sources (Project) then
1231 while Current /= Nil_String loop
1232 The_String := In_Tree.String_Elements.Table (Current);
1233 Action (Get_Name_String (The_String.Display_Value));
1234 Current := The_String.Next;
1239 procedure Get_Source_Dirs is
1240 new For_Every_Project_Imported (Integer, For_Project);
1241 Dummy : Integer := 1;
1243 -- Start of processing for For_All_Source_Dirs
1246 Get_Source_Dirs (Project, Dummy);
1247 end For_All_Source_Dirs;
1253 procedure Get_Reference
1254 (Source_File_Name : String;
1255 In_Tree : Project_Tree_Ref;
1256 Project : out Project_Id;
1257 Path : out Path_Name_Type)
1260 -- Body below could use some comments ???
1262 if Current_Verbosity > Default then
1263 Write_Str ("Getting Reference_Of (""");
1264 Write_Str (Source_File_Name);
1265 Write_Str (""") ... ");
1269 Original_Name : String := Source_File_Name;
1273 Canonical_Case_File_Name (Original_Name);
1274 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1276 while Unit /= null loop
1277 if Unit.File_Names (Spec) /= null
1278 and then Unit.File_Names (Spec).File /= No_File
1280 (Namet.Get_Name_String
1281 (Unit.File_Names (Spec).File) = Original_Name
1282 or else (Unit.File_Names (Spec).Path /=
1285 Namet.Get_Name_String
1286 (Unit.File_Names (Spec).Path.Name) =
1289 Project := Ultimate_Extension_Of
1290 (Project => Unit.File_Names (Spec).Project);
1291 Path := Unit.File_Names (Spec).Path.Display_Name;
1293 if Current_Verbosity > Default then
1294 Write_Str ("Done: Spec.");
1300 elsif Unit.File_Names (Impl) /= null
1301 and then Unit.File_Names (Impl).File /= No_File
1303 (Namet.Get_Name_String
1304 (Unit.File_Names (Impl).File) = Original_Name
1305 or else (Unit.File_Names (Impl).Path /=
1307 and then Namet.Get_Name_String
1308 (Unit.File_Names (Impl).Path.Name) =
1311 Project := Ultimate_Extension_Of
1312 (Project => Unit.File_Names (Impl).Project);
1313 Path := Unit.File_Names (Impl).Path.Display_Name;
1315 if Current_Verbosity > Default then
1316 Write_Str ("Done: Body.");
1323 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1327 Project := No_Project;
1330 if Current_Verbosity > Default then
1331 Write_Str ("Cannot be found.");
1340 procedure Initialize (In_Tree : Project_Tree_Ref) is
1342 In_Tree.Private_Part.Current_Source_Path_File := No_Path;
1343 In_Tree.Private_Part.Current_Object_Path_File := No_Path;
1350 -- Could use some comments in this body ???
1352 procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1356 Write_Line ("List of Sources:");
1358 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1360 while Unit /= No_Unit_Index loop
1362 Write_Line (Namet.Get_Name_String (Unit.Name));
1364 if Unit.File_Names (Spec).File /= No_File then
1365 if Unit.File_Names (Spec).Project = No_Project then
1366 Write_Line (" No project");
1369 Write_Str (" Project: ");
1371 (Unit.File_Names (Spec).Project.Path.Name);
1372 Write_Line (Name_Buffer (1 .. Name_Len));
1375 Write_Str (" spec: ");
1377 (Namet.Get_Name_String
1378 (Unit.File_Names (Spec).File));
1381 if Unit.File_Names (Impl).File /= No_File then
1382 if Unit.File_Names (Impl).Project = No_Project then
1383 Write_Line (" No project");
1386 Write_Str (" Project: ");
1388 (Unit.File_Names (Impl).Project.Path.Name);
1389 Write_Line (Name_Buffer (1 .. Name_Len));
1392 Write_Str (" body: ");
1394 (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1397 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1400 Write_Line ("end of List of Sources.");
1409 Main_Project : Project_Id;
1410 In_Tree : Project_Tree_Ref) return Project_Id
1412 Result : Project_Id := No_Project;
1414 Original_Name : String := Name;
1416 Lang : constant Language_Ptr :=
1417 Get_Language_From_Name (Main_Project, "ada");
1421 Current_Name : File_Name_Type;
1422 The_Original_Name : File_Name_Type;
1423 The_Spec_Name : File_Name_Type;
1424 The_Body_Name : File_Name_Type;
1427 -- ??? Same block in File_Name_Of_Library_Unit_Body
1428 Canonical_Case_File_Name (Original_Name);
1429 Name_Len := Original_Name'Length;
1430 Name_Buffer (1 .. Name_Len) := Original_Name;
1431 The_Original_Name := Name_Find;
1433 if Lang /= null then
1435 Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1436 Extended_Spec_Name : String :=
1437 Name & Namet.Get_Name_String
1438 (Naming.Spec_Suffix);
1439 Extended_Body_Name : String :=
1440 Name & Namet.Get_Name_String
1441 (Naming.Body_Suffix);
1444 Canonical_Case_File_Name (Extended_Spec_Name);
1445 Name_Len := Extended_Spec_Name'Length;
1446 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1447 The_Spec_Name := Name_Find;
1449 Canonical_Case_File_Name (Extended_Body_Name);
1450 Name_Len := Extended_Body_Name'Length;
1451 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1452 The_Body_Name := Name_Find;
1456 The_Spec_Name := The_Original_Name;
1457 The_Body_Name := The_Original_Name;
1460 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1461 while Unit /= null loop
1463 -- Case of a body present
1465 if Unit.File_Names (Impl) /= null then
1466 Current_Name := Unit.File_Names (Impl).File;
1468 -- If it has the name of the original name or the body name,
1469 -- we have found the project.
1471 if Unit.Name = Name_Id (The_Original_Name)
1472 or else Current_Name = The_Original_Name
1473 or else Current_Name = The_Body_Name
1475 Result := Unit.File_Names (Impl).Project;
1482 if Unit.File_Names (Spec) /= null then
1483 Current_Name := Unit.File_Names (Spec).File;
1485 -- If name same as the original name, or the spec name, we have
1486 -- found the project.
1488 if Unit.Name = Name_Id (The_Original_Name)
1489 or else Current_Name = The_Original_Name
1490 or else Current_Name = The_Spec_Name
1492 Result := Unit.File_Names (Spec).Project;
1497 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1500 -- Get the ultimate extending project
1502 if Result /= No_Project then
1503 while Result.Extended_By /= No_Project loop
1504 Result := Result.Extended_By;
1515 procedure Set_Ada_Paths
1516 (Project : Project_Id;
1517 In_Tree : Project_Tree_Ref;
1518 Including_Libraries : Boolean;
1519 Include_Path : Boolean := True;
1520 Objects_Path : Boolean := True)
1523 Source_Paths : Source_Path_Table.Instance;
1524 Object_Paths : Object_Path_Table.Instance;
1525 -- List of source or object dirs. Only computed the first time this
1526 -- procedure is called (since Source_FD is then reused)
1528 Source_FD : File_Descriptor := Invalid_FD;
1529 Object_FD : File_Descriptor := Invalid_FD;
1530 -- The temporary files to store the paths. These are only created the
1531 -- first time this procedure is called, and reused from then on.
1533 Process_Source_Dirs : Boolean := False;
1534 Process_Object_Dirs : Boolean := False;
1537 -- For calls to Close
1540 Buffer : String_Access := new String (1 .. Buffer_Initial);
1541 Buffer_Last : Natural := 0;
1543 procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean);
1544 -- Recursive procedure to add the source/object paths of extended/
1545 -- imported projects.
1551 procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean) is
1552 pragma Unreferenced (Dummy);
1554 Path : Path_Name_Type;
1557 -- ??? This is almost the equivalent of For_All_Source_Dirs
1559 if Process_Source_Dirs then
1561 -- Add to path all source directories of this project if there are
1564 if Has_Ada_Sources (Project) then
1565 Add_To_Source_Path (Project.Source_Dirs, In_Tree, Source_Paths);
1569 if Process_Object_Dirs then
1570 Path := Get_Object_Directory
1572 Including_Libraries => Including_Libraries,
1573 Only_If_Ada => True);
1575 if Path /= No_Path then
1576 Add_To_Object_Path (Path, Object_Paths);
1581 procedure For_All_Projects is
1582 new For_Every_Project_Imported (Boolean, Recursive_Add);
1584 Dummy : Boolean := False;
1586 -- Start of processing for Set_Ada_Paths
1589 -- If it is the first time we call this procedure for this project,
1590 -- compute the source path and/or the object path.
1592 if Include_Path and then Project.Include_Path_File = No_Path then
1593 Source_Path_Table.Init (Source_Paths);
1594 Process_Source_Dirs := True;
1595 Create_New_Path_File
1596 (In_Tree, Source_FD, Project.Include_Path_File);
1599 -- For the object path, we make a distinction depending on
1600 -- Including_Libraries.
1602 if Objects_Path and Including_Libraries then
1603 if Project.Objects_Path_File_With_Libs = No_Path then
1604 Object_Path_Table.Init (Object_Paths);
1605 Process_Object_Dirs := True;
1606 Create_New_Path_File
1607 (In_Tree, Object_FD, Project.Objects_Path_File_With_Libs);
1610 elsif Objects_Path then
1611 if Project.Objects_Path_File_Without_Libs = No_Path then
1612 Object_Path_Table.Init (Object_Paths);
1613 Process_Object_Dirs := True;
1614 Create_New_Path_File
1615 (In_Tree, Object_FD, Project.Objects_Path_File_Without_Libs);
1619 -- If there is something to do, set Seen to False for all projects,
1620 -- then call the recursive procedure Add for Project.
1622 if Process_Source_Dirs or Process_Object_Dirs then
1623 For_All_Projects (Project, Dummy);
1626 -- Write and close any file that has been created. Source_FD is not set
1627 -- when this subprogram is called a second time or more, since we reuse
1628 -- the previous version of the file.
1630 if Source_FD /= Invalid_FD then
1633 for Index in Source_Path_Table.First ..
1634 Source_Path_Table.Last (Source_Paths)
1636 Get_Name_String (Source_Paths.Table (Index));
1637 Name_Len := Name_Len + 1;
1638 Name_Buffer (Name_Len) := ASCII.LF;
1639 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1642 Last := Write (Source_FD, Buffer (1)'Address, Buffer_Last);
1644 if Last = Buffer_Last then
1645 Close (Source_FD, Status);
1652 Prj.Com.Fail ("could not write temporary file");
1656 if Object_FD /= Invalid_FD then
1659 for Index in Object_Path_Table.First ..
1660 Object_Path_Table.Last (Object_Paths)
1662 Get_Name_String (Object_Paths.Table (Index));
1663 Name_Len := Name_Len + 1;
1664 Name_Buffer (Name_Len) := ASCII.LF;
1665 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1668 Last := Write (Object_FD, Buffer (1)'Address, Buffer_Last);
1670 if Last = Buffer_Last then
1671 Close (Object_FD, Status);
1677 Prj.Com.Fail ("could not write temporary file");
1681 -- Set the env vars, if they need to be changed, and set the
1682 -- corresponding flags.
1684 if Include_Path and then
1685 In_Tree.Private_Part.Current_Source_Path_File /=
1686 Project.Include_Path_File
1688 In_Tree.Private_Part.Current_Source_Path_File :=
1689 Project.Include_Path_File;
1691 (Project_Include_Path_File,
1692 Get_Name_String (In_Tree.Private_Part.Current_Source_Path_File));
1695 if Objects_Path then
1696 if Including_Libraries then
1697 if In_Tree.Private_Part.Current_Object_Path_File /=
1698 Project.Objects_Path_File_With_Libs
1700 In_Tree.Private_Part.Current_Object_Path_File :=
1701 Project.Objects_Path_File_With_Libs;
1703 (Project_Objects_Path_File,
1705 (In_Tree.Private_Part.Current_Object_Path_File));
1709 if In_Tree.Private_Part.Current_Object_Path_File /=
1710 Project.Objects_Path_File_Without_Libs
1712 In_Tree.Private_Part.Current_Object_Path_File :=
1713 Project.Objects_Path_File_Without_Libs;
1715 (Project_Objects_Path_File,
1717 (In_Tree.Private_Part.Current_Object_Path_File));
1725 -----------------------
1726 -- Set_Path_File_Var --
1727 -----------------------
1729 procedure Set_Path_File_Var (Name : String; Value : String) is
1730 Host_Spec : String_Access := To_Host_File_Spec (Value);
1732 if Host_Spec = null then
1734 ("could not convert file name """ & Value & """ to host spec");
1736 Setenv (Name, Host_Spec.all);
1739 end Set_Path_File_Var;
1741 ---------------------------
1742 -- Ultimate_Extension_Of --
1743 ---------------------------
1745 function Ultimate_Extension_Of
1746 (Project : Project_Id) return Project_Id
1748 Result : Project_Id;
1752 while Result.Extended_By /= No_Project loop
1753 Result := Result.Extended_By;
1757 end Ultimate_Extension_Of;
1759 ---------------------
1760 -- Add_Directories --
1761 ---------------------
1763 procedure Add_Directories
1764 (Self : in out Project_Search_Path;
1767 Tmp : String_Access;
1769 if Self.Path = null then
1770 Self.Path := new String'(Uninitialized_Prefix & Path);
1773 Self.Path := new String'(Tmp.all & Path_Separator & Path);
1776 end Add_Directories;
1778 -----------------------------
1779 -- Initialize_Project_Path --
1780 -----------------------------
1782 procedure Initialize_Project_Path
1783 (Self : in out Project_Search_Path; Target_Name : String)
1785 Add_Default_Dir : Boolean := True;
1789 New_Last : Positive;
1791 Ada_Project_Path : constant String := "ADA_PROJECT_PATH";
1792 Gpr_Project_Path : constant String := "GPR_PROJECT_PATH";
1793 -- Name of alternate env. variable that contain path name(s) of
1794 -- directories where project files may reside. GPR_PROJECT_PATH has
1795 -- precedence over ADA_PROJECT_PATH.
1797 Gpr_Prj_Path : String_Access;
1798 Ada_Prj_Path : String_Access;
1799 -- The path name(s) of directories where project files may reside.
1803 -- If already initialized, nothing else to do
1804 if Self.Path /= null
1805 and then Self.Path (Self.Path'First) /= '#'
1810 -- The current directory is always first in the search path. Since the
1811 -- Project_Path currently starts with '#:' as a sign that it isn't
1812 -- initialized, we simply replace '#' with '.'
1814 if Self.Path = null then
1815 Self.Path := new String'('.' & Path_Separator);
1817 Self.Path (Self.Path'First) := '.';
1820 -- Then the reset of the project path (if any) currently contains the
1821 -- directories added through Add_Search_Project_Directory
1823 -- If environment variables are defined and not empty, add their content
1825 Gpr_Prj_Path := Getenv (Gpr_Project_Path);
1826 Ada_Prj_Path := Getenv (Ada_Project_Path);
1828 if Gpr_Prj_Path.all /= "" then
1829 Add_Directories (Self, Gpr_Prj_Path.all);
1832 Free (Gpr_Prj_Path);
1834 if Ada_Prj_Path.all /= "" then
1835 Add_Directories (Self, Ada_Prj_Path.all);
1838 Free (Ada_Prj_Path);
1840 -- Copy to Name_Buffer, since we will need to manipulate the path
1842 Name_Len := Self.Path'Length;
1843 Name_Buffer (1 .. Name_Len) := Self.Path.all;
1845 -- Scan the directory path to see if "-" is one of the directories.
1846 -- Remove each occurrence of "-" and set Add_Default_Dir to False.
1847 -- Also resolve relative paths and symbolic links.
1851 while First <= Name_Len
1852 and then (Name_Buffer (First) = Path_Separator)
1857 exit when First > Name_Len;
1861 while Last < Name_Len
1862 and then Name_Buffer (Last + 1) /= Path_Separator
1867 -- If the directory is "-", set Add_Default_Dir to False and
1868 -- remove from path.
1870 if Name_Buffer (First .. Last) = No_Project_Default_Dir then
1871 Add_Default_Dir := False;
1873 for J in Last + 1 .. Name_Len loop
1874 Name_Buffer (J - No_Project_Default_Dir'Length - 1) :=
1878 Name_Len := Name_Len - No_Project_Default_Dir'Length - 1;
1880 -- After removing the '-', go back one character to get the next
1881 -- directory correctly.
1885 elsif not Hostparm.OpenVMS
1886 or else not Is_Absolute_Path (Name_Buffer (First .. Last))
1888 -- On VMS, only expand relative path names, as absolute paths
1889 -- may correspond to multi-valued VMS logical names.
1892 New_Dir : constant String :=
1894 (Name_Buffer (First .. Last),
1895 Resolve_Links => Opt.Follow_Links_For_Dirs);
1898 -- If the absolute path was resolved and is different from
1899 -- the original, replace original with the resolved path.
1901 if New_Dir /= Name_Buffer (First .. Last)
1902 and then New_Dir'Length /= 0
1904 New_Len := Name_Len + New_Dir'Length - (Last - First + 1);
1905 New_Last := First + New_Dir'Length - 1;
1906 Name_Buffer (New_Last + 1 .. New_Len) :=
1907 Name_Buffer (Last + 1 .. Name_Len);
1908 Name_Buffer (First .. New_Last) := New_Dir;
1909 Name_Len := New_Len;
1920 -- Set the initial value of Current_Project_Path
1922 if Add_Default_Dir then
1924 Prefix : String_Ptr := Sdefault.Search_Dir_Prefix;
1927 if Prefix = null then
1928 Prefix := new String'(Executable_Prefix_Path);
1930 if Prefix.all /= "" then
1931 if Target_Name /= "" then
1932 Add_Str_To_Name_Buffer
1933 (Path_Separator & Prefix.all &
1934 "lib" & Directory_Separator & "gpr" &
1935 Directory_Separator & Target_Name);
1938 Add_Str_To_Name_Buffer
1939 (Path_Separator & Prefix.all &
1940 "share" & Directory_Separator & "gpr");
1941 Add_Str_To_Name_Buffer
1942 (Path_Separator & Prefix.all &
1943 "lib" & Directory_Separator & "gnat");
1948 new String'(Name_Buffer (1 .. Name_Len) & Path_Separator &
1950 ".." & Directory_Separator &
1951 ".." & Directory_Separator &
1952 ".." & Directory_Separator & "gnat");
1959 if Self.Path = null then
1960 Self.Path := new String'(Name_Buffer (1 .. Name_Len));
1962 end Initialize_Project_Path;
1969 (Self : in out Project_Search_Path;
1970 Path : out String_Access)
1973 Initialize_Project_Path (Self, ""); -- ??? Target_Name unspecified
1982 (Self : in out Project_Search_Path; Path : String) is
1985 Self.Path := new String'(Path);
1986 Projects_Paths.Reset (Self.Cache);
1993 procedure Find_Project
1994 (Self : in out Project_Search_Path;
1995 Project_File_Name : String;
1997 Path : out Namet.Path_Name_Type)
1999 File : constant String := Project_File_Name;
2000 -- Have to do a copy, in case the parameter is Name_Buffer, which we
2003 function Try_Path_Name (Path : String) return String_Access;
2004 pragma Inline (Try_Path_Name);
2005 -- Try the specified Path
2011 function Try_Path_Name (Path : String) return String_Access is
2014 Result : String_Access := null;
2017 if Current_Verbosity = High then
2018 Write_Str (" Trying ");
2022 if Is_Absolute_Path (Path) then
2023 if Is_Regular_File (Path) then
2024 Result := new String'(Path);
2028 -- Because we don't want to resolve symbolic links, we cannot use
2029 -- Locate_Regular_File. So, we try each possible path
2032 First := Self.Path'First;
2033 while First <= Self.Path'Last loop
2034 while First <= Self.Path'Last
2035 and then Self.Path (First) = Path_Separator
2040 exit when First > Self.Path'Last;
2043 while Last < Self.Path'Last
2044 and then Self.Path (Last + 1) /= Path_Separator
2051 if not Is_Absolute_Path (Self.Path (First .. Last)) then
2052 Add_Str_To_Name_Buffer (Get_Current_Dir); -- ??? System call
2053 Add_Char_To_Name_Buffer (Directory_Separator);
2056 Add_Str_To_Name_Buffer (Self.Path (First .. Last));
2057 Add_Char_To_Name_Buffer (Directory_Separator);
2058 Add_Str_To_Name_Buffer (Path);
2060 if Current_Verbosity = High then
2061 Write_Str (" Testing file ");
2062 Write_Line (Name_Buffer (1 .. Name_Len));
2065 if Is_Regular_File (Name_Buffer (1 .. Name_Len)) then
2066 Result := new String'(Name_Buffer (1 .. Name_Len));
2077 -- Local Declarations
2079 Result : String_Access;
2080 Has_Dot : Boolean := False;
2083 -- Start of processing for Project_Path_Name_Of
2086 Initialize_Project_Path (Self, "");
2088 if Current_Verbosity = High then
2089 Write_Str ("Searching for project (""");
2091 Write_Str (""", """);
2092 Write_Str (Directory);
2093 Write_Line (""");");
2096 -- Check the project cache
2098 Name_Len := File'Length;
2099 Name_Buffer (1 .. Name_Len) := File;
2101 Path := Projects_Paths.Get (Self.Cache, Key);
2103 if Path /= No_Path then
2107 -- Check if File contains an extension (a dot before a
2108 -- directory separator). If it is the case we do not try project file
2109 -- with an added extension as it is not possible to have multiple dots
2110 -- on a project file name.
2112 Check_Dot : for K in reverse File'Range loop
2113 if File (K) = '.' then
2118 exit Check_Dot when File (K) = Directory_Separator
2119 or else File (K) = '/';
2122 if not Is_Absolute_Path (File) then
2124 -- First we try <directory>/<file_name>.<extension>
2127 Result := Try_Path_Name
2128 (Directory & Directory_Separator &
2129 File & Project_File_Extension);
2132 -- Then we try <directory>/<file_name>
2134 if Result = null then
2135 Result := Try_Path_Name (Directory & Directory_Separator & File);
2139 -- Then we try <file_name>.<extension>
2141 if Result = null and then not Has_Dot then
2142 Result := Try_Path_Name (File & Project_File_Extension);
2145 -- Then we try <file_name>
2147 if Result = null then
2148 Result := Try_Path_Name (File);
2151 -- If we cannot find the project file, we return an empty string
2153 if Result = null then
2154 Path := Namet.No_Path;
2159 Final_Result : constant String :=
2160 GNAT.OS_Lib.Normalize_Pathname
2162 Directory => Directory,
2163 Resolve_Links => Opt.Follow_Links_For_Files,
2164 Case_Sensitive => True);
2167 Name_Len := Final_Result'Length;
2168 Name_Buffer (1 .. Name_Len) := Final_Result;
2170 Projects_Paths.Set (Self.Cache, Key, Path);
2179 procedure Free (Self : in out Project_Search_Path) is
2182 Projects_Paths.Reset (Self.Cache);