* prerequisites.xml: Refer to GCC (instead of gcc) and GNU/Linux.
[official-gcc.git] / gcc / ada / prj-util.adb
blob9454f9ff418bf22a7114f508e4c98febc7c2f6e8
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- P R J . U T I L --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2001-2011, Free Software Foundation, Inc. --
10 -- --
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. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Ada.Unchecked_Deallocation;
28 with GNAT.Case_Util; use GNAT.Case_Util;
29 with GNAT.Regexp; use GNAT.Regexp;
31 with Osint; use Osint;
32 with Output; use Output;
33 with Opt;
34 with Prj.Com;
35 with Snames; use Snames;
36 with Table;
37 with Targparm; use Targparm;
39 with GNAT.HTable;
41 package body Prj.Util is
43 package Source_Info_Table is new Table.Table
44 (Table_Component_Type => Source_Info_Iterator,
45 Table_Index_Type => Natural,
46 Table_Low_Bound => 1,
47 Table_Initial => 10,
48 Table_Increment => 100,
49 Table_Name => "Makeutl.Source_Info_Table");
51 package Source_Info_Project_HTable is new GNAT.HTable.Simple_HTable
52 (Header_Num => Prj.Header_Num,
53 Element => Natural,
54 No_Element => 0,
55 Key => Name_Id,
56 Hash => Prj.Hash,
57 Equal => "=");
59 procedure Free is new Ada.Unchecked_Deallocation
60 (Text_File_Data, Text_File);
62 -----------
63 -- Close --
64 -----------
66 procedure Close (File : in out Text_File) is
67 Len : Integer;
68 Status : Boolean;
70 begin
71 if File = null then
72 Prj.Com.Fail ("Close attempted on an invalid Text_File");
73 end if;
75 if File.Out_File then
76 if File.Buffer_Len > 0 then
77 Len := Write (File.FD, File.Buffer'Address, File.Buffer_Len);
79 if Len /= File.Buffer_Len then
80 Prj.Com.Fail ("Unable to write to an out Text_File");
81 end if;
82 end if;
84 Close (File.FD, Status);
86 if not Status then
87 Prj.Com.Fail ("Unable to close an out Text_File");
88 end if;
90 else
92 -- Close in file, no need to test status, since this is a file that
93 -- we read, and the file was read successfully before we closed it.
95 Close (File.FD);
96 end if;
98 Free (File);
99 end Close;
101 ------------
102 -- Create --
103 ------------
105 procedure Create (File : out Text_File; Name : String) is
106 FD : File_Descriptor;
107 File_Name : String (1 .. Name'Length + 1);
109 begin
110 File_Name (1 .. Name'Length) := Name;
111 File_Name (File_Name'Last) := ASCII.NUL;
112 FD := Create_File (Name => File_Name'Address,
113 Fmode => GNAT.OS_Lib.Text);
115 if FD = Invalid_FD then
116 File := null;
118 else
119 File := new Text_File_Data;
120 File.FD := FD;
121 File.Out_File := True;
122 File.End_Of_File_Reached := True;
123 end if;
124 end Create;
126 ---------------
127 -- Duplicate --
128 ---------------
130 procedure Duplicate
131 (This : in out Name_List_Index;
132 Shared : Shared_Project_Tree_Data_Access)
134 Old_Current : Name_List_Index;
135 New_Current : Name_List_Index;
137 begin
138 if This /= No_Name_List then
139 Old_Current := This;
140 Name_List_Table.Increment_Last (Shared.Name_Lists);
141 New_Current := Name_List_Table.Last (Shared.Name_Lists);
142 This := New_Current;
143 Shared.Name_Lists.Table (New_Current) :=
144 (Shared.Name_Lists.Table (Old_Current).Name, No_Name_List);
146 loop
147 Old_Current := Shared.Name_Lists.Table (Old_Current).Next;
148 exit when Old_Current = No_Name_List;
149 Shared.Name_Lists.Table (New_Current).Next := New_Current + 1;
150 Name_List_Table.Increment_Last (Shared.Name_Lists);
151 New_Current := New_Current + 1;
152 Shared.Name_Lists.Table (New_Current) :=
153 (Shared.Name_Lists.Table (Old_Current).Name, No_Name_List);
154 end loop;
155 end if;
156 end Duplicate;
158 -----------------
159 -- End_Of_File --
160 -----------------
162 function End_Of_File (File : Text_File) return Boolean is
163 begin
164 if File = null then
165 Prj.Com.Fail ("End_Of_File attempted on an invalid Text_File");
166 end if;
168 return File.End_Of_File_Reached;
169 end End_Of_File;
171 -------------------
172 -- Executable_Of --
173 -------------------
175 function Executable_Of
176 (Project : Project_Id;
177 Shared : Shared_Project_Tree_Data_Access;
178 Main : File_Name_Type;
179 Index : Int;
180 Ada_Main : Boolean := True;
181 Language : String := "";
182 Include_Suffix : Boolean := True) return File_Name_Type
184 pragma Assert (Project /= No_Project);
186 The_Packages : constant Package_Id := Project.Decl.Packages;
188 Builder_Package : constant Prj.Package_Id :=
189 Prj.Util.Value_Of
190 (Name => Name_Builder,
191 In_Packages => The_Packages,
192 Shared => Shared);
194 Executable : Variable_Value :=
195 Prj.Util.Value_Of
196 (Name => Name_Id (Main),
197 Index => Index,
198 Attribute_Or_Array_Name => Name_Executable,
199 In_Package => Builder_Package,
200 Shared => Shared);
202 Lang : Language_Ptr;
204 Spec_Suffix : Name_Id := No_Name;
205 Body_Suffix : Name_Id := No_Name;
207 Spec_Suffix_Length : Natural := 0;
208 Body_Suffix_Length : Natural := 0;
210 procedure Get_Suffixes
211 (B_Suffix : File_Name_Type;
212 S_Suffix : File_Name_Type);
213 -- Get the non empty suffixes in variables Spec_Suffix and Body_Suffix
215 function Add_Suffix (File : File_Name_Type) return File_Name_Type;
216 -- Return the name of the executable, based on File, and adding the
217 -- executable suffix if needed
219 ------------------
220 -- Get_Suffixes --
221 ------------------
223 procedure Get_Suffixes
224 (B_Suffix : File_Name_Type;
225 S_Suffix : File_Name_Type)
227 begin
228 if B_Suffix /= No_File then
229 Body_Suffix := Name_Id (B_Suffix);
230 Body_Suffix_Length := Natural (Length_Of_Name (Body_Suffix));
231 end if;
233 if S_Suffix /= No_File then
234 Spec_Suffix := Name_Id (S_Suffix);
235 Spec_Suffix_Length := Natural (Length_Of_Name (Spec_Suffix));
236 end if;
237 end Get_Suffixes;
239 ----------------
240 -- Add_Suffix --
241 ----------------
243 function Add_Suffix (File : File_Name_Type) return File_Name_Type is
244 Saved_EEOT : constant Name_Id := Executable_Extension_On_Target;
245 Result : File_Name_Type;
246 Suffix_From_Project : Variable_Value;
247 begin
248 if Include_Suffix then
249 if Project.Config.Executable_Suffix /= No_Name then
250 Executable_Extension_On_Target :=
251 Project.Config.Executable_Suffix;
252 end if;
254 Result := Executable_Name (File);
255 Executable_Extension_On_Target := Saved_EEOT;
256 return Result;
258 elsif Builder_Package /= No_Package then
260 -- If the suffix is specified in the project itself, as opposed to
261 -- the config file, it needs to be taken into account. However,
262 -- when the project was processed, in both cases the suffix was
263 -- stored in Project.Config, so get it from the project again.
265 Suffix_From_Project :=
266 Prj.Util.Value_Of
267 (Variable_Name => Name_Executable_Suffix,
268 In_Variables =>
269 Shared.Packages.Table (Builder_Package).Decl.Attributes,
270 Shared => Shared);
272 if Suffix_From_Project /= Nil_Variable_Value
273 and then Suffix_From_Project.Value /= No_Name
274 then
275 Executable_Extension_On_Target := Suffix_From_Project.Value;
276 Result := Executable_Name (File);
277 Executable_Extension_On_Target := Saved_EEOT;
278 return Result;
279 end if;
280 end if;
282 return File;
283 end Add_Suffix;
285 -- Start of processing for Executable_Of
287 begin
288 if Ada_Main then
289 Lang := Get_Language_From_Name (Project, "ada");
290 elsif Language /= "" then
291 Lang := Get_Language_From_Name (Project, Language);
292 end if;
294 if Lang /= null then
295 Get_Suffixes
296 (B_Suffix => Lang.Config.Naming_Data.Body_Suffix,
297 S_Suffix => Lang.Config.Naming_Data.Spec_Suffix);
298 end if;
300 if Builder_Package /= No_Package then
301 if Executable = Nil_Variable_Value and then Ada_Main then
302 Get_Name_String (Main);
304 -- Try as index the name minus the implementation suffix or minus
305 -- the specification suffix.
307 declare
308 Name : constant String (1 .. Name_Len) :=
309 Name_Buffer (1 .. Name_Len);
310 Last : Positive := Name_Len;
312 Truncated : Boolean := False;
314 begin
315 if Body_Suffix /= No_Name
316 and then Last > Natural (Length_Of_Name (Body_Suffix))
317 and then Name (Last - Body_Suffix_Length + 1 .. Last) =
318 Get_Name_String (Body_Suffix)
319 then
320 Truncated := True;
321 Last := Last - Body_Suffix_Length;
322 end if;
324 if Spec_Suffix /= No_Name
325 and then not Truncated
326 and then Last > Spec_Suffix_Length
327 and then Name (Last - Spec_Suffix_Length + 1 .. Last) =
328 Get_Name_String (Spec_Suffix)
329 then
330 Truncated := True;
331 Last := Last - Spec_Suffix_Length;
332 end if;
334 if Truncated then
335 Name_Len := Last;
336 Name_Buffer (1 .. Name_Len) := Name (1 .. Last);
337 Executable :=
338 Prj.Util.Value_Of
339 (Name => Name_Find,
340 Index => 0,
341 Attribute_Or_Array_Name => Name_Executable,
342 In_Package => Builder_Package,
343 Shared => Shared);
344 end if;
345 end;
346 end if;
348 -- If we have found an Executable attribute, return its value,
349 -- possibly suffixed by the executable suffix.
351 if Executable /= Nil_Variable_Value
352 and then Executable.Value /= No_Name
353 and then Length_Of_Name (Executable.Value) /= 0
354 then
355 return Add_Suffix (File_Name_Type (Executable.Value));
356 end if;
357 end if;
359 Get_Name_String (Main);
361 -- If there is a body suffix or a spec suffix, remove this suffix,
362 -- otherwise remove any suffix ('.' followed by other characters), if
363 -- there is one.
365 if Body_Suffix /= No_Name
366 and then Name_Len > Body_Suffix_Length
367 and then Name_Buffer (Name_Len - Body_Suffix_Length + 1 .. Name_Len) =
368 Get_Name_String (Body_Suffix)
369 then
370 -- Found the body termination, remove it
372 Name_Len := Name_Len - Body_Suffix_Length;
374 elsif Spec_Suffix /= No_Name
375 and then Name_Len > Spec_Suffix_Length
376 and then
377 Name_Buffer (Name_Len - Spec_Suffix_Length + 1 .. Name_Len) =
378 Get_Name_String (Spec_Suffix)
379 then
380 -- Found the spec termination, remove it
382 Name_Len := Name_Len - Spec_Suffix_Length;
384 else
385 -- Remove any suffix, if there is one
387 Get_Name_String (Strip_Suffix (Main));
388 end if;
390 return Add_Suffix (Name_Find);
391 end Executable_Of;
393 --------------
394 -- Get_Line --
395 --------------
397 procedure Get_Line
398 (File : Text_File;
399 Line : out String;
400 Last : out Natural)
402 C : Character;
404 procedure Advance;
406 -------------
407 -- Advance --
408 -------------
410 procedure Advance is
411 begin
412 if File.Cursor = File.Buffer_Len then
413 File.Buffer_Len :=
414 Read
415 (FD => File.FD,
416 A => File.Buffer'Address,
417 N => File.Buffer'Length);
419 if File.Buffer_Len = 0 then
420 File.End_Of_File_Reached := True;
421 return;
422 else
423 File.Cursor := 1;
424 end if;
426 else
427 File.Cursor := File.Cursor + 1;
428 end if;
429 end Advance;
431 -- Start of processing for Get_Line
433 begin
434 if File = null then
435 Prj.Com.Fail ("Get_Line attempted on an invalid Text_File");
437 elsif File.Out_File then
438 Prj.Com.Fail ("Get_Line attempted on an out file");
439 end if;
441 Last := Line'First - 1;
443 if not File.End_Of_File_Reached then
444 loop
445 C := File.Buffer (File.Cursor);
446 exit when C = ASCII.CR or else C = ASCII.LF;
447 Last := Last + 1;
448 Line (Last) := C;
449 Advance;
451 if File.End_Of_File_Reached then
452 return;
453 end if;
455 exit when Last = Line'Last;
456 end loop;
458 if C = ASCII.CR or else C = ASCII.LF then
459 Advance;
461 if File.End_Of_File_Reached then
462 return;
463 end if;
464 end if;
466 if C = ASCII.CR
467 and then File.Buffer (File.Cursor) = ASCII.LF
468 then
469 Advance;
470 end if;
471 end if;
472 end Get_Line;
474 ----------------
475 -- Initialize --
476 ----------------
478 procedure Initialize
479 (Iter : out Source_Info_Iterator;
480 For_Project : Name_Id)
482 Ind : constant Natural := Source_Info_Project_HTable.Get (For_Project);
483 begin
484 if Ind = 0 then
485 Iter := (No_Source_Info, 0);
486 else
487 Iter := Source_Info_Table.Table (Ind);
488 end if;
489 end Initialize;
491 --------------
492 -- Is_Valid --
493 --------------
495 function Is_Valid (File : Text_File) return Boolean is
496 begin
497 return File /= null;
498 end Is_Valid;
500 ----------
501 -- Next --
502 ----------
504 procedure Next (Iter : in out Source_Info_Iterator) is
505 begin
506 if Iter.Next = 0 then
507 Iter.Info := No_Source_Info;
509 else
510 Iter := Source_Info_Table.Table (Iter.Next);
511 end if;
512 end Next;
514 ----------
515 -- Open --
516 ----------
518 procedure Open (File : out Text_File; Name : String) is
519 FD : File_Descriptor;
520 File_Name : String (1 .. Name'Length + 1);
522 begin
523 File_Name (1 .. Name'Length) := Name;
524 File_Name (File_Name'Last) := ASCII.NUL;
525 FD := Open_Read (Name => File_Name'Address,
526 Fmode => GNAT.OS_Lib.Text);
528 if FD = Invalid_FD then
529 File := null;
531 else
532 File := new Text_File_Data;
533 File.FD := FD;
534 File.Buffer_Len :=
535 Read (FD => FD,
536 A => File.Buffer'Address,
537 N => File.Buffer'Length);
539 if File.Buffer_Len = 0 then
540 File.End_Of_File_Reached := True;
541 else
542 File.Cursor := 1;
543 end if;
544 end if;
545 end Open;
547 ---------
548 -- Put --
549 ---------
551 procedure Put
552 (Into_List : in out Name_List_Index;
553 From_List : String_List_Id;
554 In_Tree : Project_Tree_Ref;
555 Lower_Case : Boolean := False)
557 Shared : constant Shared_Project_Tree_Data_Access := In_Tree.Shared;
559 Current_Name : Name_List_Index;
560 List : String_List_Id;
561 Element : String_Element;
562 Last : Name_List_Index :=
563 Name_List_Table.Last (Shared.Name_Lists);
564 Value : Name_Id;
566 begin
567 Current_Name := Into_List;
568 while Current_Name /= No_Name_List
569 and then Shared.Name_Lists.Table (Current_Name).Next /= No_Name_List
570 loop
571 Current_Name := Shared.Name_Lists.Table (Current_Name).Next;
572 end loop;
574 List := From_List;
575 while List /= Nil_String loop
576 Element := Shared.String_Elements.Table (List);
577 Value := Element.Value;
579 if Lower_Case then
580 Get_Name_String (Value);
581 To_Lower (Name_Buffer (1 .. Name_Len));
582 Value := Name_Find;
583 end if;
585 Name_List_Table.Append
586 (Shared.Name_Lists, (Name => Value, Next => No_Name_List));
588 Last := Last + 1;
590 if Current_Name = No_Name_List then
591 Into_List := Last;
592 else
593 Shared.Name_Lists.Table (Current_Name).Next := Last;
594 end if;
596 Current_Name := Last;
598 List := Element.Next;
599 end loop;
600 end Put;
602 procedure Put (File : Text_File; S : String) is
603 Len : Integer;
604 begin
605 if File = null then
606 Prj.Com.Fail ("Attempted to write on an invalid Text_File");
608 elsif not File.Out_File then
609 Prj.Com.Fail ("Attempted to write an in Text_File");
610 end if;
612 if File.Buffer_Len + S'Length > File.Buffer'Last then
613 -- Write buffer
614 Len := Write (File.FD, File.Buffer'Address, File.Buffer_Len);
616 if Len /= File.Buffer_Len then
617 Prj.Com.Fail ("Failed to write to an out Text_File");
618 end if;
620 File.Buffer_Len := 0;
621 end if;
623 File.Buffer (File.Buffer_Len + 1 .. File.Buffer_Len + S'Length) := S;
624 File.Buffer_Len := File.Buffer_Len + S'Length;
625 end Put;
627 --------------
628 -- Put_Line --
629 --------------
631 procedure Put_Line (File : Text_File; Line : String) is
632 L : String (1 .. Line'Length + 1);
633 begin
634 L (1 .. Line'Length) := Line;
635 L (L'Last) := ASCII.LF;
636 Put (File, L);
637 end Put_Line;
639 ---------------------------
640 -- Read_Source_Info_File --
641 ---------------------------
643 procedure Read_Source_Info_File (Tree : Project_Tree_Ref) is
644 File : Text_File;
645 Info : Source_Info_Iterator;
646 Proj : Name_Id;
648 procedure Report_Error;
650 ------------------
651 -- Report_Error --
652 ------------------
654 procedure Report_Error is
655 begin
656 Write_Line ("errors in source info file """ &
657 Tree.Source_Info_File_Name.all & '"');
658 Tree.Source_Info_File_Exists := False;
659 end Report_Error;
661 begin
662 Source_Info_Project_HTable.Reset;
663 Source_Info_Table.Init;
665 if Tree.Source_Info_File_Name = null then
666 Tree.Source_Info_File_Exists := False;
667 return;
668 end if;
670 Open (File, Tree.Source_Info_File_Name.all);
672 if not Is_Valid (File) then
673 if Opt.Verbose_Mode then
674 Write_Line ("source info file " & Tree.Source_Info_File_Name.all &
675 " does not exist");
676 end if;
678 Tree.Source_Info_File_Exists := False;
679 return;
680 end if;
682 Tree.Source_Info_File_Exists := True;
684 if Opt.Verbose_Mode then
685 Write_Line ("Reading source info file " &
686 Tree.Source_Info_File_Name.all);
687 end if;
689 Source_Loop :
690 while not End_Of_File (File) loop
691 Info := (new Source_Info_Data, 0);
692 Source_Info_Table.Increment_Last;
694 -- project name
695 Get_Line (File, Name_Buffer, Name_Len);
696 Proj := Name_Find;
697 Info.Info.Project := Proj;
698 Info.Next := Source_Info_Project_HTable.Get (Proj);
699 Source_Info_Project_HTable.Set (Proj, Source_Info_Table.Last);
701 if End_Of_File (File) then
702 Report_Error;
703 exit Source_Loop;
704 end if;
706 -- language name
707 Get_Line (File, Name_Buffer, Name_Len);
708 Info.Info.Language := Name_Find;
710 if End_Of_File (File) then
711 Report_Error;
712 exit Source_Loop;
713 end if;
715 -- kind
716 Get_Line (File, Name_Buffer, Name_Len);
717 Info.Info.Kind := Source_Kind'Value (Name_Buffer (1 .. Name_Len));
719 if End_Of_File (File) then
720 Report_Error;
721 exit Source_Loop;
722 end if;
724 -- display path name
725 Get_Line (File, Name_Buffer, Name_Len);
726 Info.Info.Display_Path_Name := Name_Find;
727 Info.Info.Path_Name := Info.Info.Display_Path_Name;
729 if End_Of_File (File) then
730 Report_Error;
731 exit Source_Loop;
732 end if;
734 -- optional fields
735 Option_Loop :
736 loop
737 Get_Line (File, Name_Buffer, Name_Len);
738 exit Option_Loop when Name_Len = 0;
740 if Name_Len <= 2 then
741 Report_Error;
742 exit Source_Loop;
744 else
745 if Name_Buffer (1 .. 2) = "P=" then
746 Name_Buffer (1 .. Name_Len - 2) :=
747 Name_Buffer (3 .. Name_Len);
748 Name_Len := Name_Len - 2;
749 Info.Info.Path_Name := Name_Find;
751 elsif Name_Buffer (1 .. 2) = "U=" then
752 Name_Buffer (1 .. Name_Len - 2) :=
753 Name_Buffer (3 .. Name_Len);
754 Name_Len := Name_Len - 2;
755 Info.Info.Unit_Name := Name_Find;
757 elsif Name_Buffer (1 .. 2) = "I=" then
758 Info.Info.Index := Int'Value (Name_Buffer (3 .. Name_Len));
760 elsif Name_Buffer (1 .. Name_Len) = "N=Y" then
761 Info.Info.Naming_Exception := Yes;
763 elsif Name_Buffer (1 .. Name_Len) = "N=I" then
764 Info.Info.Naming_Exception := Inherited;
766 else
767 Report_Error;
768 exit Source_Loop;
769 end if;
770 end if;
771 end loop Option_Loop;
773 Source_Info_Table.Table (Source_Info_Table.Last) := Info;
774 end loop Source_Loop;
776 Close (File);
778 exception
779 when others =>
780 Close (File);
781 Report_Error;
782 end Read_Source_Info_File;
784 --------------------
785 -- Source_Info_Of --
786 --------------------
788 function Source_Info_Of (Iter : Source_Info_Iterator) return Source_Info is
789 begin
790 return Iter.Info;
791 end Source_Info_Of;
793 --------------
794 -- Value_Of --
795 --------------
797 function Value_Of
798 (Variable : Variable_Value;
799 Default : String) return String
801 begin
802 if Variable.Kind /= Single
803 or else Variable.Default
804 or else Variable.Value = No_Name
805 then
806 return Default;
807 else
808 return Get_Name_String (Variable.Value);
809 end if;
810 end Value_Of;
812 function Value_Of
813 (Index : Name_Id;
814 In_Array : Array_Element_Id;
815 Shared : Shared_Project_Tree_Data_Access) return Name_Id
818 Current : Array_Element_Id;
819 Element : Array_Element;
820 Real_Index : Name_Id := Index;
822 begin
823 Current := In_Array;
825 if Current = No_Array_Element then
826 return No_Name;
827 end if;
829 Element := Shared.Array_Elements.Table (Current);
831 if not Element.Index_Case_Sensitive then
832 Get_Name_String (Index);
833 To_Lower (Name_Buffer (1 .. Name_Len));
834 Real_Index := Name_Find;
835 end if;
837 while Current /= No_Array_Element loop
838 Element := Shared.Array_Elements.Table (Current);
840 if Real_Index = Element.Index then
841 exit when Element.Value.Kind /= Single;
842 exit when Element.Value.Value = Empty_String;
843 return Element.Value.Value;
844 else
845 Current := Element.Next;
846 end if;
847 end loop;
849 return No_Name;
850 end Value_Of;
852 function Value_Of
853 (Index : Name_Id;
854 Src_Index : Int := 0;
855 In_Array : Array_Element_Id;
856 Shared : Shared_Project_Tree_Data_Access;
857 Force_Lower_Case_Index : Boolean := False;
858 Allow_Wildcards : Boolean := False) return Variable_Value
860 Current : Array_Element_Id;
861 Element : Array_Element;
862 Real_Index_1 : Name_Id;
863 Real_Index_2 : Name_Id;
865 begin
866 Current := In_Array;
868 if Current = No_Array_Element then
869 return Nil_Variable_Value;
870 end if;
872 Element := Shared.Array_Elements.Table (Current);
874 Real_Index_1 := Index;
876 if not Element.Index_Case_Sensitive or else Force_Lower_Case_Index then
877 if Index /= All_Other_Names then
878 Get_Name_String (Index);
879 To_Lower (Name_Buffer (1 .. Name_Len));
880 Real_Index_1 := Name_Find;
881 end if;
882 end if;
884 while Current /= No_Array_Element loop
885 Element := Shared.Array_Elements.Table (Current);
886 Real_Index_2 := Element.Index;
888 if not Element.Index_Case_Sensitive
889 or else Force_Lower_Case_Index
890 then
891 if Element.Index /= All_Other_Names then
892 Get_Name_String (Element.Index);
893 To_Lower (Name_Buffer (1 .. Name_Len));
894 Real_Index_2 := Name_Find;
895 end if;
896 end if;
898 if Src_Index = Element.Src_Index and then
899 (Real_Index_1 = Real_Index_2 or else
900 (Real_Index_2 /= All_Other_Names and then
901 Allow_Wildcards and then
902 Match (Get_Name_String (Real_Index_1),
903 Compile (Get_Name_String (Real_Index_2),
904 Glob => True))))
905 then
906 return Element.Value;
907 else
908 Current := Element.Next;
909 end if;
910 end loop;
912 return Nil_Variable_Value;
913 end Value_Of;
915 function Value_Of
916 (Name : Name_Id;
917 Index : Int := 0;
918 Attribute_Or_Array_Name : Name_Id;
919 In_Package : Package_Id;
920 Shared : Shared_Project_Tree_Data_Access;
921 Force_Lower_Case_Index : Boolean := False;
922 Allow_Wildcards : Boolean := False) return Variable_Value
924 The_Array : Array_Element_Id;
925 The_Attribute : Variable_Value := Nil_Variable_Value;
927 begin
928 if In_Package /= No_Package then
930 -- First, look if there is an array element that fits
932 The_Array :=
933 Value_Of
934 (Name => Attribute_Or_Array_Name,
935 In_Arrays => Shared.Packages.Table (In_Package).Decl.Arrays,
936 Shared => Shared);
937 The_Attribute :=
938 Value_Of
939 (Index => Name,
940 Src_Index => Index,
941 In_Array => The_Array,
942 Shared => Shared,
943 Force_Lower_Case_Index => Force_Lower_Case_Index,
944 Allow_Wildcards => Allow_Wildcards);
946 -- If there is no array element, look for a variable
948 if The_Attribute = Nil_Variable_Value then
949 The_Attribute :=
950 Value_Of
951 (Variable_Name => Attribute_Or_Array_Name,
952 In_Variables => Shared.Packages.Table
953 (In_Package).Decl.Attributes,
954 Shared => Shared);
955 end if;
956 end if;
958 return The_Attribute;
959 end Value_Of;
961 function Value_Of
962 (Index : Name_Id;
963 In_Array : Name_Id;
964 In_Arrays : Array_Id;
965 Shared : Shared_Project_Tree_Data_Access) return Name_Id
967 Current : Array_Id;
968 The_Array : Array_Data;
970 begin
971 Current := In_Arrays;
972 while Current /= No_Array loop
973 The_Array := Shared.Arrays.Table (Current);
974 if The_Array.Name = In_Array then
975 return Value_Of
976 (Index, In_Array => The_Array.Value, Shared => Shared);
977 else
978 Current := The_Array.Next;
979 end if;
980 end loop;
982 return No_Name;
983 end Value_Of;
985 function Value_Of
986 (Name : Name_Id;
987 In_Arrays : Array_Id;
988 Shared : Shared_Project_Tree_Data_Access) return Array_Element_Id
990 Current : Array_Id;
991 The_Array : Array_Data;
993 begin
994 Current := In_Arrays;
995 while Current /= No_Array loop
996 The_Array := Shared.Arrays.Table (Current);
998 if The_Array.Name = Name then
999 return The_Array.Value;
1000 else
1001 Current := The_Array.Next;
1002 end if;
1003 end loop;
1005 return No_Array_Element;
1006 end Value_Of;
1008 function Value_Of
1009 (Name : Name_Id;
1010 In_Packages : Package_Id;
1011 Shared : Shared_Project_Tree_Data_Access) return Package_Id
1013 Current : Package_Id;
1014 The_Package : Package_Element;
1016 begin
1017 Current := In_Packages;
1018 while Current /= No_Package loop
1019 The_Package := Shared.Packages.Table (Current);
1020 exit when The_Package.Name /= No_Name
1021 and then The_Package.Name = Name;
1022 Current := The_Package.Next;
1023 end loop;
1025 return Current;
1026 end Value_Of;
1028 function Value_Of
1029 (Variable_Name : Name_Id;
1030 In_Variables : Variable_Id;
1031 Shared : Shared_Project_Tree_Data_Access) return Variable_Value
1033 Current : Variable_Id;
1034 The_Variable : Variable;
1036 begin
1037 Current := In_Variables;
1038 while Current /= No_Variable loop
1039 The_Variable := Shared.Variable_Elements.Table (Current);
1041 if Variable_Name = The_Variable.Name then
1042 return The_Variable.Value;
1043 else
1044 Current := The_Variable.Next;
1045 end if;
1046 end loop;
1048 return Nil_Variable_Value;
1049 end Value_Of;
1051 ----------------------------
1052 -- Write_Source_Info_File --
1053 ----------------------------
1055 procedure Write_Source_Info_File (Tree : Project_Tree_Ref) is
1056 Iter : Source_Iterator := For_Each_Source (Tree);
1057 Source : Prj.Source_Id;
1058 File : Text_File;
1060 begin
1061 if Opt.Verbose_Mode then
1062 Write_Line ("Writing new source info file " &
1063 Tree.Source_Info_File_Name.all);
1064 end if;
1066 Create (File, Tree.Source_Info_File_Name.all);
1068 if not Is_Valid (File) then
1069 Write_Line ("warning: unable to create source info file """ &
1070 Tree.Source_Info_File_Name.all & '"');
1071 return;
1072 end if;
1074 loop
1075 Source := Element (Iter);
1076 exit when Source = No_Source;
1078 if not Source.Locally_Removed and then
1079 Source.Replaced_By = No_Source
1080 then
1081 -- Project name
1083 Put_Line (File, Get_Name_String (Source.Project.Name));
1085 -- Language name
1087 Put_Line (File, Get_Name_String (Source.Language.Name));
1089 -- Kind
1091 Put_Line (File, Source.Kind'Img);
1093 -- Display path name
1095 Put_Line (File, Get_Name_String (Source.Path.Display_Name));
1097 -- Optional lines:
1099 -- Path name (P=)
1101 if Source.Path.Name /= Source.Path.Display_Name then
1102 Put (File, "P=");
1103 Put_Line (File, Get_Name_String (Source.Path.Name));
1104 end if;
1106 -- Unit name (U=)
1108 if Source.Unit /= No_Unit_Index then
1109 Put (File, "U=");
1110 Put_Line (File, Get_Name_String (Source.Unit.Name));
1111 end if;
1113 -- Multi-source index (I=)
1115 if Source.Index /= 0 then
1116 Put (File, "I=");
1117 Put_Line (File, Source.Index'Img);
1118 end if;
1120 -- Naming exception ("N=T");
1122 if Source.Naming_Exception = Yes then
1123 Put_Line (File, "N=Y");
1125 elsif Source.Naming_Exception = Inherited then
1126 Put_Line (File, "N=I");
1127 end if;
1129 -- Empty line to indicate end of info on this source
1131 Put_Line (File, "");
1132 end if;
1134 Next (Iter);
1135 end loop;
1137 Close (File);
1138 end Write_Source_Info_File;
1140 ---------------
1141 -- Write_Str --
1142 ---------------
1144 procedure Write_Str
1145 (S : String;
1146 Max_Length : Positive;
1147 Separator : Character)
1149 First : Positive := S'First;
1150 Last : Natural := S'Last;
1152 begin
1153 -- Nothing to do for empty strings
1155 if S'Length > 0 then
1157 -- Start on a new line if current line is already longer than
1158 -- Max_Length.
1160 if Positive (Column) >= Max_Length then
1161 Write_Eol;
1162 end if;
1164 -- If length of remainder is longer than Max_Length, we need to
1165 -- cut the remainder in several lines.
1167 while Positive (Column) + S'Last - First > Max_Length loop
1169 -- Try the maximum length possible
1171 Last := First + Max_Length - Positive (Column);
1173 -- Look for last Separator in the line
1175 while Last >= First and then S (Last) /= Separator loop
1176 Last := Last - 1;
1177 end loop;
1179 -- If we do not find a separator, we output the maximum length
1180 -- possible.
1182 if Last < First then
1183 Last := First + Max_Length - Positive (Column);
1184 end if;
1186 Write_Line (S (First .. Last));
1188 -- Set the beginning of the new remainder
1190 First := Last + 1;
1191 end loop;
1193 -- What is left goes to the buffer, without EOL
1195 Write_Str (S (First .. S'Last));
1196 end if;
1197 end Write_Str;
1198 end Prj.Util;