1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
11 -- Copyright (C) 2000-2001 Free Software Foundation, Inc. --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
24 -- GNAT was originally developed by the GNAT team at New York University. --
25 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
27 ------------------------------------------------------------------------------
29 with Ada.Characters.Handling; use Ada.Characters.Handling;
30 with Ada.Strings; use Ada.Strings;
31 with Ada.Strings.Fixed; use Ada.Strings.Fixed;
32 with Ada.Strings.Maps.Constants; use Ada.Strings.Maps.Constants;
33 with Errout; use Errout;
34 with GNAT.Case_Util; use GNAT.Case_Util;
35 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
36 with GNAT.OS_Lib; use GNAT.OS_Lib;
37 with Namet; use Namet;
38 with Osint; use Osint;
39 with Output; use Output;
40 with Prj.Com; use Prj.Com;
41 with Prj.Util; use Prj.Util;
42 with Snames; use Snames;
43 with Stringt; use Stringt;
44 with Types; use Types;
46 package body Prj.Nmsc is
48 Dir_Sep : Character renames GNAT.OS_Lib.Directory_Separator;
50 Error_Report : Put_Line_Access := null;
52 procedure Check_Ada_Naming_Scheme (Naming : Naming_Data);
53 -- Check that the package Naming is correct.
55 procedure Check_Ada_Name
58 -- Check that a name is a valid Ada unit name.
60 procedure Error_Msg (Msg : String; Flag_Location : Source_Ptr);
61 -- Output an error message. If Error_Report is null, simply call
62 -- Errout.Error_Msg. Otherwise, disregard Flag_Location and use
65 function Get_Name_String (S : String_Id) return String;
66 -- Get the string from a String_Id
71 Unit_Name : out Name_Id;
72 Unit_Kind : out Spec_Or_Body;
73 Needs_Pragma : out Boolean);
74 -- Find out, from a file name, the unit name, the unit kind and if a
75 -- specific SFN pragma is needed. If the file name corresponds to no
76 -- unit, then Unit_Name will be No_Name.
78 function Is_Illegal_Append (This : String) return Boolean;
79 -- Returns True if the string This cannot be used as
80 -- a Specification_Append, a Body_Append or a Separate_Append.
82 procedure Record_Source
86 Data : in out Project_Data;
87 Location : Source_Ptr;
88 Current_Source : in out String_List_Id);
89 -- Put a unit in the list of units of a project, if the file name
90 -- corresponds to a valid unit name.
92 procedure Show_Source_Dirs (Project : Project_Id);
93 -- List all the source directories of a project.
95 function Locate_Directory
99 -- Locate a directory.
100 -- Returns No_Name if directory does not exist.
102 function Path_Name_Of
103 (File_Name : String_Id;
106 -- Returns the path name of a (non project) file.
107 -- Returns an empty string if file cannot be found.
109 function Path_Name_Of
110 (File_Name : String_Id;
111 Directory : String_Id)
113 -- Same as above except that Directory is a String_Id instead
121 (Project : Project_Id;
122 Report_Error : Put_Line_Access)
125 Languages : Variable_Value := Nil_Variable_Value;
127 procedure Check_Unit_Names (List : Array_Element_Id);
128 -- Check that a list of unit names contains only valid names.
130 procedure Find_Sources;
131 -- Find all the sources in all of the source directories
134 procedure Get_Path_Name_And_Record_Source
136 Location : Source_Ptr;
137 Current_Source : in out String_List_Id);
138 -- Find the path name of a source in the source directories and
139 -- record the source, if found.
141 procedure Get_Sources_From_File
143 Location : Source_Ptr);
144 -- Get the sources of a project from a text file
146 ----------------------
147 -- Check_Unit_Names --
148 ----------------------
150 procedure Check_Unit_Names (List : Array_Element_Id) is
151 Current : Array_Element_Id := List;
152 Element : Array_Element;
156 -- Loop through elements of the string list
158 while Current /= No_Array_Element loop
159 Element := Array_Elements.Table (Current);
161 -- Check that it contains a valid unit name
163 Check_Ada_Name (Element.Index, Unit_Name);
165 if Unit_Name = No_Name then
166 Error_Msg_Name_1 := Element.Index;
168 ("{ is not a valid unit name.",
169 Element.Value.Location);
172 if Current_Verbosity = High then
173 Write_Str (" Body_Part (""");
174 Write_Str (Get_Name_String (Unit_Name));
178 Element.Index := Unit_Name;
179 Array_Elements.Table (Current) := Element;
182 Current := Element.Next;
184 end Check_Unit_Names;
190 procedure Find_Sources is
191 Source_Dir : String_List_Id := Data.Source_Dirs;
192 Element : String_Element;
194 Current_Source : String_List_Id := Nil_String;
197 if Current_Verbosity = High then
198 Write_Line ("Looking for sources:");
201 -- For each subdirectory
203 while Source_Dir /= Nil_String loop
205 Element := String_Elements.Table (Source_Dir);
206 if Element.Value /= No_String then
208 Source_Directory : String
209 (1 .. Integer (String_Length (Element.Value)));
211 String_To_Name_Buffer (Element.Value);
212 Source_Directory := Name_Buffer (1 .. Name_Len);
213 if Current_Verbosity = High then
214 Write_Str ("Source_Dir = ");
215 Write_Line (Source_Directory);
218 -- We look to every entry in the source directory
220 Open (Dir, Source_Directory);
223 Read (Dir, Name_Buffer, Name_Len);
225 if Current_Verbosity = High then
226 Write_Str (" Checking ");
227 Write_Line (Name_Buffer (1 .. Name_Len));
230 exit when Name_Len = 0;
233 Path_Access : constant GNAT.OS_Lib.String_Access :=
235 (Name_Buffer (1 .. Name_Len),
242 -- If it is a regular file
244 if Path_Access /= null then
245 File_Name := Name_Find;
246 Name_Len := Path_Access'Length;
247 Name_Buffer (1 .. Name_Len) := Path_Access.all;
248 Path_Name := Name_Find;
250 -- We attempt to register it as a source.
251 -- However, there is no error if the file
252 -- does not contain a valid source (as
253 -- indicated by Error_If_Invalid => False).
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;
312 Found : Boolean := False;
316 if Current_Verbosity = High then
317 Write_Str (" Checking """);
318 Write_Str (File_Name);
322 -- We look in all source directories for this file name
324 while Source_Dir /= Nil_String loop
325 Element := String_Elements.Table (Source_Dir);
327 if Current_Verbosity = High then
329 Write_Str (Get_Name_String (Element.Value));
336 Get_Name_String (Element.Value));
338 if Path_Name /= null then
339 if Current_Verbosity = High then
343 Name_Len := File_Name'Length;
344 Name_Buffer (1 .. Name_Len) := File_Name;
346 Name_Len := Path_Name'Length;
347 Name_Buffer (1 .. Name_Len) := Path_Name.all;
349 -- Register the source. Report an error if the file does not
350 -- correspond to a source.
354 Path_Name => Name_Find,
357 Location => Location,
358 Current_Source => Current_Source);
363 if Current_Verbosity = High then
367 Source_Dir := Element.Next;
371 end Get_Path_Name_And_Record_Source;
373 ---------------------------
374 -- Get_Sources_From_File --
375 ---------------------------
377 procedure Get_Sources_From_File
379 Location : Source_Ptr)
381 File : Prj.Util.Text_File;
382 Line : String (1 .. 250);
384 Current_Source : String_List_Id := Nil_String;
386 Nmb_Errors : constant Nat := Errors_Detected;
389 if Current_Verbosity = High then
390 Write_Str ("Opening """);
397 Prj.Util.Open (File, Path);
399 if not Prj.Util.Is_Valid (File) then
400 Error_Msg ("file does not exist", Location);
402 while not Prj.Util.End_Of_File (File) loop
403 Prj.Util.Get_Line (File, Line, Last);
405 -- If the line is not empty and does not start with "--",
406 -- then it must contains a file name.
409 and then (Last = 1 or else Line (1 .. 2) /= "--")
411 Get_Path_Name_And_Record_Source
412 (File_Name => Line (1 .. Last),
413 Location => Location,
414 Current_Source => Current_Source);
415 exit when Nmb_Errors /= Errors_Detected;
419 Prj.Util.Close (File);
423 -- We should have found at least one source.
424 -- If not, report an error.
426 if Current_Source = Nil_String then
427 Error_Msg ("this project has no source", Location);
429 end Get_Sources_From_File;
431 -- Start of processing for Ada_Check
434 Language_Independent_Check (Project, Report_Error);
436 Error_Report := Report_Error;
438 Data := Projects.Table (Project);
439 Languages := Prj.Util.Value_Of (Name_Languages, Data.Decl.Attributes);
441 Data.Naming.Current_Language := Name_Ada;
442 Data.Sources_Present := Data.Source_Dirs /= Nil_String;
444 if not Languages.Default then
446 Current : String_List_Id := Languages.Values;
447 Element : String_Element;
448 Ada_Found : Boolean := False;
451 Look_For_Ada : while Current /= Nil_String loop
452 Element := String_Elements.Table (Current);
453 String_To_Name_Buffer (Element.Value);
454 To_Lower (Name_Buffer (1 .. Name_Len));
456 if Name_Buffer (1 .. Name_Len) = "ada" then
461 Current := Element.Next;
462 end loop Look_For_Ada;
464 if not Ada_Found then
466 -- Mark the project file as having no sources for Ada
468 Data.Sources_Present := False;
474 Naming_Id : constant Package_Id :=
475 Util.Value_Of (Name_Naming, Data.Decl.Packages);
477 Naming : Package_Element;
480 -- If there is a package Naming, we will put in Data.Naming
481 -- what is in this package Naming.
483 if Naming_Id /= No_Package then
484 Naming := Packages.Table (Naming_Id);
486 if Current_Verbosity = High then
487 Write_Line ("Checking ""Naming"" for Ada.");
491 Bodies : constant Array_Element_Id :=
493 (Name_Implementation, Naming.Decl.Arrays);
495 Specifications : constant Array_Element_Id :=
497 (Name_Specification, Naming.Decl.Arrays);
500 if Bodies /= No_Array_Element then
502 -- We have elements in the array Body_Part
504 if Current_Verbosity = High then
505 Write_Line ("Found Bodies.");
508 Data.Naming.Bodies := Bodies;
509 Check_Unit_Names (Bodies);
512 if Current_Verbosity = High then
513 Write_Line ("No Bodies.");
517 if Specifications /= No_Array_Element then
519 -- We have elements in the array Specification
521 if Current_Verbosity = High then
522 Write_Line ("Found Specifications.");
525 Data.Naming.Specifications := Specifications;
526 Check_Unit_Names (Specifications);
529 if Current_Verbosity = High then
530 Write_Line ("No Specifications.");
535 -- We are now checking if variables Dot_Replacement, Casing,
536 -- Specification_Append, Body_Append and/or Separate_Append
539 -- For each variable, if it does not exist, we do nothing,
540 -- because we already have the default.
542 -- Check Dot_Replacement
545 Dot_Replacement : constant Variable_Value :=
547 (Name_Dot_Replacement,
548 Naming.Decl.Attributes);
551 pragma Assert (Dot_Replacement.Kind = Single,
552 "Dot_Replacement is not a single string");
554 if not Dot_Replacement.Default then
556 String_To_Name_Buffer (Dot_Replacement.Value);
559 Error_Msg ("Dot_Replacement cannot be empty",
560 Dot_Replacement.Location);
563 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
564 Data.Naming.Dot_Replacement := Name_Find;
565 Data.Naming.Dot_Repl_Loc := Dot_Replacement.Location;
572 if Current_Verbosity = High then
573 Write_Str (" Dot_Replacement = """);
574 Write_Str (Get_Name_String (Data.Naming.Dot_Replacement));
582 Casing_String : constant Variable_Value :=
583 Util.Value_Of (Name_Casing, Naming.Decl.Attributes);
586 pragma Assert (Casing_String.Kind = Single,
587 "Casing is not a single string");
589 if not Casing_String.Default then
591 Casing_Image : constant String :=
592 Get_Name_String (Casing_String.Value);
596 Casing : constant Casing_Type :=
597 Value (Casing_Image);
600 Data.Naming.Casing := Casing;
604 when Constraint_Error =>
605 if Casing_Image'Length = 0 then
606 Error_Msg ("Casing cannot be an empty string",
607 Casing_String.Location);
610 Name_Len := Casing_Image'Length;
611 Name_Buffer (1 .. Name_Len) := Casing_Image;
612 Error_Msg_Name_1 := Name_Find;
614 ("{ is not a correct Casing",
615 Casing_String.Location);
621 if Current_Verbosity = High then
622 Write_Str (" Casing = ");
623 Write_Str (Image (Data.Naming.Casing));
628 -- Check Specification_Suffix
631 Ada_Spec_Suffix : constant Name_Id :=
634 In_Array => Data.Naming.Specification_Suffix);
637 if Ada_Spec_Suffix /= No_Name then
638 Data.Naming.Current_Spec_Suffix := Ada_Spec_Suffix;
641 Data.Naming.Current_Spec_Suffix := Ada_Default_Spec_Suffix;
645 if Current_Verbosity = High then
646 Write_Str (" Specification_Suffix = """);
647 Write_Str (Get_Name_String (Data.Naming.Current_Spec_Suffix));
652 -- Check Implementation_Suffix
655 Ada_Impl_Suffix : constant Name_Id :=
658 In_Array => Data.Naming.Implementation_Suffix);
661 if Ada_Impl_Suffix /= No_Name then
662 Data.Naming.Current_Impl_Suffix := Ada_Impl_Suffix;
665 Data.Naming.Current_Impl_Suffix := Ada_Default_Impl_Suffix;
669 if Current_Verbosity = High then
670 Write_Str (" Implementation_Suffix = """);
671 Write_Str (Get_Name_String (Data.Naming.Current_Impl_Suffix));
676 -- Check Separate_Suffix
679 Ada_Sep_Suffix : constant Variable_Value :=
681 (Variable_Name => Name_Separate_Suffix,
682 In_Variables => Naming.Decl.Attributes);
684 if Ada_Sep_Suffix.Default then
685 Data.Naming.Separate_Suffix :=
686 Data.Naming.Current_Impl_Suffix;
689 String_To_Name_Buffer (Ada_Sep_Suffix.Value);
692 Error_Msg ("Separate_Suffix cannot be empty",
693 Ada_Sep_Suffix.Location);
696 Data.Naming.Separate_Suffix := Name_Find;
697 Data.Naming.Sep_Suffix_Loc := Ada_Sep_Suffix.Location;
704 if Current_Verbosity = High then
705 Write_Str (" Separate_Suffix = """);
706 Write_Str (Get_Name_String (Data.Naming.Separate_Suffix));
711 -- Check if Data.Naming is valid
713 Check_Ada_Naming_Scheme (Data.Naming);
716 Data.Naming.Current_Spec_Suffix := Ada_Default_Spec_Suffix;
717 Data.Naming.Current_Impl_Suffix := Ada_Default_Impl_Suffix;
718 Data.Naming.Separate_Suffix := Ada_Default_Impl_Suffix;
722 -- If we have source directories, then find the sources
724 if Data.Sources_Present then
725 if Data.Source_Dirs = Nil_String then
726 Data.Sources_Present := False;
730 Sources : constant Variable_Value :=
733 Data.Decl.Attributes);
735 Source_List_File : constant Variable_Value :=
737 (Name_Source_List_File,
738 Data.Decl.Attributes);
742 (Sources.Kind = List,
743 "Source_Files is not a list");
745 (Source_List_File.Kind = Single,
746 "Source_List_File is not a single string");
748 if not Sources.Default then
749 if not Source_List_File.Default then
751 ("?both variables source_files and " &
752 "source_list_file are present",
753 Source_List_File.Location);
756 -- Sources is a list of file names
759 Current_Source : String_List_Id := Nil_String;
760 Current : String_List_Id := Sources.Values;
761 Element : String_Element;
764 Data.Sources_Present := Current /= Nil_String;
766 while Current /= Nil_String loop
767 Element := String_Elements.Table (Current);
768 String_To_Name_Buffer (Element.Value);
771 File_Name : constant String :=
772 Name_Buffer (1 .. Name_Len);
775 Get_Path_Name_And_Record_Source
776 (File_Name => File_Name,
777 Location => Element.Location,
778 Current_Source => Current_Source);
779 Current := Element.Next;
784 -- No source_files specified.
785 -- We check Source_List_File has been specified.
787 elsif not Source_List_File.Default then
789 -- Source_List_File is the name of the file
790 -- that contains the source file names
793 Source_File_Path_Name : constant String :=
795 (Source_List_File.Value,
799 if Source_File_Path_Name'Length = 0 then
800 String_To_Name_Buffer (Source_List_File.Value);
801 Error_Msg_Name_1 := Name_Find;
803 ("file with sources { does not exist",
804 Source_List_File.Location);
807 Get_Sources_From_File
808 (Source_File_Path_Name,
809 Source_List_File.Location);
814 -- Neither Source_Files nor Source_List_File has been
816 -- Find all the files that satisfy
817 -- the naming scheme in all the source directories.
825 Projects.Table (Project) := Data;
832 procedure Check_Ada_Name
836 The_Name : String := Get_Name_String (Name);
837 Need_Letter : Boolean := True;
838 Last_Underscore : Boolean := False;
839 OK : Boolean := The_Name'Length > 0;
842 for Index in The_Name'Range loop
845 -- We need a letter (at the beginning, and following a dot),
846 -- but we don't have one.
848 if Is_Letter (The_Name (Index)) then
849 Need_Letter := False;
854 if Current_Verbosity = High then
855 Write_Int (Types.Int (Index));
857 Write_Char (The_Name (Index));
858 Write_Line ("' is not a letter.");
864 elsif Last_Underscore
865 and then (The_Name (Index) = '_' or else The_Name (Index) = '.')
867 -- Two underscores are illegal, and a dot cannot follow
872 if Current_Verbosity = High then
873 Write_Int (Types.Int (Index));
875 Write_Char (The_Name (Index));
876 Write_Line ("' is illegal here.");
881 elsif The_Name (Index) = '.' then
883 -- We need a letter after a dot
887 elsif The_Name (Index) = '_' then
888 Last_Underscore := True;
891 -- We need an letter or a digit
893 Last_Underscore := False;
895 if not Is_Alphanumeric (The_Name (Index)) then
898 if Current_Verbosity = High then
899 Write_Int (Types.Int (Index));
901 Write_Char (The_Name (Index));
902 Write_Line ("' is not alphanumeric.");
910 -- Cannot end with an underscore or a dot
912 OK := OK and then not Need_Letter and then not Last_Underscore;
917 -- Signal a problem with No_Name
923 -------------------------
924 -- Check_Naming_Scheme --
925 -------------------------
927 procedure Check_Ada_Naming_Scheme (Naming : Naming_Data) is
929 -- Only check if we are not using the standard naming scheme
931 if Naming /= Standard_Naming_Data then
933 Dot_Replacement : constant String :=
935 (Naming.Dot_Replacement);
937 Specification_Suffix : constant String :=
939 (Naming.Current_Spec_Suffix);
941 Implementation_Suffix : constant String :=
943 (Naming.Current_Impl_Suffix);
945 Separate_Suffix : constant String :=
947 (Naming.Separate_Suffix);
950 -- Dot_Replacement cannot
952 -- - start or end with an alphanumeric
954 -- - start with an '_' followed by an alphanumeric
955 -- - contain a '.' except if it is "."
957 if Dot_Replacement'Length = 0
958 or else Is_Alphanumeric
959 (Dot_Replacement (Dot_Replacement'First))
960 or else Is_Alphanumeric
961 (Dot_Replacement (Dot_Replacement'Last))
962 or else (Dot_Replacement (Dot_Replacement'First) = '_'
964 (Dot_Replacement'Length = 1
967 (Dot_Replacement (Dot_Replacement'First + 1))))
968 or else (Dot_Replacement'Length > 1
970 Index (Source => Dot_Replacement,
971 Pattern => ".") /= 0)
974 ('"' & Dot_Replacement &
975 """ is illegal for Dot_Replacement.",
976 Naming.Dot_Repl_Loc);
981 -- - start with an alphanumeric
982 -- - start with an '_' followed by an alphanumeric
984 if Is_Illegal_Append (Specification_Suffix) then
986 ('"' & Specification_Suffix &
987 """ is illegal for Specification_Suffix.",
988 Naming.Spec_Suffix_Loc);
991 if Is_Illegal_Append (Implementation_Suffix) then
993 ('"' & Implementation_Suffix &
994 """ is illegal for Implementation_Suffix.",
995 Naming.Impl_Suffix_Loc);
998 if Implementation_Suffix /= Separate_Suffix then
999 if Is_Illegal_Append (Separate_Suffix) then
1001 ('"' & Separate_Suffix &
1002 """ is illegal for Separate_Append.",
1003 Naming.Sep_Suffix_Loc);
1007 -- Specification_Suffix cannot have the same termination as
1008 -- Implementation_Suffix or Separate_Suffix
1010 if Specification_Suffix'Length <= Implementation_Suffix'Length
1012 Implementation_Suffix (Implementation_Suffix'Last -
1013 Specification_Suffix'Length + 1 ..
1014 Implementation_Suffix'Last) = Specification_Suffix
1017 ("Implementation_Suffix (""" &
1018 Implementation_Suffix &
1019 """) cannot end with" &
1020 "Specification_Suffix (""" &
1021 Specification_Suffix & """).",
1022 Naming.Impl_Suffix_Loc);
1025 if Specification_Suffix'Length <= Separate_Suffix'Length
1028 (Separate_Suffix'Last - Specification_Suffix'Length + 1
1030 Separate_Suffix'Last) = Specification_Suffix
1033 ("Separate_Suffix (""" &
1035 """) cannot end with" &
1036 " Specification_Suffix (""" &
1037 Specification_Suffix & """).",
1038 Naming.Sep_Suffix_Loc);
1042 end Check_Ada_Naming_Scheme;
1048 procedure Error_Msg (Msg : String; Flag_Location : Source_Ptr) is
1050 Error_Buffer : String (1 .. 5_000);
1051 Error_Last : Natural := 0;
1052 Msg_Name : Natural := 0;
1053 First : Positive := Msg'First;
1055 procedure Add (C : Character);
1056 -- Add a character to the buffer
1058 procedure Add (S : String);
1059 -- Add a string to the buffer
1061 procedure Add (Id : Name_Id);
1062 -- Add a name to the buffer
1068 procedure Add (C : Character) is
1070 Error_Last := Error_Last + 1;
1071 Error_Buffer (Error_Last) := C;
1074 procedure Add (S : String) is
1076 Error_Buffer (Error_Last + 1 .. Error_Last + S'Length) := S;
1077 Error_Last := Error_Last + S'Length;
1080 procedure Add (Id : Name_Id) is
1082 Get_Name_String (Id);
1083 Add (Name_Buffer (1 .. Name_Len));
1086 -- Start of processing for Error_Msg
1089 if Error_Report = null then
1090 Errout.Error_Msg (Msg, Flag_Location);
1094 if Msg (First) = '\' then
1096 -- Continuation character, ignore.
1100 elsif Msg (First) = '?' then
1102 -- Warning character. It is always the first one,
1109 for Index in First .. Msg'Last loop
1110 if Msg (Index) = '{' or else Msg (Index) = '%' then
1112 -- Include a name between double quotes.
1114 Msg_Name := Msg_Name + 1;
1118 when 1 => Add (Error_Msg_Name_1);
1120 when 2 => Add (Error_Msg_Name_2);
1122 when 3 => Add (Error_Msg_Name_3);
1124 when others => null;
1135 Error_Report (Error_Buffer (1 .. Error_Last));
1138 ---------------------
1139 -- Get_Name_String --
1140 ---------------------
1142 function Get_Name_String (S : String_Id) return String is
1144 if S = No_String then
1147 String_To_Name_Buffer (S);
1148 return Name_Buffer (1 .. Name_Len);
1150 end Get_Name_String;
1157 (File_Name : Name_Id;
1158 Naming : Naming_Data;
1159 Unit_Name : out Name_Id;
1160 Unit_Kind : out Spec_Or_Body;
1161 Needs_Pragma : out Boolean)
1163 Canonical_Case_Name : Name_Id;
1166 Needs_Pragma := False;
1167 Get_Name_String (File_Name);
1168 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1169 Canonical_Case_Name := Name_Find;
1171 if Naming.Bodies /= No_Array_Element then
1173 -- There are some specified file names for some bodies
1174 -- of this project. Find out if File_Name is one of these bodies.
1177 Current : Array_Element_Id := Naming.Bodies;
1178 Element : Array_Element;
1181 while Current /= No_Array_Element loop
1182 Element := Array_Elements.Table (Current);
1184 if Element.Index /= No_Name then
1185 String_To_Name_Buffer (Element.Value.Value);
1186 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1188 if Canonical_Case_Name = Name_Find then
1190 -- File_Name corresponds to one body.
1191 -- So, we know it is a body, and we know the unit name.
1193 Unit_Kind := Body_Part;
1194 Unit_Name := Element.Index;
1195 Needs_Pragma := True;
1200 Current := Element.Next;
1205 if Naming.Specifications /= No_Array_Element then
1207 -- There are some specified file names for some bodiesspecifications
1208 -- of this project. Find out if File_Name is one of these
1212 Current : Array_Element_Id := Naming.Specifications;
1213 Element : Array_Element;
1216 while Current /= No_Array_Element loop
1217 Element := Array_Elements.Table (Current);
1219 if Element.Index /= No_Name then
1220 String_To_Name_Buffer (Element.Value.Value);
1221 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1223 if Canonical_Case_Name = Name_Find then
1225 -- File_Name corresponds to one specification.
1226 -- So, we know it is a spec, and we know the unit name.
1228 Unit_Kind := Specification;
1229 Unit_Name := Element.Index;
1230 Needs_Pragma := True;
1236 Current := Element.Next;
1242 File : String := Get_Name_String (Canonical_Case_Name);
1243 First : Positive := File'First;
1244 Last : Natural := File'Last;
1247 -- Check if the end of the file name is Specification_Append
1249 Get_Name_String (Naming.Current_Spec_Suffix);
1251 if File'Length > Name_Len
1252 and then File (Last - Name_Len + 1 .. Last) =
1253 Name_Buffer (1 .. Name_Len)
1257 Unit_Kind := Specification;
1258 Last := Last - Name_Len;
1260 if Current_Verbosity = High then
1261 Write_Str (" Specification: ");
1262 Write_Line (File (First .. Last));
1266 Get_Name_String (Naming.Current_Impl_Suffix);
1268 -- Check if the end of the file name is Body_Append
1270 if File'Length > Name_Len
1271 and then File (Last - Name_Len + 1 .. Last) =
1272 Name_Buffer (1 .. Name_Len)
1276 Unit_Kind := Body_Part;
1277 Last := Last - Name_Len;
1279 if Current_Verbosity = High then
1280 Write_Str (" Body: ");
1281 Write_Line (File (First .. Last));
1284 elsif Naming.Separate_Suffix /= Naming.Current_Spec_Suffix then
1285 Get_Name_String (Naming.Separate_Suffix);
1287 -- Check if the end of the file name is Separate_Append
1289 if File'Length > Name_Len
1290 and then File (Last - Name_Len + 1 .. Last) =
1291 Name_Buffer (1 .. Name_Len)
1293 -- We have a separate (a body)
1295 Unit_Kind := Body_Part;
1296 Last := Last - Name_Len;
1298 if Current_Verbosity = High then
1299 Write_Str (" Separate: ");
1300 Write_Line (File (First .. Last));
1314 -- This is not a source file
1316 Unit_Name := No_Name;
1317 Unit_Kind := Specification;
1319 if Current_Verbosity = High then
1320 Write_Line (" Not a valid file name.");
1326 Get_Name_String (Naming.Dot_Replacement);
1328 if Name_Buffer (1 .. Name_Len) /= "." then
1330 -- If Dot_Replacement is not a single dot,
1331 -- then there should not be any dot in the name.
1333 for Index in First .. Last loop
1334 if File (Index) = '.' then
1335 if Current_Verbosity = High then
1337 (" Not a valid file name (some dot not replaced).");
1340 Unit_Name := No_Name;
1346 -- Replace the substring Dot_Replacement with dots
1349 Index : Positive := First;
1352 while Index <= Last - Name_Len + 1 loop
1354 if File (Index .. Index + Name_Len - 1) =
1355 Name_Buffer (1 .. Name_Len)
1357 File (Index) := '.';
1359 if Name_Len > 1 and then Index < Last then
1360 File (Index + 1 .. Last - Name_Len + 1) :=
1361 File (Index + Name_Len .. Last);
1364 Last := Last - Name_Len + 1;
1372 -- Check if the casing is right
1375 Src : String := File (First .. Last);
1378 case Naming.Casing is
1379 when All_Lower_Case =>
1382 Mapping => Lower_Case_Map);
1384 when All_Upper_Case =>
1387 Mapping => Upper_Case_Map);
1389 when Mixed_Case | Unknown =>
1393 if Src /= File (First .. Last) then
1394 if Current_Verbosity = High then
1395 Write_Line (" Not a valid file name (casing).");
1398 Unit_Name := No_Name;
1402 -- We put the name in lower case
1406 Mapping => Lower_Case_Map);
1408 if Current_Verbosity = High then
1413 Name_Len := Src'Length;
1414 Name_Buffer (1 .. Name_Len) := Src;
1416 -- Now, we check if this name is a valid unit name
1418 Check_Ada_Name (Name => Name_Find, Unit => Unit_Name);
1425 -----------------------
1426 -- Is_Illegal_Append --
1427 -----------------------
1429 function Is_Illegal_Append (This : String) return Boolean is
1431 return This'Length = 0
1432 or else Is_Alphanumeric (This (This'First))
1433 or else (This'Length >= 2
1434 and then This (This'First) = '_'
1435 and then Is_Alphanumeric (This (This'First + 1)));
1436 end Is_Illegal_Append;
1438 --------------------------------
1439 -- Language_Independent_Check --
1440 --------------------------------
1442 procedure Language_Independent_Check
1443 (Project : Project_Id;
1444 Report_Error : Put_Line_Access)
1446 Last_Source_Dir : String_List_Id := Nil_String;
1447 Data : Project_Data := Projects.Table (Project);
1449 procedure Find_Source_Dirs (From : String_Id; Location : Source_Ptr);
1450 -- Find one or several source directories, and add them
1451 -- to the list of source directories of the project.
1453 ----------------------
1454 -- Find_Source_Dirs --
1455 ----------------------
1457 procedure Find_Source_Dirs (From : String_Id; Location : Source_Ptr) is
1459 Directory : String (1 .. Integer (String_Length (From)));
1460 Directory_Id : Name_Id;
1461 Element : String_Element;
1463 procedure Recursive_Find_Dirs (Path : String_Id);
1464 -- Find all the subdirectories (recursively) of Path
1465 -- and add them to the list of source directories
1468 -------------------------
1469 -- Recursive_Find_Dirs --
1470 -------------------------
1472 procedure Recursive_Find_Dirs (Path : String_Id) is
1474 Name : String (1 .. 250);
1476 The_Path : String := Get_Name_String (Path) & Dir_Sep;
1478 The_Path_Last : Positive := The_Path'Last;
1481 if The_Path'Length > 1
1483 (The_Path (The_Path_Last - 1) = Dir_Sep
1484 or else The_Path (The_Path_Last - 1) = '/')
1486 The_Path_Last := The_Path_Last - 1;
1489 if Current_Verbosity = High then
1491 Write_Line (The_Path (The_Path'First .. The_Path_Last));
1494 String_Elements.Increment_Last;
1497 Location => No_Location,
1498 Next => Nil_String);
1500 -- Case of first source directory
1502 if Last_Source_Dir = Nil_String then
1503 Data.Source_Dirs := String_Elements.Last;
1505 -- Here we already have source directories.
1508 -- Link the previous last to the new one
1510 String_Elements.Table (Last_Source_Dir).Next :=
1511 String_Elements.Last;
1514 -- And register this source directory as the new last
1516 Last_Source_Dir := String_Elements.Last;
1517 String_Elements.Table (Last_Source_Dir) := Element;
1519 -- Now look for subdirectories
1521 Open (Dir, The_Path (The_Path'First .. The_Path_Last));
1524 Read (Dir, Name, Last);
1527 if Current_Verbosity = High then
1528 Write_Str (" Checking ");
1529 Write_Line (Name (1 .. Last));
1532 if Name (1 .. Last) /= "."
1533 and then Name (1 .. Last) /= ".."
1538 Path_Name : constant String :=
1539 The_Path (The_Path'First .. The_Path_Last) &
1543 if Is_Directory (Path_Name) then
1545 -- We have found a new subdirectory,
1546 -- register it and find its own subdirectories.
1549 Store_String_Chars (Path_Name);
1550 Recursive_Find_Dirs (End_String);
1559 when Directory_Error =>
1561 end Recursive_Find_Dirs;
1563 -- Start of processing for Find_Source_Dirs
1566 if Current_Verbosity = High then
1567 Write_Str ("Find_Source_Dirs (""");
1570 String_To_Name_Buffer (From);
1571 Directory := Name_Buffer (1 .. Name_Len);
1572 Directory_Id := Name_Find;
1574 if Current_Verbosity = High then
1575 Write_Str (Directory);
1579 -- First, check if we are looking for a directory tree,
1580 -- indicated by "/**" at the end.
1582 if Directory'Length >= 3
1583 and then Directory (Directory'Last - 1 .. Directory'Last) = "**"
1584 and then (Directory (Directory'Last - 2) = '/'
1586 Directory (Directory'Last - 2) = Dir_Sep)
1588 Name_Len := Directory'Length - 3;
1590 if Name_Len = 0 then
1591 -- This is the case of "/**": all directories
1592 -- in the file system.
1595 Name_Buffer (1) := Directory (Directory'First);
1598 Name_Buffer (1 .. Name_Len) :=
1599 Directory (Directory'First .. Directory'Last - 3);
1602 if Current_Verbosity = High then
1603 Write_Str ("Looking for all subdirectories of """);
1604 Write_Str (Name_Buffer (1 .. Name_Len));
1609 Base_Dir : constant Name_Id := Name_Find;
1610 Root : constant Name_Id :=
1611 Locate_Directory (Base_Dir, Data.Directory);
1614 if Root = No_Name then
1615 Error_Msg_Name_1 := Base_Dir;
1616 if Location = No_Location then
1617 Error_Msg ("{ is not a valid directory.", Data.Location);
1619 Error_Msg ("{ is not a valid directory.", Location);
1623 -- We have an existing directory,
1624 -- we register it and all of its subdirectories.
1626 if Current_Verbosity = High then
1627 Write_Line ("Looking for source directories:");
1631 Store_String_Chars (Get_Name_String (Root));
1632 Recursive_Find_Dirs (End_String);
1634 if Current_Verbosity = High then
1635 Write_Line ("End of looking for source directories.");
1640 -- We have a single directory
1644 Path_Name : constant Name_Id :=
1645 Locate_Directory (Directory_Id, Data.Directory);
1648 if Path_Name = No_Name then
1649 Error_Msg_Name_1 := Directory_Id;
1650 if Location = No_Location then
1651 Error_Msg ("{ is not a valid directory", Data.Location);
1653 Error_Msg ("{ is not a valid directory", Location);
1657 -- As it is an existing directory, we add it to
1658 -- the list of directories.
1660 String_Elements.Increment_Last;
1662 Store_String_Chars (Get_Name_String (Path_Name));
1663 Element.Value := End_String;
1665 if Last_Source_Dir = Nil_String then
1667 -- This is the first source directory
1669 Data.Source_Dirs := String_Elements.Last;
1672 -- We already have source directories,
1673 -- link the previous last to the new one.
1675 String_Elements.Table (Last_Source_Dir).Next :=
1676 String_Elements.Last;
1679 -- And register this source directory as the new last
1681 Last_Source_Dir := String_Elements.Last;
1682 String_Elements.Table (Last_Source_Dir) := Element;
1686 end Find_Source_Dirs;
1688 -- Start of processing for Language_Independent_Check
1692 if Data.Language_Independent_Checked then
1696 Data.Language_Independent_Checked := True;
1698 Error_Report := Report_Error;
1700 if Current_Verbosity = High then
1701 Write_Line ("Starting to look for directories");
1704 -- Let's check the object directory
1707 Object_Dir : Variable_Value :=
1708 Util.Value_Of (Name_Object_Dir, Data.Decl.Attributes);
1711 pragma Assert (Object_Dir.Kind = Single,
1712 "Object_Dir is not a single string");
1714 -- We set the object directory to its default
1716 Data.Object_Directory := Data.Directory;
1718 if not String_Equal (Object_Dir.Value, Empty_String) then
1720 String_To_Name_Buffer (Object_Dir.Value);
1722 if Name_Len = 0 then
1723 Error_Msg ("Object_Dir cannot be empty",
1724 Object_Dir.Location);
1727 -- We check that the specified object directory
1730 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1733 Dir_Id : constant Name_Id := Name_Find;
1736 Data.Object_Directory :=
1737 Locate_Directory (Dir_Id, Data.Directory);
1739 if Data.Object_Directory = No_Name then
1740 Error_Msg_Name_1 := Dir_Id;
1742 ("the object directory { cannot be found",
1750 if Current_Verbosity = High then
1751 if Data.Object_Directory = No_Name then
1752 Write_Line ("No object directory");
1754 Write_Str ("Object directory: """);
1755 Write_Str (Get_Name_String (Data.Object_Directory));
1760 -- Look for the source directories
1763 Source_Dirs : Variable_Value :=
1764 Util.Value_Of (Name_Source_Dirs, Data.Decl.Attributes);
1768 if Current_Verbosity = High then
1769 Write_Line ("Starting to look for source directories");
1772 pragma Assert (Source_Dirs.Kind = List,
1773 "Source_Dirs is not a list");
1775 if Source_Dirs.Default then
1777 -- No Source_Dirs specified: the single source directory
1778 -- is the one containing the project file
1780 String_Elements.Increment_Last;
1781 Data.Source_Dirs := String_Elements.Last;
1783 Store_String_Chars (Get_Name_String (Data.Directory));
1784 String_Elements.Table (Data.Source_Dirs) :=
1785 (Value => End_String,
1786 Location => No_Location,
1787 Next => Nil_String);
1789 if Current_Verbosity = High then
1790 Write_Line ("(Undefined) Single object directory:");
1792 Write_Str (Get_Name_String (Data.Directory));
1796 elsif Source_Dirs.Values = Nil_String then
1798 -- If Source_Dirs is an empty string list, this means
1799 -- that this project contains no source.
1801 if Data.Object_Directory = Data.Directory then
1802 Data.Object_Directory := No_Name;
1805 Data.Source_Dirs := Nil_String;
1806 Data.Sources_Present := False;
1810 Source_Dir : String_List_Id := Source_Dirs.Values;
1811 Element : String_Element;
1814 -- We will find the source directories for each
1815 -- element of the list
1817 while Source_Dir /= Nil_String loop
1818 Element := String_Elements.Table (Source_Dir);
1819 Find_Source_Dirs (Element.Value, Element.Location);
1820 Source_Dir := Element.Next;
1825 if Current_Verbosity = High then
1826 Write_Line ("Puting source directories in canonical cases");
1830 Current : String_List_Id := Data.Source_Dirs;
1831 Element : String_Element;
1834 while Current /= Nil_String loop
1835 Element := String_Elements.Table (Current);
1836 if Element.Value /= No_String then
1837 String_To_Name_Buffer (Element.Value);
1838 Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1840 Store_String_Chars (Name_Buffer (1 .. Name_Len));
1841 Element.Value := End_String;
1842 String_Elements.Table (Current) := Element;
1845 Current := Element.Next;
1850 -- Library Dir, Name, Version and Kind
1853 Attributes : constant Prj.Variable_Id := Data.Decl.Attributes;
1855 Lib_Dir : Prj.Variable_Value :=
1856 Prj.Util.Value_Of (Snames.Name_Library_Dir, Attributes);
1858 Lib_Name : Prj.Variable_Value :=
1859 Prj.Util.Value_Of (Snames.Name_Library_Name, Attributes);
1861 Lib_Version : Prj.Variable_Value :=
1863 (Snames.Name_Library_Version, Attributes);
1865 The_Lib_Kind : Prj.Variable_Value :=
1867 (Snames.Name_Library_Kind, Attributes);
1870 pragma Assert (Lib_Dir.Kind = Single);
1872 if Lib_Dir.Value = Empty_String then
1874 if Current_Verbosity = High then
1875 Write_Line ("No library directory");
1879 -- Find path name, check that it is a directory
1881 Stringt.String_To_Name_Buffer (Lib_Dir.Value);
1884 Dir_Id : constant Name_Id := Name_Find;
1888 Locate_Directory (Dir_Id, Data.Directory);
1890 if Data.Library_Dir = No_Name then
1891 Error_Msg ("not an existing directory",
1894 elsif Data.Library_Dir = Data.Object_Directory then
1896 ("library directory cannot be the same " &
1897 "as object directory",
1899 Data.Library_Dir := No_Name;
1902 if Current_Verbosity = High then
1903 Write_Str ("Library directory =""");
1904 Write_Str (Get_Name_String (Data.Library_Dir));
1911 pragma Assert (Lib_Name.Kind = Single);
1913 if Lib_Name.Value = Empty_String then
1914 if Current_Verbosity = High then
1915 Write_Line ("No library name");
1919 Stringt.String_To_Name_Buffer (Lib_Name.Value);
1921 if not Is_Letter (Name_Buffer (1)) then
1922 Error_Msg ("must start with a letter",
1926 Data.Library_Name := Name_Find;
1928 for Index in 2 .. Name_Len loop
1929 if not Is_Alphanumeric (Name_Buffer (Index)) then
1930 Data.Library_Name := No_Name;
1931 Error_Msg ("only letters and digits are allowed",
1937 if Data.Library_Name /= No_Name
1938 and then Current_Verbosity = High then
1939 Write_Str ("Library name = """);
1940 Write_Str (Get_Name_String (Data.Library_Name));
1947 Data.Library_Dir /= No_Name
1949 Data.Library_Name /= No_Name;
1951 if Data.Library then
1952 if Current_Verbosity = High then
1953 Write_Line ("This is a library project file");
1956 pragma Assert (Lib_Version.Kind = Single);
1958 if Lib_Version.Value = Empty_String then
1959 if Current_Verbosity = High then
1960 Write_Line ("No library version specified");
1964 Stringt.String_To_Name_Buffer (Lib_Version.Value);
1965 Data.Lib_Internal_Name := Name_Find;
1968 pragma Assert (The_Lib_Kind.Kind = Single);
1970 if The_Lib_Kind.Value = Empty_String then
1971 if Current_Verbosity = High then
1972 Write_Line ("No library kind specified");
1976 Stringt.String_To_Name_Buffer (The_Lib_Kind.Value);
1979 Kind_Name : constant String :=
1980 To_Lower (Name_Buffer (1 .. Name_Len));
1982 OK : Boolean := True;
1986 if Kind_Name = "static" then
1987 Data.Library_Kind := Static;
1989 elsif Kind_Name = "dynamic" then
1990 Data.Library_Kind := Dynamic;
1992 elsif Kind_Name = "relocatable" then
1993 Data.Library_Kind := Relocatable;
1997 ("illegal value for Library_Kind",
1998 The_Lib_Kind.Location);
2002 if Current_Verbosity = High and then OK then
2003 Write_Str ("Library kind = ");
2004 Write_Line (Kind_Name);
2011 if Current_Verbosity = High then
2012 Show_Source_Dirs (Project);
2016 Naming_Id : constant Package_Id :=
2017 Util.Value_Of (Name_Naming, Data.Decl.Packages);
2019 Naming : Package_Element;
2022 -- If there is a package Naming, we will put in Data.Naming
2023 -- what is in this package Naming.
2025 if Naming_Id /= No_Package then
2026 Naming := Packages.Table (Naming_Id);
2028 if Current_Verbosity = High then
2029 Write_Line ("Checking ""Naming"".");
2032 -- Check Specification_Suffix
2034 Data.Naming.Specification_Suffix := Util.Value_Of
2035 (Name_Specification_Suffix,
2036 Naming.Decl.Arrays);
2039 Current : Array_Element_Id := Data.Naming.Specification_Suffix;
2040 Element : Array_Element;
2043 while Current /= No_Array_Element loop
2044 Element := Array_Elements.Table (Current);
2045 String_To_Name_Buffer (Element.Value.Value);
2047 if Name_Len = 0 then
2049 ("Specification_Suffix cannot be empty",
2050 Element.Value.Location);
2053 Array_Elements.Table (Current) := Element;
2054 Current := Element.Next;
2058 -- Check Implementation_Suffix
2060 Data.Naming.Implementation_Suffix := Util.Value_Of
2061 (Name_Implementation_Suffix,
2062 Naming.Decl.Arrays);
2065 Current : Array_Element_Id := Data.Naming.Implementation_Suffix;
2066 Element : Array_Element;
2069 while Current /= No_Array_Element loop
2070 Element := Array_Elements.Table (Current);
2071 String_To_Name_Buffer (Element.Value.Value);
2073 if Name_Len = 0 then
2075 ("Implementation_Suffix cannot be empty",
2076 Element.Value.Location);
2079 Array_Elements.Table (Current) := Element;
2080 Current := Element.Next;
2087 Projects.Table (Project) := Data;
2088 end Language_Independent_Check;
2090 ----------------------
2091 -- Locate_Directory --
2092 ----------------------
2094 function Locate_Directory
2099 The_Name : constant String := Get_Name_String (Name);
2100 The_Parent : constant String :=
2101 Get_Name_String (Parent) & Dir_Sep;
2103 The_Parent_Last : Positive := The_Parent'Last;
2106 if The_Parent'Length > 1
2107 and then (The_Parent (The_Parent_Last - 1) = Dir_Sep
2108 or else The_Parent (The_Parent_Last - 1) = '/')
2110 The_Parent_Last := The_Parent_Last - 1;
2113 if Current_Verbosity = High then
2114 Write_Str ("Locate_Directory (""");
2115 Write_Str (The_Name);
2116 Write_Str (""", """);
2117 Write_Str (The_Parent);
2121 if Is_Absolute_Path (The_Name) then
2122 if Is_Directory (The_Name) then
2128 Full_Path : constant String :=
2129 The_Parent (The_Parent'First .. The_Parent_Last) &
2133 if Is_Directory (Full_Path) then
2134 Name_Len := Full_Path'Length;
2135 Name_Buffer (1 .. Name_Len) := Full_Path;
2143 end Locate_Directory;
2149 function Path_Name_Of
2150 (File_Name : String_Id;
2151 Directory : String_Id)
2154 Result : String_Access;
2157 String_To_Name_Buffer (File_Name);
2160 The_File_Name : constant String := Name_Buffer (1 .. Name_Len);
2163 String_To_Name_Buffer (Directory);
2164 Result := Locate_Regular_File
2165 (File_Name => The_File_Name,
2166 Path => Name_Buffer (1 .. Name_Len));
2169 if Result = null then
2172 Canonical_Case_File_Name (Result.all);
2177 function Path_Name_Of
2178 (File_Name : String_Id;
2179 Directory : Name_Id)
2182 Result : String_Access;
2183 The_Directory : constant String := Get_Name_String (Directory);
2186 String_To_Name_Buffer (File_Name);
2187 Result := Locate_Regular_File
2188 (File_Name => Name_Buffer (1 .. Name_Len),
2189 Path => The_Directory);
2191 if Result = null then
2194 Canonical_Case_File_Name (Result.all);
2203 procedure Record_Source
2204 (File_Name : Name_Id;
2205 Path_Name : Name_Id;
2206 Project : Project_Id;
2207 Data : in out Project_Data;
2208 Location : Source_Ptr;
2209 Current_Source : in out String_List_Id)
2211 Unit_Name : Name_Id;
2212 Unit_Kind : Spec_Or_Body;
2213 Needs_Pragma : Boolean;
2214 The_Location : Source_Ptr := Location;
2217 -- Find out the unit name, the unit kind and if it needs
2218 -- a specific SFN pragma.
2221 (File_Name => File_Name,
2222 Naming => Data.Naming,
2223 Unit_Name => Unit_Name,
2224 Unit_Kind => Unit_Kind,
2225 Needs_Pragma => Needs_Pragma);
2227 -- If it is not a source file, report an error only if
2228 -- Error_If_Invalid is true.
2230 if Unit_Name = No_Name then
2231 if Current_Verbosity = High then
2233 Write_Str (Get_Name_String (File_Name));
2234 Write_Line (""" is not a valid source file name (ignored).");
2238 -- Put the file name in the list of sources of the project
2240 String_Elements.Increment_Last;
2241 Get_Name_String (File_Name);
2243 Store_String_Chars (Name_Buffer (1 .. Name_Len));
2244 String_Elements.Table (String_Elements.Last) :=
2245 (Value => End_String,
2246 Location => No_Location,
2247 Next => Nil_String);
2249 if Current_Source = Nil_String then
2250 Data.Sources := String_Elements.Last;
2253 String_Elements.Table (Current_Source).Next :=
2254 String_Elements.Last;
2257 Current_Source := String_Elements.Last;
2259 -- Put the unit in unit list
2262 The_Unit : Unit_Id := Units_Htable.Get (Unit_Name);
2263 The_Unit_Data : Unit_Data;
2266 if Current_Verbosity = High then
2267 Write_Str ("Putting ");
2268 Write_Str (Get_Name_String (Unit_Name));
2269 Write_Line (" in the unit list.");
2272 -- The unit is already in the list, but may be it is
2273 -- only the other unit kind (spec or body), or what is
2274 -- in the unit list is a unit of a project we are modifying.
2276 if The_Unit /= Prj.Com.No_Unit then
2277 The_Unit_Data := Units.Table (The_Unit);
2279 if The_Unit_Data.File_Names (Unit_Kind).Name = No_Name
2280 or else (Data.Modifies /= No_Project
2282 The_Unit_Data.File_Names (Unit_Kind).Project =
2285 The_Unit_Data.File_Names (Unit_Kind) :=
2289 Needs_Pragma => Needs_Pragma);
2290 Units.Table (The_Unit) := The_Unit_Data;
2293 -- It is an error to have two units with the same name
2294 -- and the same kind (spec or body).
2296 if The_Location = No_Location then
2297 The_Location := Projects.Table (Project).Location;
2300 Error_Msg_Name_1 := Unit_Name;
2301 Error_Msg ("duplicate source {", The_Location);
2305 (The_Unit_Data.File_Names (Unit_Kind).Project).Name;
2307 The_Unit_Data.File_Names (Unit_Kind).Path;
2308 Error_Msg ("\ project file {, {", The_Location);
2310 Error_Msg_Name_1 := Projects.Table (Project).Name;
2311 Error_Msg_Name_2 := Path_Name;
2312 Error_Msg ("\ project file {, {", The_Location);
2316 -- It is a new unit, create a new record
2319 Units.Increment_Last;
2320 The_Unit := Units.Last;
2321 Units_Htable.Set (Unit_Name, The_Unit);
2322 The_Unit_Data.Name := Unit_Name;
2323 The_Unit_Data.File_Names (Unit_Kind) :=
2327 Needs_Pragma => Needs_Pragma);
2328 Units.Table (The_Unit) := The_Unit_Data;
2334 ----------------------
2335 -- Show_Source_Dirs --
2336 ----------------------
2338 procedure Show_Source_Dirs (Project : Project_Id) is
2339 Current : String_List_Id := Projects.Table (Project).Source_Dirs;
2340 Element : String_Element;
2343 Write_Line ("Source_Dirs:");
2345 while Current /= Nil_String loop
2346 Element := String_Elements.Table (Current);
2348 Write_Line (Get_Name_String (Element.Value));
2349 Current := Element.Next;
2352 Write_Line ("end Source_Dirs.");
2353 end Show_Source_Dirs;