1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2014, 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 ------------------------------------------------------------------------------
26 with Ada
.Containers
.Indefinite_Ordered_Sets
;
28 with Ada
.Unchecked_Deallocation
;
30 with GNAT
.Case_Util
; use GNAT
.Case_Util
;
31 with GNAT
.Regexp
; use GNAT
.Regexp
;
34 with Osint
; use Osint
;
35 with Output
; use Output
;
38 with Snames
; use Snames
;
40 with Targparm
; use Targparm
;
44 package body Prj
.Util
is
46 package Source_Info_Table
is new Table
.Table
47 (Table_Component_Type
=> Source_Info_Iterator
,
48 Table_Index_Type
=> Natural,
51 Table_Increment
=> 100,
52 Table_Name
=> "Makeutl.Source_Info_Table");
54 package Source_Info_Project_HTable
is new GNAT
.HTable
.Simple_HTable
55 (Header_Num
=> Prj
.Header_Num
,
62 procedure Free
is new Ada
.Unchecked_Deallocation
63 (Text_File_Data
, Text_File
);
69 procedure Close
(File
: in out Text_File
) is
75 Prj
.Com
.Fail
("Close attempted on an invalid Text_File");
79 if File
.Buffer_Len
> 0 then
80 Len
:= Write
(File
.FD
, File
.Buffer
'Address, File
.Buffer_Len
);
82 if Len
/= File
.Buffer_Len
then
83 Prj
.Com
.Fail
("Unable to write to an out Text_File");
87 Close
(File
.FD
, Status
);
90 Prj
.Com
.Fail
("Unable to close an out Text_File");
95 -- Close in file, no need to test status, since this is a file that
96 -- we read, and the file was read successfully before we closed it.
108 procedure Create
(File
: out Text_File
; Name
: String) is
109 FD
: File_Descriptor
;
110 File_Name
: String (1 .. Name
'Length + 1);
113 File_Name
(1 .. Name
'Length) := Name
;
114 File_Name
(File_Name
'Last) := ASCII
.NUL
;
115 FD
:= Create_File
(Name
=> File_Name
'Address,
116 Fmode
=> GNAT
.OS_Lib
.Text
);
118 if FD
= Invalid_FD
then
122 File
:= new Text_File_Data
;
124 File
.Out_File
:= True;
125 File
.End_Of_File_Reached
:= True;
134 (This
: in out Name_List_Index
;
135 Shared
: Shared_Project_Tree_Data_Access
)
137 Old_Current
: Name_List_Index
;
138 New_Current
: Name_List_Index
;
141 if This
/= No_Name_List
then
143 Name_List_Table
.Increment_Last
(Shared
.Name_Lists
);
144 New_Current
:= Name_List_Table
.Last
(Shared
.Name_Lists
);
146 Shared
.Name_Lists
.Table
(New_Current
) :=
147 (Shared
.Name_Lists
.Table
(Old_Current
).Name
, No_Name_List
);
150 Old_Current
:= Shared
.Name_Lists
.Table
(Old_Current
).Next
;
151 exit when Old_Current
= No_Name_List
;
152 Shared
.Name_Lists
.Table
(New_Current
).Next
:= New_Current
+ 1;
153 Name_List_Table
.Increment_Last
(Shared
.Name_Lists
);
154 New_Current
:= New_Current
+ 1;
155 Shared
.Name_Lists
.Table
(New_Current
) :=
156 (Shared
.Name_Lists
.Table
(Old_Current
).Name
, No_Name_List
);
165 function End_Of_File
(File
: Text_File
) return Boolean is
168 Prj
.Com
.Fail
("End_Of_File attempted on an invalid Text_File");
171 return File
.End_Of_File_Reached
;
178 function Executable_Of
179 (Project
: Project_Id
;
180 Shared
: Shared_Project_Tree_Data_Access
;
181 Main
: File_Name_Type
;
183 Ada_Main
: Boolean := True;
184 Language
: String := "";
185 Include_Suffix
: Boolean := True) return File_Name_Type
187 pragma Assert
(Project
/= No_Project
);
189 The_Packages
: constant Package_Id
:= Project
.Decl
.Packages
;
191 Builder_Package
: constant Prj
.Package_Id
:=
193 (Name
=> Name_Builder
,
194 In_Packages
=> The_Packages
,
197 Executable
: Variable_Value
:=
199 (Name
=> Name_Id
(Main
),
201 Attribute_Or_Array_Name
=> Name_Executable
,
202 In_Package
=> Builder_Package
,
207 Spec_Suffix
: Name_Id
:= No_Name
;
208 Body_Suffix
: Name_Id
:= No_Name
;
210 Spec_Suffix_Length
: Natural := 0;
211 Body_Suffix_Length
: Natural := 0;
213 procedure Get_Suffixes
214 (B_Suffix
: File_Name_Type
;
215 S_Suffix
: File_Name_Type
);
216 -- Get the non empty suffixes in variables Spec_Suffix and Body_Suffix
218 function Add_Suffix
(File
: File_Name_Type
) return File_Name_Type
;
219 -- Return the name of the executable, based on File, and adding the
220 -- executable suffix if needed
226 procedure Get_Suffixes
227 (B_Suffix
: File_Name_Type
;
228 S_Suffix
: File_Name_Type
)
231 if B_Suffix
/= No_File
then
232 Body_Suffix
:= Name_Id
(B_Suffix
);
233 Body_Suffix_Length
:= Natural (Length_Of_Name
(Body_Suffix
));
236 if S_Suffix
/= No_File
then
237 Spec_Suffix
:= Name_Id
(S_Suffix
);
238 Spec_Suffix_Length
:= Natural (Length_Of_Name
(Spec_Suffix
));
246 function Add_Suffix
(File
: File_Name_Type
) return File_Name_Type
is
247 Saved_EEOT
: constant Name_Id
:= Executable_Extension_On_Target
;
248 Result
: File_Name_Type
;
249 Suffix_From_Project
: Variable_Value
;
251 if Include_Suffix
then
252 if Project
.Config
.Executable_Suffix
/= No_Name
then
253 Executable_Extension_On_Target
:=
254 Project
.Config
.Executable_Suffix
;
257 Result
:= Executable_Name
(File
);
258 Executable_Extension_On_Target
:= Saved_EEOT
;
261 elsif Builder_Package
/= No_Package
then
263 -- If the suffix is specified in the project itself, as opposed to
264 -- the config file, it needs to be taken into account. However,
265 -- when the project was processed, in both cases the suffix was
266 -- stored in Project.Config, so get it from the project again.
268 Suffix_From_Project
:=
270 (Variable_Name
=> Name_Executable_Suffix
,
272 Shared
.Packages
.Table
(Builder_Package
).Decl
.Attributes
,
275 if Suffix_From_Project
/= Nil_Variable_Value
276 and then Suffix_From_Project
.Value
/= No_Name
278 Executable_Extension_On_Target
:= Suffix_From_Project
.Value
;
279 Result
:= Executable_Name
(File
);
280 Executable_Extension_On_Target
:= Saved_EEOT
;
288 -- Start of processing for Executable_Of
292 Lang
:= Get_Language_From_Name
(Project
, "ada");
293 elsif Language
/= "" then
294 Lang
:= Get_Language_From_Name
(Project
, Language
);
299 (B_Suffix
=> Lang
.Config
.Naming_Data
.Body_Suffix
,
300 S_Suffix
=> Lang
.Config
.Naming_Data
.Spec_Suffix
);
303 if Builder_Package
/= No_Package
then
304 if Executable
= Nil_Variable_Value
and then Ada_Main
then
305 Get_Name_String
(Main
);
307 -- Try as index the name minus the implementation suffix or minus
308 -- the specification suffix.
311 Name
: constant String (1 .. Name_Len
) :=
312 Name_Buffer
(1 .. Name_Len
);
313 Last
: Positive := Name_Len
;
315 Truncated
: Boolean := False;
318 if Body_Suffix
/= No_Name
319 and then Last
> Natural (Length_Of_Name
(Body_Suffix
))
320 and then Name
(Last
- Body_Suffix_Length
+ 1 .. Last
) =
321 Get_Name_String
(Body_Suffix
)
324 Last
:= Last
- Body_Suffix_Length
;
327 if Spec_Suffix
/= No_Name
328 and then not Truncated
329 and then Last
> Spec_Suffix_Length
330 and then Name
(Last
- Spec_Suffix_Length
+ 1 .. Last
) =
331 Get_Name_String
(Spec_Suffix
)
334 Last
:= Last
- Spec_Suffix_Length
;
339 Name_Buffer
(1 .. Name_Len
) := Name
(1 .. Last
);
344 Attribute_Or_Array_Name
=> Name_Executable
,
345 In_Package
=> Builder_Package
,
351 -- If we have found an Executable attribute, return its value,
352 -- possibly suffixed by the executable suffix.
354 if Executable
/= Nil_Variable_Value
355 and then Executable
.Value
/= No_Name
356 and then Length_Of_Name
(Executable
.Value
) /= 0
358 return Add_Suffix
(File_Name_Type
(Executable
.Value
));
362 Get_Name_String
(Main
);
364 -- If there is a body suffix or a spec suffix, remove this suffix,
365 -- otherwise remove any suffix ('.' followed by other characters), if
368 if Body_Suffix
/= No_Name
369 and then Name_Len
> Body_Suffix_Length
370 and then Name_Buffer
(Name_Len
- Body_Suffix_Length
+ 1 .. Name_Len
) =
371 Get_Name_String
(Body_Suffix
)
373 -- Found the body termination, remove it
375 Name_Len
:= Name_Len
- Body_Suffix_Length
;
377 elsif Spec_Suffix
/= No_Name
378 and then Name_Len
> Spec_Suffix_Length
380 Name_Buffer
(Name_Len
- Spec_Suffix_Length
+ 1 .. Name_Len
) =
381 Get_Name_String
(Spec_Suffix
)
383 -- Found the spec termination, remove it
385 Name_Len
:= Name_Len
- Spec_Suffix_Length
;
388 -- Remove any suffix, if there is one
390 Get_Name_String
(Strip_Suffix
(Main
));
393 return Add_Suffix
(Name_Find
);
396 ---------------------------
397 -- For_Interface_Sources --
398 ---------------------------
400 procedure For_Interface_Sources
401 (Tree
: Project_Tree_Ref
;
402 Project
: Project_Id
)
405 use type Ada
.Containers
.Count_Type
;
407 package Dep_Names
is new Containers
.Indefinite_Ordered_Sets
(String);
409 function Load_ALI
(Filename
: String) return ALI_Id
;
410 -- Load an ALI file and return its id
416 function Load_ALI
(Filename
: String) return ALI_Id
is
417 Result
: ALI_Id
:= No_ALI_Id
;
418 Text
: Text_Buffer_Ptr
;
419 Lib_File
: File_Name_Type
;
422 if Directories
.Exists
(Filename
) then
424 Add_Str_To_Name_Buffer
(Filename
);
425 Lib_File
:= Name_Find
;
426 Text
:= Osint
.Read_Library_Info
(Lib_File
);
440 -- Local declarations
442 Iter
: Source_Iterator
;
446 First_Unit
: Unit_Id
;
447 Second_Unit
: Unit_Id
;
448 Body_Needed
: Boolean;
449 Deps
: Dep_Names
.Set
;
451 -- Start of processing for For_Interface_Sources
454 if Project
.Qualifier
= Aggregate_Library
then
455 Iter
:= For_Each_Source
(Tree
);
457 Iter
:= For_Each_Source
(Tree
, Project
);
460 -- First look at each spec, check if the body is needed
463 Sid
:= Element
(Iter
);
464 exit when Sid
= No_Source
;
466 -- Skip sources that are removed/excluded and sources not part of
467 -- the interface for standalone libraries.
470 and then (not Sid
.Project
.Externally_Built
471 or else Sid
.Project
= Project
)
472 and then not Sid
.Locally_Removed
473 and then (Project
.Standalone_Library
= No
474 or else Sid
.Declared_In_Interfaces
)
476 -- Handle case of non-compilable languages
478 and then Sid
.Dep_Name
/= No_File
482 -- Check ALI for dependencies on body and sep
486 (Get_Name_String
(Get_Object_Directory
(Sid
.Project
, True))
487 & Get_Name_String
(Sid
.Dep_Name
));
489 if ALI
/= No_ALI_Id
then
490 First_Unit
:= ALIs
.Table
(ALI
).First_Unit
;
491 Second_Unit
:= No_Unit_Id
;
494 -- If there is both a spec and a body, check if both needed
496 if Units
.Table
(First_Unit
).Utype
= Is_Body
then
497 Second_Unit
:= ALIs
.Table
(ALI
).Last_Unit
;
499 -- If the body is not needed, then reset First_Unit
501 if not Units
.Table
(Second_Unit
).Body_Needed_For_SAL
then
502 Body_Needed
:= False;
505 elsif Units
.Table
(First_Unit
).Utype
= Is_Spec_Only
then
506 Body_Needed
:= False;
509 -- Handle all the separates, if any
512 if Other_Part
(Sid
) /= null then
513 Deps
.Include
(Get_Name_String
(Other_Part
(Sid
).File
));
516 for Dep
in ALIs
.Table
(ALI
).First_Sdep
..
517 ALIs
.Table
(ALI
).Last_Sdep
519 if Sdep
.Table
(Dep
).Subunit_Name
/= No_Name
then
521 (Get_Name_String
(Sdep
.Table
(Dep
).Sfile
));
531 -- Now handle the bodies and separates if needed
533 if Deps
.Length
/= 0 then
534 if Project
.Qualifier
= Aggregate_Library
then
535 Iter
:= For_Each_Source
(Tree
);
537 Iter
:= For_Each_Source
(Tree
, Project
);
541 Sid
:= Element
(Iter
);
542 exit when Sid
= No_Source
;
545 and then Deps
.Contains
(Get_Name_String
(Sid
.File
))
553 end For_Interface_Sources
;
574 if File
.Cursor
= File
.Buffer_Len
then
578 A
=> File
.Buffer
'Address,
579 N
=> File
.Buffer
'Length);
581 if File
.Buffer_Len
= 0 then
582 File
.End_Of_File_Reached
:= True;
589 File
.Cursor
:= File
.Cursor
+ 1;
593 -- Start of processing for Get_Line
597 Prj
.Com
.Fail
("Get_Line attempted on an invalid Text_File");
599 elsif File
.Out_File
then
600 Prj
.Com
.Fail
("Get_Line attempted on an out file");
603 Last
:= Line
'First - 1;
605 if not File
.End_Of_File_Reached
then
607 C
:= File
.Buffer
(File
.Cursor
);
608 exit when C
= ASCII
.CR
or else C
= ASCII
.LF
;
613 if File
.End_Of_File_Reached
then
617 exit when Last
= Line
'Last;
620 if C
= ASCII
.CR
or else C
= ASCII
.LF
then
623 if File
.End_Of_File_Reached
then
629 and then File
.Buffer
(File
.Cursor
) = ASCII
.LF
641 (Iter
: out Source_Info_Iterator
;
642 For_Project
: Name_Id
)
644 Ind
: constant Natural := Source_Info_Project_HTable
.Get
(For_Project
);
647 Iter
:= (No_Source_Info
, 0);
649 Iter
:= Source_Info_Table
.Table
(Ind
);
657 function Is_Valid
(File
: Text_File
) return Boolean is
666 procedure Next
(Iter
: in out Source_Info_Iterator
) is
668 if Iter
.Next
= 0 then
669 Iter
.Info
:= No_Source_Info
;
672 Iter
:= Source_Info_Table
.Table
(Iter
.Next
);
680 procedure Open
(File
: out Text_File
; Name
: String) is
681 FD
: File_Descriptor
;
682 File_Name
: String (1 .. Name
'Length + 1);
685 File_Name
(1 .. Name
'Length) := Name
;
686 File_Name
(File_Name
'Last) := ASCII
.NUL
;
687 FD
:= Open_Read
(Name
=> File_Name
'Address,
688 Fmode
=> GNAT
.OS_Lib
.Text
);
690 if FD
= Invalid_FD
then
694 File
:= new Text_File_Data
;
698 A
=> File
.Buffer
'Address,
699 N
=> File
.Buffer
'Length);
701 if File
.Buffer_Len
= 0 then
702 File
.End_Of_File_Reached
:= True;
714 (Into_List
: in out Name_List_Index
;
715 From_List
: String_List_Id
;
716 In_Tree
: Project_Tree_Ref
;
717 Lower_Case
: Boolean := False)
719 Shared
: constant Shared_Project_Tree_Data_Access
:= In_Tree
.Shared
;
721 Current_Name
: Name_List_Index
;
722 List
: String_List_Id
;
723 Element
: String_Element
;
724 Last
: Name_List_Index
:=
725 Name_List_Table
.Last
(Shared
.Name_Lists
);
729 Current_Name
:= Into_List
;
730 while Current_Name
/= No_Name_List
731 and then Shared
.Name_Lists
.Table
(Current_Name
).Next
/= No_Name_List
733 Current_Name
:= Shared
.Name_Lists
.Table
(Current_Name
).Next
;
737 while List
/= Nil_String
loop
738 Element
:= Shared
.String_Elements
.Table
(List
);
739 Value
:= Element
.Value
;
742 Get_Name_String
(Value
);
743 To_Lower
(Name_Buffer
(1 .. Name_Len
));
747 Name_List_Table
.Append
748 (Shared
.Name_Lists
, (Name
=> Value
, Next
=> No_Name_List
));
752 if Current_Name
= No_Name_List
then
755 Shared
.Name_Lists
.Table
(Current_Name
).Next
:= Last
;
758 Current_Name
:= Last
;
760 List
:= Element
.Next
;
764 procedure Put
(File
: Text_File
; S
: String) is
768 Prj
.Com
.Fail
("Attempted to write on an invalid Text_File");
770 elsif not File
.Out_File
then
771 Prj
.Com
.Fail
("Attempted to write an in Text_File");
774 if File
.Buffer_Len
+ S
'Length > File
.Buffer
'Last then
776 Len
:= Write
(File
.FD
, File
.Buffer
'Address, File
.Buffer_Len
);
778 if Len
/= File
.Buffer_Len
then
779 Prj
.Com
.Fail
("Failed to write to an out Text_File");
782 File
.Buffer_Len
:= 0;
785 File
.Buffer
(File
.Buffer_Len
+ 1 .. File
.Buffer_Len
+ S
'Length) := S
;
786 File
.Buffer_Len
:= File
.Buffer_Len
+ S
'Length;
793 procedure Put_Line
(File
: Text_File
; Line
: String) is
794 L
: String (1 .. Line
'Length + 1);
796 L
(1 .. Line
'Length) := Line
;
797 L
(L
'Last) := ASCII
.LF
;
801 ---------------------------
802 -- Read_Source_Info_File --
803 ---------------------------
805 procedure Read_Source_Info_File
(Tree
: Project_Tree_Ref
) is
807 Info
: Source_Info_Iterator
;
810 procedure Report_Error
;
816 procedure Report_Error
is
818 Write_Line
("errors in source info file """ &
819 Tree
.Source_Info_File_Name
.all & '"');
820 Tree
.Source_Info_File_Exists
:= False;
824 Source_Info_Project_HTable
.Reset
;
825 Source_Info_Table
.Init
;
827 if Tree
.Source_Info_File_Name
= null then
828 Tree
.Source_Info_File_Exists
:= False;
832 Open
(File
, Tree
.Source_Info_File_Name
.all);
834 if not Is_Valid
(File
) then
835 if Opt
.Verbose_Mode
then
836 Write_Line
("source info file " & Tree
.Source_Info_File_Name
.all &
840 Tree
.Source_Info_File_Exists
:= False;
844 Tree
.Source_Info_File_Exists
:= True;
846 if Opt
.Verbose_Mode
then
847 Write_Line
("Reading source info file " &
848 Tree
.Source_Info_File_Name
.all);
852 while not End_Of_File
(File
) loop
853 Info
:= (new Source_Info_Data
, 0);
854 Source_Info_Table
.Increment_Last
;
857 Get_Line
(File
, Name_Buffer
, Name_Len
);
859 Info
.Info
.Project
:= Proj
;
860 Info
.Next
:= Source_Info_Project_HTable
.Get
(Proj
);
861 Source_Info_Project_HTable
.Set
(Proj
, Source_Info_Table
.Last
);
863 if End_Of_File
(File
) then
869 Get_Line
(File
, Name_Buffer
, Name_Len
);
870 Info
.Info
.Language
:= Name_Find
;
872 if End_Of_File
(File
) then
878 Get_Line
(File
, Name_Buffer
, Name_Len
);
879 Info
.Info
.Kind
:= Source_Kind
'Value (Name_Buffer
(1 .. Name_Len
));
881 if End_Of_File
(File
) then
887 Get_Line
(File
, Name_Buffer
, Name_Len
);
888 Info
.Info
.Display_Path_Name
:= Name_Find
;
889 Info
.Info
.Path_Name
:= Info
.Info
.Display_Path_Name
;
891 if End_Of_File
(File
) then
899 Get_Line
(File
, Name_Buffer
, Name_Len
);
900 exit Option_Loop
when Name_Len
= 0;
902 if Name_Len
<= 2 then
907 if Name_Buffer
(1 .. 2) = "P=" then
908 Name_Buffer
(1 .. Name_Len
- 2) :=
909 Name_Buffer
(3 .. Name_Len
);
910 Name_Len
:= Name_Len
- 2;
911 Info
.Info
.Path_Name
:= Name_Find
;
913 elsif Name_Buffer
(1 .. 2) = "U=" then
914 Name_Buffer
(1 .. Name_Len
- 2) :=
915 Name_Buffer
(3 .. Name_Len
);
916 Name_Len
:= Name_Len
- 2;
917 Info
.Info
.Unit_Name
:= Name_Find
;
919 elsif Name_Buffer
(1 .. 2) = "I=" then
920 Info
.Info
.Index
:= Int
'Value (Name_Buffer
(3 .. Name_Len
));
922 elsif Name_Buffer
(1 .. Name_Len
) = "N=Y" then
923 Info
.Info
.Naming_Exception
:= Yes
;
925 elsif Name_Buffer
(1 .. Name_Len
) = "N=I" then
926 Info
.Info
.Naming_Exception
:= Inherited
;
933 end loop Option_Loop
;
935 Source_Info_Table
.Table
(Source_Info_Table
.Last
) := Info
;
936 end loop Source_Loop
;
944 end Read_Source_Info_File
;
950 function Source_Info_Of
(Iter
: Source_Info_Iterator
) return Source_Info
is
960 (Variable
: Variable_Value
;
961 Default
: String) return String
964 if Variable
.Kind
/= Single
965 or else Variable
.Default
966 or else Variable
.Value
= No_Name
970 return Get_Name_String
(Variable
.Value
);
976 In_Array
: Array_Element_Id
;
977 Shared
: Shared_Project_Tree_Data_Access
) return Name_Id
980 Current
: Array_Element_Id
;
981 Element
: Array_Element
;
982 Real_Index
: Name_Id
:= Index
;
987 if Current
= No_Array_Element
then
991 Element
:= Shared
.Array_Elements
.Table
(Current
);
993 if not Element
.Index_Case_Sensitive
then
994 Get_Name_String
(Index
);
995 To_Lower
(Name_Buffer
(1 .. Name_Len
));
996 Real_Index
:= Name_Find
;
999 while Current
/= No_Array_Element
loop
1000 Element
:= Shared
.Array_Elements
.Table
(Current
);
1002 if Real_Index
= Element
.Index
then
1003 exit when Element
.Value
.Kind
/= Single
;
1004 exit when Element
.Value
.Value
= Empty_String
;
1005 return Element
.Value
.Value
;
1007 Current
:= Element
.Next
;
1016 Src_Index
: Int
:= 0;
1017 In_Array
: Array_Element_Id
;
1018 Shared
: Shared_Project_Tree_Data_Access
;
1019 Force_Lower_Case_Index
: Boolean := False;
1020 Allow_Wildcards
: Boolean := False) return Variable_Value
1022 Current
: Array_Element_Id
;
1023 Element
: Array_Element
;
1024 Real_Index_1
: Name_Id
;
1025 Real_Index_2
: Name_Id
;
1028 Current
:= In_Array
;
1030 if Current
= No_Array_Element
then
1031 return Nil_Variable_Value
;
1034 Element
:= Shared
.Array_Elements
.Table
(Current
);
1036 Real_Index_1
:= Index
;
1038 if not Element
.Index_Case_Sensitive
or else Force_Lower_Case_Index
then
1039 if Index
/= All_Other_Names
then
1040 Get_Name_String
(Index
);
1041 To_Lower
(Name_Buffer
(1 .. Name_Len
));
1042 Real_Index_1
:= Name_Find
;
1046 while Current
/= No_Array_Element
loop
1047 Element
:= Shared
.Array_Elements
.Table
(Current
);
1048 Real_Index_2
:= Element
.Index
;
1050 if not Element
.Index_Case_Sensitive
1051 or else Force_Lower_Case_Index
1053 if Element
.Index
/= All_Other_Names
then
1054 Get_Name_String
(Element
.Index
);
1055 To_Lower
(Name_Buffer
(1 .. Name_Len
));
1056 Real_Index_2
:= Name_Find
;
1060 if Src_Index
= Element
.Src_Index
and then
1061 (Real_Index_1
= Real_Index_2
or else
1062 (Real_Index_2
/= All_Other_Names
and then
1063 Allow_Wildcards
and then
1064 Match
(Get_Name_String
(Real_Index_1
),
1065 Compile
(Get_Name_String
(Real_Index_2
),
1068 return Element
.Value
;
1070 Current
:= Element
.Next
;
1074 return Nil_Variable_Value
;
1080 Attribute_Or_Array_Name
: Name_Id
;
1081 In_Package
: Package_Id
;
1082 Shared
: Shared_Project_Tree_Data_Access
;
1083 Force_Lower_Case_Index
: Boolean := False;
1084 Allow_Wildcards
: Boolean := False) return Variable_Value
1086 The_Array
: Array_Element_Id
;
1087 The_Attribute
: Variable_Value
:= Nil_Variable_Value
;
1090 if In_Package
/= No_Package
then
1092 -- First, look if there is an array element that fits
1096 (Name
=> Attribute_Or_Array_Name
,
1097 In_Arrays
=> Shared
.Packages
.Table
(In_Package
).Decl
.Arrays
,
1103 In_Array
=> The_Array
,
1105 Force_Lower_Case_Index
=> Force_Lower_Case_Index
,
1106 Allow_Wildcards
=> Allow_Wildcards
);
1108 -- If there is no array element, look for a variable
1110 if The_Attribute
= Nil_Variable_Value
then
1113 (Variable_Name
=> Attribute_Or_Array_Name
,
1114 In_Variables
=> Shared
.Packages
.Table
1115 (In_Package
).Decl
.Attributes
,
1120 return The_Attribute
;
1126 In_Arrays
: Array_Id
;
1127 Shared
: Shared_Project_Tree_Data_Access
) return Name_Id
1130 The_Array
: Array_Data
;
1133 Current
:= In_Arrays
;
1134 while Current
/= No_Array
loop
1135 The_Array
:= Shared
.Arrays
.Table
(Current
);
1136 if The_Array
.Name
= In_Array
then
1138 (Index
, In_Array
=> The_Array
.Value
, Shared
=> Shared
);
1140 Current
:= The_Array
.Next
;
1149 In_Arrays
: Array_Id
;
1150 Shared
: Shared_Project_Tree_Data_Access
) return Array_Element_Id
1153 The_Array
: Array_Data
;
1156 Current
:= In_Arrays
;
1157 while Current
/= No_Array
loop
1158 The_Array
:= Shared
.Arrays
.Table
(Current
);
1160 if The_Array
.Name
= Name
then
1161 return The_Array
.Value
;
1163 Current
:= The_Array
.Next
;
1167 return No_Array_Element
;
1172 In_Packages
: Package_Id
;
1173 Shared
: Shared_Project_Tree_Data_Access
) return Package_Id
1175 Current
: Package_Id
;
1176 The_Package
: Package_Element
;
1179 Current
:= In_Packages
;
1180 while Current
/= No_Package
loop
1181 The_Package
:= Shared
.Packages
.Table
(Current
);
1182 exit when The_Package
.Name
/= No_Name
1183 and then The_Package
.Name
= Name
;
1184 Current
:= The_Package
.Next
;
1191 (Variable_Name
: Name_Id
;
1192 In_Variables
: Variable_Id
;
1193 Shared
: Shared_Project_Tree_Data_Access
) return Variable_Value
1195 Current
: Variable_Id
;
1196 The_Variable
: Variable
;
1199 Current
:= In_Variables
;
1200 while Current
/= No_Variable
loop
1201 The_Variable
:= Shared
.Variable_Elements
.Table
(Current
);
1203 if Variable_Name
= The_Variable
.Name
then
1204 return The_Variable
.Value
;
1206 Current
:= The_Variable
.Next
;
1210 return Nil_Variable_Value
;
1213 ----------------------------
1214 -- Write_Source_Info_File --
1215 ----------------------------
1217 procedure Write_Source_Info_File
(Tree
: Project_Tree_Ref
) is
1218 Iter
: Source_Iterator
:= For_Each_Source
(Tree
);
1219 Source
: Prj
.Source_Id
;
1223 if Opt
.Verbose_Mode
then
1224 Write_Line
("Writing new source info file " &
1225 Tree
.Source_Info_File_Name
.all);
1228 Create
(File
, Tree
.Source_Info_File_Name
.all);
1230 if not Is_Valid
(File
) then
1231 Write_Line
("warning: unable to create source info file """ &
1232 Tree
.Source_Info_File_Name
.all & '"');
1237 Source
:= Element
(Iter
);
1238 exit when Source
= No_Source
;
1240 if not Source
.Locally_Removed
and then
1241 Source
.Replaced_By
= No_Source
1245 Put_Line
(File
, Get_Name_String
(Source
.Project
.Name
));
1249 Put_Line
(File
, Get_Name_String
(Source
.Language
.Name
));
1253 Put_Line
(File
, Source
.Kind
'Img);
1255 -- Display path name
1257 Put_Line
(File
, Get_Name_String
(Source
.Path
.Display_Name
));
1263 if Source
.Path
.Name
/= Source
.Path
.Display_Name
then
1265 Put_Line
(File
, Get_Name_String
(Source
.Path
.Name
));
1270 if Source
.Unit
/= No_Unit_Index
then
1272 Put_Line
(File
, Get_Name_String
(Source
.Unit
.Name
));
1275 -- Multi-source index (I=)
1277 if Source
.Index
/= 0 then
1279 Put_Line
(File
, Source
.Index
'Img);
1282 -- Naming exception ("N=T");
1284 if Source
.Naming_Exception
= Yes
then
1285 Put_Line
(File
, "N=Y");
1287 elsif Source
.Naming_Exception
= Inherited
then
1288 Put_Line
(File
, "N=I");
1291 -- Empty line to indicate end of info on this source
1293 Put_Line
(File
, "");
1300 end Write_Source_Info_File
;
1308 Max_Length
: Positive;
1309 Separator
: Character)
1311 First
: Positive := S
'First;
1312 Last
: Natural := S
'Last;
1315 -- Nothing to do for empty strings
1317 if S
'Length > 0 then
1319 -- Start on a new line if current line is already longer than
1322 if Positive (Column
) >= Max_Length
then
1326 -- If length of remainder is longer than Max_Length, we need to
1327 -- cut the remainder in several lines.
1329 while Positive (Column
) + S
'Last - First
> Max_Length
loop
1331 -- Try the maximum length possible
1333 Last
:= First
+ Max_Length
- Positive (Column
);
1335 -- Look for last Separator in the line
1337 while Last
>= First
and then S
(Last
) /= Separator
loop
1341 -- If we do not find a separator, we output the maximum length
1344 if Last
< First
then
1345 Last
:= First
+ Max_Length
- Positive (Column
);
1348 Write_Line
(S
(First
.. Last
));
1350 -- Set the beginning of the new remainder
1355 -- What is left goes to the buffer, without EOL
1357 Write_Str
(S
(First
.. S
'Last));