1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
10 -- Copyright (C) 2000-2002 Free Software Foundation, Inc. --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
23 -- GNAT was originally developed by the GNAT team at New York University. --
24 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
26 ------------------------------------------------------------------------------
31 with Namet; use Namet;
32 with Osint; use Osint;
33 with Output; use Output;
34 with Prj.Com; use Prj.Com;
35 with Prj.Env; use Prj.Env;
36 with Prj.Util; use Prj.Util;
37 with Snames; use Snames;
38 with Stringt; use Stringt;
39 with Types; use Types;
41 with Ada.Characters.Handling; use Ada.Characters.Handling;
42 with Ada.Strings; use Ada.Strings;
43 with Ada.Strings.Fixed; use Ada.Strings.Fixed;
44 with Ada.Strings.Maps.Constants; use Ada.Strings.Maps.Constants;
46 with GNAT.Case_Util; use GNAT.Case_Util;
47 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
48 with GNAT.OS_Lib; use GNAT.OS_Lib;
50 package body Prj.Nmsc is
52 Dir_Sep : Character renames GNAT.OS_Lib.Directory_Separator;
54 Error_Report : Put_Line_Access := null;
55 Current_Project : Project_Id := No_Project;
57 procedure Check_Ada_Naming_Scheme (Naming : Naming_Data);
58 -- Check that the package Naming is correct.
60 procedure Check_Ada_Name
63 -- Check that a name is a valid Ada unit name.
65 procedure Error_Msg (Msg : String; Flag_Location : Source_Ptr);
66 -- Output an error message. If Error_Report is null, simply call
67 -- Errout.Error_Msg. Otherwise, disregard Flag_Location and use
70 function Get_Name_String (S : String_Id) return String;
71 -- Get the string from a String_Id
76 Unit_Name : out Name_Id;
77 Unit_Kind : out Spec_Or_Body;
78 Needs_Pragma : out Boolean);
79 -- Find out, from a file name, the unit name, the unit kind and if a
80 -- specific SFN pragma is needed. If the file name corresponds to no
81 -- unit, then Unit_Name will be No_Name.
83 function Is_Illegal_Suffix
85 Dot_Replacement_Is_A_Single_Dot : Boolean)
87 -- Returns True if the string Suffix cannot be used as
88 -- a spec suffix, a body suffix or a separate suffix.
90 procedure Record_Source
94 Data : in out Project_Data;
95 Location : Source_Ptr;
96 Current_Source : in out String_List_Id);
97 -- Put a unit in the list of units of a project, if the file name
98 -- corresponds to a valid unit name.
100 procedure Show_Source_Dirs (Project : Project_Id);
101 -- List all the source directories of a project.
103 function Locate_Directory
107 -- Locate a directory.
108 -- Returns No_Name if directory does not exist.
110 function Path_Name_Of
111 (File_Name : String_Id;
114 -- Returns the path name of a (non project) file.
115 -- Returns an empty string if file cannot be found.
122 (Project : Project_Id;
123 Report_Error : Put_Line_Access)
126 Languages : Variable_Value := Nil_Variable_Value;
128 procedure Check_Unit_Names (List : Array_Element_Id);
129 -- Check that a list of unit names contains only valid names.
131 procedure Find_Sources;
132 -- Find all the sources in all of the source directories
135 procedure Get_Path_Name_And_Record_Source
137 Location : Source_Ptr;
138 Current_Source : in out String_List_Id);
139 -- Find the path name of a source in the source directories and
140 -- record the source, if found.
142 procedure Get_Sources_From_File
144 Location : Source_Ptr);
145 -- Get the sources of a project from a text file
147 ----------------------
148 -- Check_Unit_Names --
149 ----------------------
151 procedure Check_Unit_Names (List : Array_Element_Id) is
152 Current : Array_Element_Id := List;
153 Element : Array_Element;
157 -- Loop through elements of the string list
159 while Current /= No_Array_Element loop
160 Element := Array_Elements.Table (Current);
162 -- Check that it contains a valid unit name
164 Check_Ada_Name (Element.Index, Unit_Name);
166 if Unit_Name = No_Name then
167 Errout.Error_Msg_Name_1 := Element.Index;
169 ("{ is not a valid unit name.",
170 Element.Value.Location);
173 if Current_Verbosity = High then
174 Write_Str (" Body_Part (""");
175 Write_Str (Get_Name_String (Unit_Name));
179 Element.Index := Unit_Name;
180 Array_Elements.Table (Current) := Element;
183 Current := Element.Next;
185 end Check_Unit_Names;
191 procedure Find_Sources is
192 Source_Dir : String_List_Id := Data.Source_Dirs;
193 Element : String_Element;
195 Current_Source : String_List_Id := Nil_String;
198 if Current_Verbosity = High then
199 Write_Line ("Looking for sources:");
202 -- For each subdirectory
204 while Source_Dir /= Nil_String loop
206 Element := String_Elements.Table (Source_Dir);
207 if Element.Value /= No_String then
209 Source_Directory : String
210 (1 .. Integer (String_Length (Element.Value)));
212 String_To_Name_Buffer (Element.Value);
213 Source_Directory := Name_Buffer (1 .. Name_Len);
214 if Current_Verbosity = High then
215 Write_Str ("Source_Dir = ");
216 Write_Line (Source_Directory);
219 -- We look to every entry in the source directory
221 Open (Dir, Source_Directory);
224 Read (Dir, Name_Buffer, Name_Len);
226 if Current_Verbosity = High then
227 Write_Str (" Checking ");
228 Write_Line (Name_Buffer (1 .. Name_Len));
231 exit when Name_Len = 0;
234 Path_Access : constant GNAT.OS_Lib.String_Access :=
236 (Name_Buffer (1 .. Name_Len),
243 -- If it is a regular file
245 if Path_Access /= null then
246 File_Name := Name_Find;
247 Name_Len := Path_Access'Length;
248 Name_Buffer (1 .. Name_Len) := Path_Access.all;
249 Path_Name := Name_Find;
251 -- We attempt to register it as a source.
252 -- However, there is no error if the file
253 -- does not contain a valid source.
254 -- But there is an error if we have a
255 -- duplicate unit name.
258 (File_Name => File_Name,
259 Path_Name => Path_Name,
262 Location => No_Location,
263 Current_Source => Current_Source);
266 if Current_Verbosity = High then
268 (" Not a regular file.");
279 when Directory_Error =>
283 Source_Dir := Element.Next;
286 if Current_Verbosity = High then
287 Write_Line ("end Looking for sources.");
290 -- If we have looked for sources and found none, then
291 -- it is an error. If a project is not supposed to contain
292 -- any source, then we never call Find_Sources.
294 if Current_Source = Nil_String then
295 Error_Msg ("there are no sources in this project",
300 -------------------------------------
301 -- Get_Path_Name_And_Record_Source --
302 -------------------------------------
304 procedure Get_Path_Name_And_Record_Source
306 Location : Source_Ptr;
307 Current_Source : in out String_List_Id)
309 Source_Dir : String_List_Id := Data.Source_Dirs;
310 Element : String_Element;
311 Path_Name : GNAT.OS_Lib.String_Access;
315 Found : Boolean := False;
316 Fname : String := File_Name;
319 Canonical_Case_File_Name (Fname);
320 Name_Len := Fname'Length;
321 Name_Buffer (1 .. Name_Len) := Fname;
324 if Current_Verbosity = High then
325 Write_Str (" Checking """);
330 -- We look in all source directories for this file name
332 while Source_Dir /= Nil_String loop
333 Element := String_Elements.Table (Source_Dir);
335 if Current_Verbosity = High then
337 Write_Str (Get_Name_String (Element.Value));
344 Get_Name_String (Element.Value));
346 if Path_Name /= null then
347 if Current_Verbosity = High then
351 Name_Len := Path_Name'Length;
352 Name_Buffer (1 .. Name_Len) := Path_Name.all;
355 -- Register the source if it is an Ada compilation unit..
362 Location => Location,
363 Current_Source => Current_Source);
368 if Current_Verbosity = High then
372 Source_Dir := Element.Next;
376 -- It is an error if a source file names in a source list or
377 -- in a source list file is not found.
380 Errout.Error_Msg_Name_1 := File;
381 Error_Msg ("source file { cannot be found", Location);
384 end Get_Path_Name_And_Record_Source;
386 ---------------------------
387 -- Get_Sources_From_File --
388 ---------------------------
390 procedure Get_Sources_From_File
392 Location : Source_Ptr)
394 File : Prj.Util.Text_File;
395 Line : String (1 .. 250);
397 Current_Source : String_List_Id := Nil_String;
400 if Current_Verbosity = High then
401 Write_Str ("Opening """);
408 Prj.Util.Open (File, Path);
410 if not Prj.Util.Is_Valid (File) then
411 Error_Msg ("file does not exist", Location);
413 while not Prj.Util.End_Of_File (File) loop
414 Prj.Util.Get_Line (File, Line, Last);
416 -- If the line is not empty and does not start with "--",
417 -- then it should contain a file name. However, if the
418 -- file name does not exist, it may be for another language
419 -- and we don't fail.
422 and then (Last = 1 or else Line (1 .. 2) /= "--")
424 Get_Path_Name_And_Record_Source
425 (File_Name => Line (1 .. Last),
426 Location => Location,
427 Current_Source => Current_Source);
431 Prj.Util.Close (File);
435 -- We should have found at least one source.
436 -- If not, report an error.
438 if Current_Source = Nil_String then
439 Error_Msg ("this project has no source", Location);
441 end Get_Sources_From_File;
443 -- Start of processing for Ada_Check
446 Language_Independent_Check (Project, Report_Error);
448 Error_Report := Report_Error;
449 Current_Project := Project;
451 Data := Projects.Table (Project);
452 Languages := Prj.Util.Value_Of (Name_Languages, Data.Decl.Attributes);
454 Data.Naming.Current_Language := Name_Ada;
455 Data.Sources_Present := Data.Source_Dirs /= Nil_String;
457 if not Languages.Default then
459 Current : String_List_Id := Languages.Values;
460 Element : String_Element;
461 Ada_Found : Boolean := False;
464 Look_For_Ada : while Current /= Nil_String loop
465 Element := String_Elements.Table (Current);
466 String_To_Name_Buffer (Element.Value);
467 To_Lower (Name_Buffer (1 .. Name_Len));
469 if Name_Buffer (1 .. Name_Len) = "ada" then
474 Current := Element.Next;
475 end loop Look_For_Ada;
477 if not Ada_Found then
479 -- Mark the project file as having no sources for Ada
481 Data.Sources_Present := False;
487 Naming_Id : constant Package_Id :=
488 Util.Value_Of (Name_Naming, Data.Decl.Packages);
490 Naming : Package_Element;
493 -- If there is a package Naming, we will put in Data.Naming
494 -- what is in this package Naming.
496 if Naming_Id /= No_Package then
497 Naming := Packages.Table (Naming_Id);
499 if Current_Verbosity = High then
500 Write_Line ("Checking ""Naming"" for Ada.");
504 Bodies : constant Array_Element_Id :=
506 (Name_Implementation, Naming.Decl.Arrays);
508 Specifications : constant Array_Element_Id :=
510 (Name_Specification, Naming.Decl.Arrays);
513 if Bodies /= No_Array_Element then
515 -- We have elements in the array Body_Part
517 if Current_Verbosity = High then
518 Write_Line ("Found Bodies.");
521 Data.Naming.Bodies := Bodies;
522 Check_Unit_Names (Bodies);
525 if Current_Verbosity = High then
526 Write_Line ("No Bodies.");
530 if Specifications /= No_Array_Element then
532 -- We have elements in the array Specification
534 if Current_Verbosity = High then
535 Write_Line ("Found Specifications.");
538 Data.Naming.Specifications := Specifications;
539 Check_Unit_Names (Specifications);
542 if Current_Verbosity = High then
543 Write_Line ("No Specifications.");
548 -- We are now checking if variables Dot_Replacement, Casing,
549 -- Specification_Append, Body_Append and/or Separate_Append
552 -- For each variable, if it does not exist, we do nothing,
553 -- because we already have the default.
555 -- Check Dot_Replacement
558 Dot_Replacement : constant Variable_Value :=
560 (Name_Dot_Replacement,
561 Naming.Decl.Attributes);
564 pragma Assert (Dot_Replacement.Kind = Single,
565 "Dot_Replacement is not a single string");
567 if not Dot_Replacement.Default then
569 String_To_Name_Buffer (Dot_Replacement.Value);
572 Error_Msg ("Dot_Replacement cannot be empty",
573 Dot_Replacement.Location);
576 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
577 Data.Naming.Dot_Replacement := Name_Find;
578 Data.Naming.Dot_Repl_Loc := Dot_Replacement.Location;
585 if Current_Verbosity = High then
586 Write_Str (" Dot_Replacement = """);
587 Write_Str (Get_Name_String (Data.Naming.Dot_Replacement));
595 Casing_String : constant Variable_Value :=
596 Util.Value_Of (Name_Casing, Naming.Decl.Attributes);
599 pragma Assert (Casing_String.Kind = Single,
600 "Casing is not a single string");
602 if not Casing_String.Default then
604 Casing_Image : constant String :=
605 Get_Name_String (Casing_String.Value);
609 Casing : constant Casing_Type :=
610 Value (Casing_Image);
613 Data.Naming.Casing := Casing;
617 when Constraint_Error =>
618 if Casing_Image'Length = 0 then
619 Error_Msg ("Casing cannot be an empty string",
620 Casing_String.Location);
623 Name_Len := Casing_Image'Length;
624 Name_Buffer (1 .. Name_Len) := Casing_Image;
625 Errout.Error_Msg_Name_1 := Name_Find;
627 ("{ is not a correct Casing",
628 Casing_String.Location);
634 if Current_Verbosity = High then
635 Write_Str (" Casing = ");
636 Write_Str (Image (Data.Naming.Casing));
641 -- Check Specification_Suffix
644 Ada_Spec_Suffix : constant Variable_Value :=
647 In_Array => Data.Naming.Specification_Suffix);
650 if Ada_Spec_Suffix.Kind = Single
651 and then String_Length (Ada_Spec_Suffix.Value) /= 0
653 String_To_Name_Buffer (Ada_Spec_Suffix.Value);
654 Data.Naming.Current_Spec_Suffix := Name_Find;
655 Data.Naming.Spec_Suffix_Loc := Ada_Spec_Suffix.Location;
658 Data.Naming.Current_Spec_Suffix := Default_Ada_Spec_Suffix;
662 if Current_Verbosity = High then
663 Write_Str (" Specification_Suffix = """);
664 Write_Str (Get_Name_String (Data.Naming.Current_Spec_Suffix));
669 -- Check Implementation_Suffix
672 Ada_Impl_Suffix : constant Variable_Value :=
675 In_Array => Data.Naming.Implementation_Suffix);
678 if Ada_Impl_Suffix.Kind = Single
679 and then String_Length (Ada_Impl_Suffix.Value) /= 0
681 String_To_Name_Buffer (Ada_Impl_Suffix.Value);
682 Data.Naming.Current_Impl_Suffix := Name_Find;
683 Data.Naming.Impl_Suffix_Loc := Ada_Impl_Suffix.Location;
686 Data.Naming.Current_Impl_Suffix := Default_Ada_Impl_Suffix;
690 if Current_Verbosity = High then
691 Write_Str (" Implementation_Suffix = """);
692 Write_Str (Get_Name_String (Data.Naming.Current_Impl_Suffix));
697 -- Check Separate_Suffix
700 Ada_Sep_Suffix : constant Variable_Value :=
702 (Variable_Name => Name_Separate_Suffix,
703 In_Variables => Naming.Decl.Attributes);
705 if Ada_Sep_Suffix.Default then
706 Data.Naming.Separate_Suffix :=
707 Data.Naming.Current_Impl_Suffix;
710 String_To_Name_Buffer (Ada_Sep_Suffix.Value);
713 Error_Msg ("Separate_Suffix cannot be empty",
714 Ada_Sep_Suffix.Location);
717 Data.Naming.Separate_Suffix := Name_Find;
718 Data.Naming.Sep_Suffix_Loc := Ada_Sep_Suffix.Location;
725 if Current_Verbosity = High then
726 Write_Str (" Separate_Suffix = """);
727 Write_Str (Get_Name_String (Data.Naming.Separate_Suffix));
732 -- Check if Data.Naming is valid
734 Check_Ada_Naming_Scheme (Data.Naming);
737 Data.Naming.Current_Spec_Suffix := Default_Ada_Spec_Suffix;
738 Data.Naming.Current_Impl_Suffix := Default_Ada_Impl_Suffix;
739 Data.Naming.Separate_Suffix := Default_Ada_Impl_Suffix;
743 -- If we have source directories, then find the sources
745 if Data.Sources_Present then
746 if Data.Source_Dirs = Nil_String then
747 Data.Sources_Present := False;
751 Sources : constant Variable_Value :=
754 Data.Decl.Attributes);
756 Source_List_File : constant Variable_Value :=
758 (Name_Source_List_File,
759 Data.Decl.Attributes);
763 (Sources.Kind = List,
764 "Source_Files is not a list");
766 (Source_List_File.Kind = Single,
767 "Source_List_File is not a single string");
769 if not Sources.Default then
770 if not Source_List_File.Default then
772 ("?both variables source_files and " &
773 "source_list_file are present",
774 Source_List_File.Location);
777 -- Sources is a list of file names
780 Current_Source : String_List_Id := Nil_String;
781 Current : String_List_Id := Sources.Values;
782 Element : String_Element;
785 Data.Sources_Present := Current /= Nil_String;
787 while Current /= Nil_String loop
788 Element := String_Elements.Table (Current);
789 String_To_Name_Buffer (Element.Value);
792 File_Name : constant String :=
793 Name_Buffer (1 .. Name_Len);
796 Get_Path_Name_And_Record_Source
797 (File_Name => File_Name,
798 Location => Element.Location,
799 Current_Source => Current_Source);
800 Current := Element.Next;
805 -- No source_files specified.
806 -- We check Source_List_File has been specified.
808 elsif not Source_List_File.Default then
810 -- Source_List_File is the name of the file
811 -- that contains the source file names
814 Source_File_Path_Name : constant String :=
816 (Source_List_File.Value,
820 if Source_File_Path_Name'Length = 0 then
821 String_To_Name_Buffer (Source_List_File.Value);
822 Errout.Error_Msg_Name_1 := Name_Find;
824 ("file with sources { does not exist",
825 Source_List_File.Location);
828 Get_Sources_From_File
829 (Source_File_Path_Name,
830 Source_List_File.Location);
835 -- Neither Source_Files nor Source_List_File has been
837 -- Find all the files that satisfy
838 -- the naming scheme in all the source directories.
846 Projects.Table (Project) := Data;
853 procedure Check_Ada_Name
857 The_Name : String := Get_Name_String (Name);
858 Need_Letter : Boolean := True;
859 Last_Underscore : Boolean := False;
860 OK : Boolean := The_Name'Length > 0;
863 for Index in The_Name'Range loop
866 -- We need a letter (at the beginning, and following a dot),
867 -- but we don't have one.
869 if Is_Letter (The_Name (Index)) then
870 Need_Letter := False;
875 if Current_Verbosity = High then
876 Write_Int (Types.Int (Index));
878 Write_Char (The_Name (Index));
879 Write_Line ("' is not a letter.");
885 elsif Last_Underscore
886 and then (The_Name (Index) = '_' or else The_Name (Index) = '.')
888 -- Two underscores are illegal, and a dot cannot follow
893 if Current_Verbosity = High then
894 Write_Int (Types.Int (Index));
896 Write_Char (The_Name (Index));
897 Write_Line ("' is illegal here.");
902 elsif The_Name (Index) = '.' then
904 -- We need a letter after a dot
908 elsif The_Name (Index) = '_' then
909 Last_Underscore := True;
912 -- We need an letter or a digit
914 Last_Underscore := False;
916 if not Is_Alphanumeric (The_Name (Index)) then
919 if Current_Verbosity = High then
920 Write_Int (Types.Int (Index));
922 Write_Char (The_Name (Index));
923 Write_Line ("' is not alphanumeric.");
931 -- Cannot end with an underscore or a dot
933 OK := OK and then not Need_Letter and then not Last_Underscore;
938 -- Signal a problem with No_Name
944 -----------------------------
945 -- Check_Ada_Naming_Scheme --
946 -----------------------------
948 procedure Check_Ada_Naming_Scheme (Naming : Naming_Data) is
950 -- Only check if we are not using the standard naming scheme
952 if Naming /= Standard_Naming_Data then
954 Dot_Replacement : constant String :=
956 (Naming.Dot_Replacement);
958 Specification_Suffix : constant String :=
960 (Naming.Current_Spec_Suffix);
962 Implementation_Suffix : constant String :=
964 (Naming.Current_Impl_Suffix);
966 Separate_Suffix : constant String :=
968 (Naming.Separate_Suffix);
971 -- Dot_Replacement cannot
973 -- - start or end with an alphanumeric
975 -- - start with an '_' followed by an alphanumeric
976 -- - contain a '.' except if it is "."
978 if Dot_Replacement'Length = 0
979 or else Is_Alphanumeric
980 (Dot_Replacement (Dot_Replacement'First))
981 or else Is_Alphanumeric
982 (Dot_Replacement (Dot_Replacement'Last))
983 or else (Dot_Replacement (Dot_Replacement'First) = '_'
985 (Dot_Replacement'Length = 1
988 (Dot_Replacement (Dot_Replacement'First + 1))))
989 or else (Dot_Replacement'Length > 1
991 Index (Source => Dot_Replacement,
992 Pattern => ".") /= 0)
995 ('"' & Dot_Replacement &
996 """ is illegal for Dot_Replacement.",
997 Naming.Dot_Repl_Loc);
1002 -- - start with an alphanumeric
1003 -- - start with an '_' followed by an alphanumeric
1005 if Is_Illegal_Suffix
1006 (Specification_Suffix, Dot_Replacement = ".")
1008 Errout.Error_Msg_Name_1 := Naming.Current_Spec_Suffix;
1010 ("{ is illegal for Specification_Suffix",
1011 Naming.Spec_Suffix_Loc);
1014 if Is_Illegal_Suffix
1015 (Implementation_Suffix, Dot_Replacement = ".")
1017 Errout.Error_Msg_Name_1 := Naming.Current_Impl_Suffix;
1019 ("{ is illegal for Implementation_Suffix",
1020 Naming.Impl_Suffix_Loc);
1023 if Implementation_Suffix /= Separate_Suffix then
1024 if Is_Illegal_Suffix
1025 (Separate_Suffix, Dot_Replacement = ".")
1027 Errout.Error_Msg_Name_1 := Naming.Separate_Suffix;
1029 ("{ is illegal for Separate_Suffix",
1030 Naming.Sep_Suffix_Loc);
1034 -- Specification_Suffix cannot have the same termination as
1035 -- Implementation_Suffix or Separate_Suffix
1037 if Specification_Suffix'Length <= Implementation_Suffix'Length
1039 Implementation_Suffix (Implementation_Suffix'Last -
1040 Specification_Suffix'Length + 1 ..
1041 Implementation_Suffix'Last) = Specification_Suffix
1044 ("Implementation_Suffix (""" &
1045 Implementation_Suffix &
1046 """) cannot end with" &
1047 "Specification_Suffix (""" &
1048 Specification_Suffix & """).",
1049 Naming.Impl_Suffix_Loc);
1052 if Specification_Suffix'Length <= Separate_Suffix'Length
1055 (Separate_Suffix'Last - Specification_Suffix'Length + 1
1057 Separate_Suffix'Last) = Specification_Suffix
1060 ("Separate_Suffix (""" &
1062 """) cannot end with" &
1063 " Specification_Suffix (""" &
1064 Specification_Suffix & """).",
1065 Naming.Sep_Suffix_Loc);
1070 end Check_Ada_Naming_Scheme;
1076 procedure Error_Msg (Msg : String; Flag_Location : Source_Ptr) is
1078 Error_Buffer : String (1 .. 5_000);
1079 Error_Last : Natural := 0;
1080 Msg_Name : Natural := 0;
1081 First : Positive := Msg'First;
1083 procedure Add (C : Character);
1084 -- Add a character to the buffer
1086 procedure Add (S : String);
1087 -- Add a string to the buffer
1089 procedure Add (Id : Name_Id);
1090 -- Add a name to the buffer
1096 procedure Add (C : Character) is
1098 Error_Last := Error_Last + 1;
1099 Error_Buffer (Error_Last) := C;
1102 procedure Add (S : String) is
1104 Error_Buffer (Error_Last + 1 .. Error_Last + S'Length) := S;
1105 Error_Last := Error_Last + S'Length;
1108 procedure Add (Id : Name_Id) is
1110 Get_Name_String (Id);
1111 Add (Name_Buffer (1 .. Name_Len));
1114 -- Start of processing for Error_Msg
1117 if Error_Report = null then
1118 Errout.Error_Msg (Msg, Flag_Location);
1122 if Msg (First) = '\' then
1124 -- Continuation character, ignore.
1128 elsif Msg (First) = '?' then
1130 -- Warning character. It is always the first one,
1137 for Index in First .. Msg'Last loop
1138 if Msg (Index) = '{' or else Msg (Index) = '%' then
1140 -- Include a name between double quotes.
1142 Msg_Name := Msg_Name + 1;
1146 when 1 => Add (Errout.Error_Msg_Name_1);
1147 when 2 => Add (Errout.Error_Msg_Name_2);
1148 when 3 => Add (Errout.Error_Msg_Name_3);
1150 when others => null;
1161 Error_Report (Error_Buffer (1 .. Error_Last), Current_Project);
1164 ---------------------
1165 -- Get_Name_String --
1166 ---------------------
1168 function Get_Name_String (S : String_Id) return String is
1170 if S = No_String then
1173 String_To_Name_Buffer (S);
1174 return Name_Buffer (1 .. Name_Len);
1176 end Get_Name_String;
1183 (File_Name : Name_Id;
1184 Naming : Naming_Data;
1185 Unit_Name : out Name_Id;
1186 Unit_Kind : out Spec_Or_Body;
1187 Needs_Pragma : out Boolean)
1189 Canonical_Case_Name : Name_Id;
1192 Needs_Pragma := False;
1193 Get_Name_String (File_Name);
1194 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1195 Canonical_Case_Name := Name_Find;
1197 if Naming.Bodies /= No_Array_Element then
1199 -- There are some specified file names for some bodies
1200 -- of this project. Find out if File_Name is one of these bodies.
1203 Current : Array_Element_Id := Naming.Bodies;
1204 Element : Array_Element;
1207 while Current /= No_Array_Element loop
1208 Element := Array_Elements.Table (Current);
1210 if Element.Index /= No_Name then
1211 String_To_Name_Buffer (Element.Value.Value);
1212 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1214 if Canonical_Case_Name = Name_Find then
1216 -- File_Name corresponds to one body.
1217 -- So, we know it is a body, and we know the unit name.
1219 Unit_Kind := Body_Part;
1220 Unit_Name := Element.Index;
1221 Needs_Pragma := True;
1226 Current := Element.Next;
1231 if Naming.Specifications /= No_Array_Element then
1233 -- There are some specified file names for some bodiesspecifications
1234 -- of this project. Find out if File_Name is one of these
1238 Current : Array_Element_Id := Naming.Specifications;
1239 Element : Array_Element;
1242 while Current /= No_Array_Element loop
1243 Element := Array_Elements.Table (Current);
1245 if Element.Index /= No_Name then
1246 String_To_Name_Buffer (Element.Value.Value);
1247 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1249 if Canonical_Case_Name = Name_Find then
1251 -- File_Name corresponds to one specification.
1252 -- So, we know it is a spec, and we know the unit name.
1254 Unit_Kind := Specification;
1255 Unit_Name := Element.Index;
1256 Needs_Pragma := True;
1262 Current := Element.Next;
1268 File : String := Get_Name_String (Canonical_Case_Name);
1269 First : Positive := File'First;
1270 Last : Natural := File'Last;
1272 Standard_GNAT : Boolean :=
1273 Naming.Current_Spec_Suffix =
1274 Default_Ada_Spec_Suffix
1276 Naming.Current_Impl_Suffix =
1277 Default_Ada_Impl_Suffix;
1280 -- Check if the end of the file name is Specification_Append
1282 Get_Name_String (Naming.Current_Spec_Suffix);
1284 if File'Length > Name_Len
1285 and then File (Last - Name_Len + 1 .. Last) =
1286 Name_Buffer (1 .. Name_Len)
1290 Unit_Kind := Specification;
1291 Last := Last - Name_Len;
1293 if Current_Verbosity = High then
1294 Write_Str (" Specification: ");
1295 Write_Line (File (First .. Last));
1299 Get_Name_String (Naming.Current_Impl_Suffix);
1301 -- Check if the end of the file name is Body_Append
1303 if File'Length > Name_Len
1304 and then File (Last - Name_Len + 1 .. Last) =
1305 Name_Buffer (1 .. Name_Len)
1309 Unit_Kind := Body_Part;
1310 Last := Last - Name_Len;
1312 if Current_Verbosity = High then
1313 Write_Str (" Body: ");
1314 Write_Line (File (First .. Last));
1317 elsif Naming.Separate_Suffix /= Naming.Current_Spec_Suffix then
1318 Get_Name_String (Naming.Separate_Suffix);
1320 -- Check if the end of the file name is Separate_Append
1322 if File'Length > Name_Len
1323 and then File (Last - Name_Len + 1 .. Last) =
1324 Name_Buffer (1 .. Name_Len)
1326 -- We have a separate (a body)
1328 Unit_Kind := Body_Part;
1329 Last := Last - Name_Len;
1331 if Current_Verbosity = High then
1332 Write_Str (" Separate: ");
1333 Write_Line (File (First .. Last));
1347 -- This is not a source file
1349 Unit_Name := No_Name;
1350 Unit_Kind := Specification;
1352 if Current_Verbosity = High then
1353 Write_Line (" Not a valid file name.");
1359 Get_Name_String (Naming.Dot_Replacement);
1361 Standard_GNAT and then Name_Buffer (1 .. Name_Len) = "-";
1363 if Name_Buffer (1 .. Name_Len) /= "." then
1365 -- If Dot_Replacement is not a single dot,
1366 -- then there should not be any dot in the name.
1368 for Index in First .. Last loop
1369 if File (Index) = '.' then
1370 if Current_Verbosity = High then
1372 (" Not a valid file name (some dot not replaced).");
1375 Unit_Name := No_Name;
1381 -- Replace the substring Dot_Replacement with dots
1384 Index : Positive := First;
1387 while Index <= Last - Name_Len + 1 loop
1389 if File (Index .. Index + Name_Len - 1) =
1390 Name_Buffer (1 .. Name_Len)
1392 File (Index) := '.';
1394 if Name_Len > 1 and then Index < Last then
1395 File (Index + 1 .. Last - Name_Len + 1) :=
1396 File (Index + Name_Len .. Last);
1399 Last := Last - Name_Len + 1;
1407 -- Check if the casing is right
1410 Src : String := File (First .. Last);
1413 case Naming.Casing is
1414 when All_Lower_Case =>
1417 Mapping => Lower_Case_Map);
1419 when All_Upper_Case =>
1422 Mapping => Upper_Case_Map);
1424 when Mixed_Case | Unknown =>
1428 if Src /= File (First .. Last) then
1429 if Current_Verbosity = High then
1430 Write_Line (" Not a valid file name (casing).");
1433 Unit_Name := No_Name;
1437 -- We put the name in lower case
1441 Mapping => Lower_Case_Map);
1443 -- In the standard GNAT naming scheme, check for special cases:
1444 -- children or separates of A, G, I or S, and run time sources.
1446 if Standard_GNAT and then Src'Length >= 3 then
1448 S1 : constant Character := Src (Src'First);
1449 S2 : constant Character := Src (Src'First + 1);
1452 if S1 = 'a' or else S1 = 'g'
1453 or else S1 = 'i' or else S1 = 's'
1455 -- Children or separates of packages A, G, I or S
1457 if (Hostparm.OpenVMS and then S2 = '$')
1458 or else (not Hostparm.OpenVMS and then S2 = '~')
1460 Src (Src'First + 1) := '.';
1462 -- If it is potentially a run time source, disable
1463 -- filling of the mapping file to avoid warnings.
1466 Set_Mapping_File_Initial_State_To_Empty;
1473 if Current_Verbosity = High then
1478 Name_Len := Src'Length;
1479 Name_Buffer (1 .. Name_Len) := Src;
1481 -- Now, we check if this name is a valid unit name
1483 Check_Ada_Name (Name => Name_Find, Unit => Unit_Name);
1490 -----------------------
1491 -- Is_Illegal_Suffix --
1492 -----------------------
1494 function Is_Illegal_Suffix
1496 Dot_Replacement_Is_A_Single_Dot : Boolean)
1500 if Suffix'Length = 0
1501 or else Is_Alphanumeric (Suffix (Suffix'First))
1502 or else Index (Suffix, ".") = 0
1503 or else (Suffix'Length >= 2
1504 and then Suffix (Suffix'First) = '_'
1505 and then Is_Alphanumeric (Suffix (Suffix'First + 1)))
1510 -- If dot replacement is a single dot, and first character of
1511 -- suffix is also a dot
1513 if Dot_Replacement_Is_A_Single_Dot
1514 and then Suffix (Suffix'First) = '.'
1516 for Index in Suffix'First + 1 .. Suffix'Last loop
1518 -- If there is another dot
1520 if Suffix (Index) = '.' then
1522 -- It is illegal to have a letter following the initial dot
1524 return Is_Letter (Suffix (Suffix'First + 1));
1532 end Is_Illegal_Suffix;
1534 --------------------------------
1535 -- Language_Independent_Check --
1536 --------------------------------
1538 procedure Language_Independent_Check
1539 (Project : Project_Id;
1540 Report_Error : Put_Line_Access)
1542 Last_Source_Dir : String_List_Id := Nil_String;
1543 Data : Project_Data := Projects.Table (Project);
1545 procedure Find_Source_Dirs (From : String_Id; Location : Source_Ptr);
1546 -- Find one or several source directories, and add them
1547 -- to the list of source directories of the project.
1549 ----------------------
1550 -- Find_Source_Dirs --
1551 ----------------------
1553 procedure Find_Source_Dirs (From : String_Id; Location : Source_Ptr) is
1555 Directory : String (1 .. Integer (String_Length (From)));
1556 Directory_Id : Name_Id;
1557 Element : String_Element;
1559 procedure Recursive_Find_Dirs (Path : String_Id);
1560 -- Find all the subdirectories (recursively) of Path
1561 -- and add them to the list of source directories
1564 -------------------------
1565 -- Recursive_Find_Dirs --
1566 -------------------------
1568 procedure Recursive_Find_Dirs (Path : String_Id) is
1570 Name : String (1 .. 250);
1572 The_Path : String := Get_Name_String (Path) & Dir_Sep;
1574 The_Path_Last : Positive := The_Path'Last;
1577 if The_Path'Length > 1
1579 (The_Path (The_Path_Last - 1) = Dir_Sep
1580 or else The_Path (The_Path_Last - 1) = '/')
1582 The_Path_Last := The_Path_Last - 1;
1585 Canonical_Case_File_Name (The_Path);
1587 if Current_Verbosity = High then
1589 Write_Line (The_Path (The_Path'First .. The_Path_Last));
1592 String_Elements.Increment_Last;
1595 Location => No_Location,
1596 Next => Nil_String);
1598 -- Case of first source directory
1600 if Last_Source_Dir = Nil_String then
1601 Data.Source_Dirs := String_Elements.Last;
1603 -- Here we already have source directories.
1606 -- Link the previous last to the new one
1608 String_Elements.Table (Last_Source_Dir).Next :=
1609 String_Elements.Last;
1612 -- And register this source directory as the new last
1614 Last_Source_Dir := String_Elements.Last;
1615 String_Elements.Table (Last_Source_Dir) := Element;
1617 -- Now look for subdirectories
1619 Open (Dir, The_Path (The_Path'First .. The_Path_Last));
1622 Read (Dir, Name, Last);
1625 if Current_Verbosity = High then
1626 Write_Str (" Checking ");
1627 Write_Line (Name (1 .. Last));
1630 if Name (1 .. Last) /= "."
1631 and then Name (1 .. Last) /= ".."
1636 Path_Name : String :=
1637 The_Path (The_Path'First .. The_Path_Last) &
1641 Canonical_Case_File_Name (Path_Name);
1643 if Is_Directory (Path_Name) then
1645 -- We have found a new subdirectory,
1646 -- register it and find its own subdirectories.
1649 Store_String_Chars (Path_Name);
1650 Recursive_Find_Dirs (End_String);
1659 when Directory_Error =>
1661 end Recursive_Find_Dirs;
1663 -- Start of processing for Find_Source_Dirs
1666 if Current_Verbosity = High then
1667 Write_Str ("Find_Source_Dirs (""");
1670 String_To_Name_Buffer (From);
1671 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1672 Directory := Name_Buffer (1 .. Name_Len);
1673 Directory_Id := Name_Find;
1675 if Current_Verbosity = High then
1676 Write_Str (Directory);
1680 -- First, check if we are looking for a directory tree,
1681 -- indicated by "/**" at the end.
1683 if Directory'Length >= 3
1684 and then Directory (Directory'Last - 1 .. Directory'Last) = "**"
1685 and then (Directory (Directory'Last - 2) = '/'
1687 Directory (Directory'Last - 2) = Dir_Sep)
1689 Name_Len := Directory'Length - 3;
1691 if Name_Len = 0 then
1692 -- This is the case of "/**": all directories
1693 -- in the file system.
1696 Name_Buffer (1) := Directory (Directory'First);
1699 Name_Buffer (1 .. Name_Len) :=
1700 Directory (Directory'First .. Directory'Last - 3);
1703 if Current_Verbosity = High then
1704 Write_Str ("Looking for all subdirectories of """);
1705 Write_Str (Name_Buffer (1 .. Name_Len));
1710 Base_Dir : constant Name_Id := Name_Find;
1711 Root : constant Name_Id :=
1712 Locate_Directory (Base_Dir, Data.Directory);
1715 if Root = No_Name then
1716 Errout.Error_Msg_Name_1 := Base_Dir;
1717 if Location = No_Location then
1718 Error_Msg ("{ is not a valid directory.", Data.Location);
1720 Error_Msg ("{ is not a valid directory.", Location);
1724 -- We have an existing directory,
1725 -- we register it and all of its subdirectories.
1727 if Current_Verbosity = High then
1728 Write_Line ("Looking for source directories:");
1732 Store_String_Chars (Get_Name_String (Root));
1733 Recursive_Find_Dirs (End_String);
1735 if Current_Verbosity = High then
1736 Write_Line ("End of looking for source directories.");
1741 -- We have a single directory
1745 Path_Name : constant Name_Id :=
1746 Locate_Directory (Directory_Id, Data.Directory);
1749 if Path_Name = No_Name then
1750 Errout.Error_Msg_Name_1 := Directory_Id;
1751 if Location = No_Location then
1752 Error_Msg ("{ is not a valid directory", Data.Location);
1754 Error_Msg ("{ is not a valid directory", Location);
1758 -- As it is an existing directory, we add it to
1759 -- the list of directories.
1761 String_Elements.Increment_Last;
1763 Store_String_Chars (Get_Name_String (Path_Name));
1764 Element.Value := End_String;
1766 if Last_Source_Dir = Nil_String then
1768 -- This is the first source directory
1770 Data.Source_Dirs := String_Elements.Last;
1773 -- We already have source directories,
1774 -- link the previous last to the new one.
1776 String_Elements.Table (Last_Source_Dir).Next :=
1777 String_Elements.Last;
1780 -- And register this source directory as the new last
1782 Last_Source_Dir := String_Elements.Last;
1783 String_Elements.Table (Last_Source_Dir) := Element;
1787 end Find_Source_Dirs;
1789 -- Start of processing for Language_Independent_Check
1793 if Data.Language_Independent_Checked then
1797 Data.Language_Independent_Checked := True;
1799 Error_Report := Report_Error;
1801 if Current_Verbosity = High then
1802 Write_Line ("Starting to look for directories");
1805 -- Check the object directory
1808 Object_Dir : Variable_Value :=
1809 Util.Value_Of (Name_Object_Dir, Data.Decl.Attributes);
1812 pragma Assert (Object_Dir.Kind = Single,
1813 "Object_Dir is not a single string");
1815 -- We set the object directory to its default
1817 Data.Object_Directory := Data.Directory;
1819 if not String_Equal (Object_Dir.Value, Empty_String) then
1821 String_To_Name_Buffer (Object_Dir.Value);
1823 if Name_Len = 0 then
1824 Error_Msg ("Object_Dir cannot be empty",
1825 Object_Dir.Location);
1828 -- We check that the specified object directory
1831 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1834 Dir_Id : constant Name_Id := Name_Find;
1837 Data.Object_Directory :=
1838 Locate_Directory (Dir_Id, Data.Directory);
1840 if Data.Object_Directory = No_Name then
1841 Errout.Error_Msg_Name_1 := Dir_Id;
1843 ("the object directory { cannot be found",
1851 if Current_Verbosity = High then
1852 if Data.Object_Directory = No_Name then
1853 Write_Line ("No object directory");
1855 Write_Str ("Object directory: """);
1856 Write_Str (Get_Name_String (Data.Object_Directory));
1861 -- Check the exec directory
1864 Exec_Dir : Variable_Value :=
1865 Util.Value_Of (Name_Exec_Dir, Data.Decl.Attributes);
1868 pragma Assert (Exec_Dir.Kind = Single,
1869 "Exec_Dir is not a single string");
1871 -- We set the object directory to its default
1873 Data.Exec_Directory := Data.Object_Directory;
1875 if not String_Equal (Exec_Dir.Value, Empty_String) then
1877 String_To_Name_Buffer (Exec_Dir.Value);
1879 if Name_Len = 0 then
1880 Error_Msg ("Exec_Dir cannot be empty",
1884 -- We check that the specified object directory
1887 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1890 Dir_Id : constant Name_Id := Name_Find;
1893 Data.Exec_Directory :=
1894 Locate_Directory (Dir_Id, Data.Directory);
1896 if Data.Exec_Directory = No_Name then
1897 Errout.Error_Msg_Name_1 := Dir_Id;
1899 ("the exec directory { cannot be found",
1907 if Current_Verbosity = High then
1908 if Data.Exec_Directory = No_Name then
1909 Write_Line ("No exec directory");
1911 Write_Str ("Exec directory: """);
1912 Write_Str (Get_Name_String (Data.Exec_Directory));
1917 -- Look for the source directories
1920 Source_Dirs : Variable_Value :=
1921 Util.Value_Of (Name_Source_Dirs, Data.Decl.Attributes);
1925 if Current_Verbosity = High then
1926 Write_Line ("Starting to look for source directories");
1929 pragma Assert (Source_Dirs.Kind = List,
1930 "Source_Dirs is not a list");
1932 if Source_Dirs.Default then
1934 -- No Source_Dirs specified: the single source directory
1935 -- is the one containing the project file
1937 String_Elements.Increment_Last;
1938 Data.Source_Dirs := String_Elements.Last;
1940 Store_String_Chars (Get_Name_String (Data.Directory));
1941 String_Elements.Table (Data.Source_Dirs) :=
1942 (Value => End_String,
1943 Location => No_Location,
1944 Next => Nil_String);
1946 if Current_Verbosity = High then
1947 Write_Line ("(Undefined) Single object directory:");
1949 Write_Str (Get_Name_String (Data.Directory));
1953 elsif Source_Dirs.Values = Nil_String then
1955 -- If Source_Dirs is an empty string list, this means
1956 -- that this project contains no source.
1958 if Data.Object_Directory = Data.Directory then
1959 Data.Object_Directory := No_Name;
1962 Data.Source_Dirs := Nil_String;
1963 Data.Sources_Present := False;
1967 Source_Dir : String_List_Id := Source_Dirs.Values;
1968 Element : String_Element;
1971 -- We will find the source directories for each
1972 -- element of the list
1974 while Source_Dir /= Nil_String loop
1975 Element := String_Elements.Table (Source_Dir);
1976 Find_Source_Dirs (Element.Value, Element.Location);
1977 Source_Dir := Element.Next;
1982 if Current_Verbosity = High then
1983 Write_Line ("Puting source directories in canonical cases");
1987 Current : String_List_Id := Data.Source_Dirs;
1988 Element : String_Element;
1991 while Current /= Nil_String loop
1992 Element := String_Elements.Table (Current);
1993 if Element.Value /= No_String then
1994 String_To_Name_Buffer (Element.Value);
1995 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1997 Store_String_Chars (Name_Buffer (1 .. Name_Len));
1998 Element.Value := End_String;
1999 String_Elements.Table (Current) := Element;
2002 Current := Element.Next;
2007 -- Library Dir, Name, Version and Kind
2010 Attributes : constant Prj.Variable_Id := Data.Decl.Attributes;
2012 Lib_Dir : Prj.Variable_Value :=
2013 Prj.Util.Value_Of (Snames.Name_Library_Dir, Attributes);
2015 Lib_Name : Prj.Variable_Value :=
2016 Prj.Util.Value_Of (Snames.Name_Library_Name, Attributes);
2018 Lib_Version : Prj.Variable_Value :=
2020 (Snames.Name_Library_Version, Attributes);
2022 The_Lib_Kind : Prj.Variable_Value :=
2024 (Snames.Name_Library_Kind, Attributes);
2027 pragma Assert (Lib_Dir.Kind = Single);
2029 if Lib_Dir.Value = Empty_String then
2031 if Current_Verbosity = High then
2032 Write_Line ("No library directory");
2036 -- Find path name, check that it is a directory
2038 Stringt.String_To_Name_Buffer (Lib_Dir.Value);
2041 Dir_Id : constant Name_Id := Name_Find;
2045 Locate_Directory (Dir_Id, Data.Directory);
2047 if Data.Library_Dir = No_Name then
2048 Error_Msg ("not an existing directory",
2051 elsif Data.Library_Dir = Data.Object_Directory then
2053 ("library directory cannot be the same " &
2054 "as object directory",
2056 Data.Library_Dir := No_Name;
2059 if Current_Verbosity = High then
2060 Write_Str ("Library directory =""");
2061 Write_Str (Get_Name_String (Data.Library_Dir));
2068 pragma Assert (Lib_Name.Kind = Single);
2070 if Lib_Name.Value = Empty_String then
2071 if Current_Verbosity = High then
2072 Write_Line ("No library name");
2076 Stringt.String_To_Name_Buffer (Lib_Name.Value);
2078 if not Is_Letter (Name_Buffer (1)) then
2079 Error_Msg ("must start with a letter",
2083 Data.Library_Name := Name_Find;
2085 for Index in 2 .. Name_Len loop
2086 if not Is_Alphanumeric (Name_Buffer (Index)) then
2087 Data.Library_Name := No_Name;
2088 Error_Msg ("only letters and digits are allowed",
2094 if Data.Library_Name /= No_Name
2095 and then Current_Verbosity = High then
2096 Write_Str ("Library name = """);
2097 Write_Str (Get_Name_String (Data.Library_Name));
2104 Data.Library_Dir /= No_Name
2106 Data.Library_Name /= No_Name;
2108 if Data.Library then
2110 if not MLib.Tgt.Libraries_Are_Supported then
2111 Error_Msg ("?libraries are not supported on this platform",
2113 Data.Library := False;
2116 if Current_Verbosity = High then
2117 Write_Line ("This is a library project file");
2120 pragma Assert (Lib_Version.Kind = Single);
2122 if Lib_Version.Value = Empty_String then
2123 if Current_Verbosity = High then
2124 Write_Line ("No library version specified");
2128 Stringt.String_To_Name_Buffer (Lib_Version.Value);
2129 Data.Lib_Internal_Name := Name_Find;
2132 pragma Assert (The_Lib_Kind.Kind = Single);
2134 if The_Lib_Kind.Value = Empty_String then
2135 if Current_Verbosity = High then
2136 Write_Line ("No library kind specified");
2140 Stringt.String_To_Name_Buffer (The_Lib_Kind.Value);
2143 Kind_Name : constant String :=
2144 To_Lower (Name_Buffer (1 .. Name_Len));
2146 OK : Boolean := True;
2149 if Kind_Name = "static" then
2150 Data.Library_Kind := Static;
2152 elsif Kind_Name = "dynamic" then
2153 Data.Library_Kind := Dynamic;
2155 elsif Kind_Name = "relocatable" then
2156 Data.Library_Kind := Relocatable;
2160 ("illegal value for Library_Kind",
2161 The_Lib_Kind.Location);
2165 if Current_Verbosity = High and then OK then
2166 Write_Str ("Library kind = ");
2167 Write_Line (Kind_Name);
2175 if Current_Verbosity = High then
2176 Show_Source_Dirs (Project);
2180 Naming_Id : constant Package_Id :=
2181 Util.Value_Of (Name_Naming, Data.Decl.Packages);
2183 Naming : Package_Element;
2186 -- If there is a package Naming, we will put in Data.Naming
2187 -- what is in this package Naming.
2189 if Naming_Id /= No_Package then
2190 Naming := Packages.Table (Naming_Id);
2192 if Current_Verbosity = High then
2193 Write_Line ("Checking ""Naming"".");
2196 -- Check Specification_Suffix
2199 Spec_Suffixs : Array_Element_Id :=
2201 (Name_Specification_Suffix,
2202 Naming.Decl.Arrays);
2203 Suffix : Array_Element_Id;
2204 Element : Array_Element;
2205 Suffix2 : Array_Element_Id;
2208 -- If some suffixs have been specified, we make sure that
2209 -- for each language for which a default suffix has been
2210 -- specified, there is a suffix specified, either the one
2211 -- in the project file or if there were noe, the default.
2213 if Spec_Suffixs /= No_Array_Element then
2214 Suffix := Data.Naming.Specification_Suffix;
2216 while Suffix /= No_Array_Element loop
2217 Element := Array_Elements.Table (Suffix);
2218 Suffix2 := Spec_Suffixs;
2220 while Suffix2 /= No_Array_Element loop
2221 exit when Array_Elements.Table (Suffix2).Index =
2223 Suffix2 := Array_Elements.Table (Suffix2).Next;
2226 -- There is a registered default suffix, but no
2227 -- suffix specified in the project file.
2228 -- Add the default to the array.
2230 if Suffix2 = No_Array_Element then
2231 Array_Elements.Increment_Last;
2232 Array_Elements.Table (Array_Elements.Last) :=
2233 (Index => Element.Index,
2234 Value => Element.Value,
2235 Next => Spec_Suffixs);
2236 Spec_Suffixs := Array_Elements.Last;
2239 Suffix := Element.Next;
2242 -- Put the resulting array as the specification suffixs
2244 Data.Naming.Specification_Suffix := Spec_Suffixs;
2249 Current : Array_Element_Id := Data.Naming.Specification_Suffix;
2250 Element : Array_Element;
2253 while Current /= No_Array_Element loop
2254 Element := Array_Elements.Table (Current);
2255 String_To_Name_Buffer (Element.Value.Value);
2257 if Name_Len = 0 then
2259 ("Specification_Suffix cannot be empty",
2260 Element.Value.Location);
2263 Array_Elements.Table (Current) := Element;
2264 Current := Element.Next;
2268 -- Check Implementation_Suffix
2271 Impl_Suffixs : Array_Element_Id :=
2273 (Name_Implementation_Suffix,
2274 Naming.Decl.Arrays);
2275 Suffix : Array_Element_Id;
2276 Element : Array_Element;
2277 Suffix2 : Array_Element_Id;
2279 -- If some suffixs have been specified, we make sure that
2280 -- for each language for which a default suffix has been
2281 -- specified, there is a suffix specified, either the one
2282 -- in the project file or if there were noe, the default.
2284 if Impl_Suffixs /= No_Array_Element then
2285 Suffix := Data.Naming.Implementation_Suffix;
2287 while Suffix /= No_Array_Element loop
2288 Element := Array_Elements.Table (Suffix);
2289 Suffix2 := Impl_Suffixs;
2291 while Suffix2 /= No_Array_Element loop
2292 exit when Array_Elements.Table (Suffix2).Index =
2294 Suffix2 := Array_Elements.Table (Suffix2).Next;
2297 -- There is a registered default suffix, but no
2298 -- suffix specified in the project file.
2299 -- Add the default to the array.
2301 if Suffix2 = No_Array_Element then
2302 Array_Elements.Increment_Last;
2303 Array_Elements.Table (Array_Elements.Last) :=
2304 (Index => Element.Index,
2305 Value => Element.Value,
2306 Next => Impl_Suffixs);
2307 Impl_Suffixs := Array_Elements.Last;
2310 Suffix := Element.Next;
2313 -- Put the resulting array as the implementation suffixs
2315 Data.Naming.Implementation_Suffix := Impl_Suffixs;
2320 Current : Array_Element_Id := Data.Naming.Implementation_Suffix;
2321 Element : Array_Element;
2324 while Current /= No_Array_Element loop
2325 Element := Array_Elements.Table (Current);
2326 String_To_Name_Buffer (Element.Value.Value);
2328 if Name_Len = 0 then
2330 ("Implementation_Suffix cannot be empty",
2331 Element.Value.Location);
2334 Array_Elements.Table (Current) := Element;
2335 Current := Element.Next;
2339 -- Get the exceptions, if any
2341 Data.Naming.Specification_Exceptions :=
2343 (Name_Specification_Exceptions,
2344 In_Arrays => Naming.Decl.Arrays);
2346 Data.Naming.Implementation_Exceptions :=
2348 (Name_Implementation_Exceptions,
2349 In_Arrays => Naming.Decl.Arrays);
2353 Projects.Table (Project) := Data;
2354 end Language_Independent_Check;
2356 ----------------------
2357 -- Locate_Directory --
2358 ----------------------
2360 function Locate_Directory
2365 The_Name : constant String := Get_Name_String (Name);
2366 The_Parent : constant String :=
2367 Get_Name_String (Parent) & Dir_Sep;
2369 The_Parent_Last : Positive := The_Parent'Last;
2372 if The_Parent'Length > 1
2373 and then (The_Parent (The_Parent_Last - 1) = Dir_Sep
2374 or else The_Parent (The_Parent_Last - 1) = '/')
2376 The_Parent_Last := The_Parent_Last - 1;
2379 if Current_Verbosity = High then
2380 Write_Str ("Locate_Directory (""");
2381 Write_Str (The_Name);
2382 Write_Str (""", """);
2383 Write_Str (The_Parent);
2387 if Is_Absolute_Path (The_Name) then
2388 if Is_Directory (The_Name) then
2394 Full_Path : constant String :=
2395 The_Parent (The_Parent'First .. The_Parent_Last) &
2399 if Is_Directory (Full_Path) then
2400 Name_Len := Full_Path'Length;
2401 Name_Buffer (1 .. Name_Len) := Full_Path;
2409 end Locate_Directory;
2415 function Path_Name_Of
2416 (File_Name : String_Id;
2417 Directory : Name_Id)
2420 Result : String_Access;
2421 The_Directory : constant String := Get_Name_String (Directory);
2424 String_To_Name_Buffer (File_Name);
2425 Result := Locate_Regular_File
2426 (File_Name => Name_Buffer (1 .. Name_Len),
2427 Path => The_Directory);
2429 if Result = null then
2432 Canonical_Case_File_Name (Result.all);
2441 procedure Record_Source
2442 (File_Name : Name_Id;
2443 Path_Name : Name_Id;
2444 Project : Project_Id;
2445 Data : in out Project_Data;
2446 Location : Source_Ptr;
2447 Current_Source : in out String_List_Id)
2449 Unit_Name : Name_Id;
2450 Unit_Kind : Spec_Or_Body;
2451 Needs_Pragma : Boolean;
2452 The_Location : Source_Ptr := Location;
2455 -- Find out the unit name, the unit kind and if it needs
2456 -- a specific SFN pragma.
2459 (File_Name => File_Name,
2460 Naming => Data.Naming,
2461 Unit_Name => Unit_Name,
2462 Unit_Kind => Unit_Kind,
2463 Needs_Pragma => Needs_Pragma);
2465 if Unit_Name = No_Name then
2466 if Current_Verbosity = High then
2468 Write_Str (Get_Name_String (File_Name));
2469 Write_Line (""" is not a valid source file name (ignored).");
2473 -- Put the file name in the list of sources of the project
2475 String_Elements.Increment_Last;
2476 Get_Name_String (File_Name);
2478 Store_String_Chars (Name_Buffer (1 .. Name_Len));
2479 String_Elements.Table (String_Elements.Last) :=
2480 (Value => End_String,
2481 Location => No_Location,
2482 Next => Nil_String);
2484 if Current_Source = Nil_String then
2485 Data.Sources := String_Elements.Last;
2488 String_Elements.Table (Current_Source).Next :=
2489 String_Elements.Last;
2492 Current_Source := String_Elements.Last;
2494 -- Put the unit in unit list
2497 The_Unit : Unit_Id := Units_Htable.Get (Unit_Name);
2498 The_Unit_Data : Unit_Data;
2501 if Current_Verbosity = High then
2502 Write_Str ("Putting ");
2503 Write_Str (Get_Name_String (Unit_Name));
2504 Write_Line (" in the unit list.");
2507 -- The unit is already in the list, but may be it is
2508 -- only the other unit kind (spec or body), or what is
2509 -- in the unit list is a unit of a project we are extending.
2511 if The_Unit /= Prj.Com.No_Unit then
2512 The_Unit_Data := Units.Table (The_Unit);
2514 if The_Unit_Data.File_Names (Unit_Kind).Name = No_Name
2515 or else (Data.Modifies /= No_Project
2517 The_Unit_Data.File_Names (Unit_Kind).Project =
2520 The_Unit_Data.File_Names (Unit_Kind) :=
2524 Needs_Pragma => Needs_Pragma);
2525 Units.Table (The_Unit) := The_Unit_Data;
2528 -- It is an error to have two units with the same name
2529 -- and the same kind (spec or body).
2531 if The_Location = No_Location then
2532 The_Location := Projects.Table (Project).Location;
2535 Errout.Error_Msg_Name_1 := Unit_Name;
2536 Error_Msg ("duplicate source {", The_Location);
2538 Errout.Error_Msg_Name_1 :=
2540 (The_Unit_Data.File_Names (Unit_Kind).Project).Name;
2541 Errout.Error_Msg_Name_2 :=
2542 The_Unit_Data.File_Names (Unit_Kind).Path;
2543 Error_Msg ("\ project file {, {", The_Location);
2545 Errout.Error_Msg_Name_1 := Projects.Table (Project).Name;
2546 Errout.Error_Msg_Name_2 := Path_Name;
2547 Error_Msg ("\ project file {, {", The_Location);
2551 -- It is a new unit, create a new record
2554 Units.Increment_Last;
2555 The_Unit := Units.Last;
2556 Units_Htable.Set (Unit_Name, The_Unit);
2557 The_Unit_Data.Name := Unit_Name;
2558 The_Unit_Data.File_Names (Unit_Kind) :=
2562 Needs_Pragma => Needs_Pragma);
2563 Units.Table (The_Unit) := The_Unit_Data;
2569 ----------------------
2570 -- Show_Source_Dirs --
2571 ----------------------
2573 procedure Show_Source_Dirs (Project : Project_Id) is
2574 Current : String_List_Id := Projects.Table (Project).Source_Dirs;
2575 Element : String_Element;
2578 Write_Line ("Source_Dirs:");
2580 while Current /= Nil_String loop
2581 Element := String_Elements.Table (Current);
2583 Write_Line (Get_Name_String (Element.Value));
2584 Current := Element.Next;
2587 Write_Line ("end Source_Dirs.");
2588 end Show_Source_Dirs;