OSDN Git Service

2006-10-31 Vincent Celier <celier@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / prj-nmsc.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                             P R J . N M S C                              --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2000-2006, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- GNAT was originally developed  by the GNAT team at  New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
24 --                                                                          --
25 ------------------------------------------------------------------------------
26
27 with Err_Vars; use Err_Vars;
28 with Fmap;     use Fmap;
29 with Hostparm;
30 with MLib.Tgt; use MLib.Tgt;
31 with Namet;    use Namet;
32 with Osint;    use Osint;
33 with Output;   use Output;
34 with Prj.Env;  use Prj.Env;
35 with Prj.Err;
36 with Prj.Util; use Prj.Util;
37 with Sinput.P;
38 with Snames;   use Snames;
39 with Table;    use Table;
40 with Targparm; use Targparm;
41
42 with Ada.Characters.Handling;    use Ada.Characters.Handling;
43 with Ada.Strings;                use Ada.Strings;
44 with Ada.Strings.Fixed;          use Ada.Strings.Fixed;
45 with Ada.Strings.Maps.Constants; use Ada.Strings.Maps.Constants;
46
47 with GNAT.Case_Util;             use GNAT.Case_Util;
48 with GNAT.Directory_Operations;  use GNAT.Directory_Operations;
49 with GNAT.HTable;
50
51 package body Prj.Nmsc is
52
53    Error_Report : Put_Line_Access := null;
54    --  Set to point to error reporting procedure
55
56    When_No_Sources : Error_Warning := Error;
57    --  Indicates what should be done when there is no Ada sources in a non
58    --  extending Ada project.
59
60    ALI_Suffix   : constant String := ".ali";
61    --  File suffix for ali files
62
63    Object_Suffix : constant String := Get_Target_Object_Suffix.all;
64    --  File suffix for object files
65
66    type Name_Location is record
67       Name     : Name_Id;
68       Location : Source_Ptr;
69       Found    : Boolean := False;
70    end record;
71    --  Information about file names found in string list attribute
72    --  Source_Files or in a source list file, stored in hash table
73    --  Source_Names, used by procedure Get_Path_Names_And_Record_Sources.
74
75    No_Name_Location : constant Name_Location :=
76      (Name => No_Name, Location => No_Location, Found => False);
77
78    package Source_Names is new GNAT.HTable.Simple_HTable
79      (Header_Num => Header_Num,
80       Element    => Name_Location,
81       No_Element => No_Name_Location,
82       Key        => Name_Id,
83       Hash       => Hash,
84       Equal      => "=");
85    --  Hash table to store file names found in string list attribute
86    --  Source_Files or in a source list file, stored in hash table
87    --  Source_Names, used by procedure Get_Path_Names_And_Record_Sources.
88
89    package Recursive_Dirs is new GNAT.HTable.Simple_HTable
90      (Header_Num => Header_Num,
91       Element    => Boolean,
92       No_Element => False,
93       Key        => Name_Id,
94       Hash       => Hash,
95       Equal      => "=");
96    --  Hash table to store recursive source directories, to avoid looking
97    --  several times, and to avoid cycles that may be introduced by symbolic
98    --  links.
99
100    type Ada_Naming_Exception_Id is new Nat;
101    No_Ada_Naming_Exception : constant Ada_Naming_Exception_Id := 0;
102
103    type Unit_Info is record
104       Kind : Spec_Or_Body;
105       Unit : Name_Id;
106       Next : Ada_Naming_Exception_Id := No_Ada_Naming_Exception;
107    end record;
108    --  No_Unit : constant Unit_Info :=
109    --              (Specification, No_Name, No_Ada_Naming_Exception);
110
111    package Ada_Naming_Exception_Table is new Table.Table
112      (Table_Component_Type => Unit_Info,
113       Table_Index_Type     => Ada_Naming_Exception_Id,
114       Table_Low_Bound      => 1,
115       Table_Initial        => 20,
116       Table_Increment      => 100,
117       Table_Name           => "Prj.Nmsc.Ada_Naming_Exception_Table");
118
119    package Ada_Naming_Exceptions is new GNAT.HTable.Simple_HTable
120      (Header_Num => Header_Num,
121       Element    => Ada_Naming_Exception_Id,
122       No_Element => No_Ada_Naming_Exception,
123       Key        => Name_Id,
124       Hash       => Hash,
125       Equal      => "=");
126    --  A hash table to store naming exceptions for Ada. For each file name
127    --  there is one or several unit in table Ada_Naming_Exception_Table.
128
129    function Hash (Unit : Unit_Info) return Header_Num;
130
131    type Name_And_Index is record
132       Name  : Name_Id := No_Name;
133       Index : Int     := 0;
134    end record;
135    No_Name_And_Index : constant Name_And_Index :=
136                          (Name => No_Name, Index => 0);
137
138    package Reverse_Ada_Naming_Exceptions is new GNAT.HTable.Simple_HTable
139      (Header_Num => Header_Num,
140       Element    => Name_And_Index,
141       No_Element => No_Name_And_Index,
142       Key        => Unit_Info,
143       Hash       => Hash,
144       Equal      => "=");
145    --  A table to check if a unit with an exceptional name will hide
146    --  a source with a file name following the naming convention.
147
148    function ALI_File_Name (Source : String) return String;
149    --  Return the ALI file name corresponding to a source
150
151    procedure Check_Ada_Name (Name : String; Unit : out Name_Id);
152    --  Check that a name is a valid Ada unit name
153
154    procedure Check_Naming_Scheme
155      (Data    : in out Project_Data;
156       Project : Project_Id;
157       In_Tree : Project_Tree_Ref);
158    --  Check the naming scheme part of Data
159
160    procedure Check_Ada_Naming_Scheme_Validity
161      (Project : Project_Id;
162       In_Tree : Project_Tree_Ref;
163       Naming  : Naming_Data);
164    --  Check that the package Naming is correct
165
166    procedure Check_For_Source
167      (File_Name        : Name_Id;
168       Path_Name        : Name_Id;
169       Project          : Project_Id;
170       In_Tree          : Project_Tree_Ref;
171       Data             : in out Project_Data;
172       Location         : Source_Ptr;
173       Language         : Language_Index;
174       Suffix           : String;
175       Naming_Exception : Boolean);
176    --  Check if a file, with name File_Name and path Path_Name, in a source
177    --  directory is a source for language Language in project Project of
178    --  project tree In_Tree. ???
179
180    procedure Check_If_Externally_Built
181      (Project : Project_Id;
182       In_Tree : Project_Tree_Ref;
183       Data    : in out Project_Data);
184    --  Check attribute Externally_Built of project Project in project tree
185    --  In_Tree and modify its data Data if it has the value "true".
186
187    procedure Check_Library_Attributes
188      (Project   : Project_Id;
189       In_Tree : Project_Tree_Ref;
190       Data      : in out Project_Data);
191    --  Check the library attributes of project Project in project tree In_Tree
192    --  and modify its data Data accordingly.
193
194    procedure Check_Package_Naming
195      (Project : Project_Id;
196       In_Tree : Project_Tree_Ref;
197       Data    : in out Project_Data);
198    --  Check package Naming of project Project in project tree In_Tree and
199    --  modify its data Data accordingly.
200
201    procedure Check_Programming_Languages
202      (In_Tree : Project_Tree_Ref; Data : in out Project_Data);
203    --  Check attribute Languages for the project with data Data in project
204    --  tree In_Tree and set the components of Data for all the programming
205    --  languages indicated in attribute Languages, if any.
206
207    function Check_Project
208      (P            : Project_Id;
209       Root_Project : Project_Id;
210       In_Tree      : Project_Tree_Ref;
211       Extending    : Boolean) return Boolean;
212    --  Returns True if P is Root_Project or, if Extending is True, a project
213    --  extended by Root_Project.
214
215    procedure Check_Stand_Alone_Library
216      (Project   : Project_Id;
217       In_Tree   : Project_Tree_Ref;
218       Data      : in out Project_Data;
219       Extending : Boolean);
220    --  Check if project Project in project tree In_Tree is a Stand-Alone
221    --  Library project, and modify its data Data accordingly if it is one.
222
223    function Compute_Directory_Last (Dir : String) return Natural;
224    --  Return the index of the last significant character in Dir. This is used
225    --  to avoid duplicates '/' at the end of directory names
226
227    function Body_Suffix_Of
228      (Language   : Language_Index;
229       In_Project : Project_Data;
230       In_Tree    : Project_Tree_Ref)
231       return String;
232    --  Returns the suffix of sources of language Language in project In_Project
233    --  in project tree In_Tree.
234
235    procedure Error_Msg
236      (Project       : Project_Id;
237       In_Tree       : Project_Tree_Ref;
238       Msg           : String;
239       Flag_Location : Source_Ptr);
240    --  Output an error message. If Error_Report is null, simply call
241    --  Prj.Err.Error_Msg. Otherwise, disregard Flag_Location and use
242    --  Error_Report.
243
244    procedure Find_Sources
245      (Project      : Project_Id;
246       In_Tree      : Project_Tree_Ref;
247       Data         : in out Project_Data;
248       For_Language : Language_Index;
249       Follow_Links : Boolean := False);
250    --  Find all the sources in all of the source directories of a project for
251    --  a specified language.
252
253    procedure Free_Ada_Naming_Exceptions;
254    --  Free the internal hash tables used for checking naming exceptions
255
256    procedure Get_Directories
257      (Project : Project_Id;
258       In_Tree : Project_Tree_Ref;
259       Data    : in out Project_Data);
260    --  Get the object directory, the exec directory and the source directories
261    --  of a project.
262
263    procedure Get_Mains
264      (Project : Project_Id;
265       In_Tree : Project_Tree_Ref;
266       Data    : in out Project_Data);
267    --  Get the mains of a project from attribute Main, if it exists, and put
268    --  them in the project data.
269
270    procedure Get_Sources_From_File
271      (Path     : String;
272       Location : Source_Ptr;
273       Project  : Project_Id;
274       In_Tree  : Project_Tree_Ref);
275    --  Get the list of sources from a text file and put them in hash table
276    --  Source_Names.
277
278    procedure Get_Unit
279      (Canonical_File_Name : Name_Id;
280       Naming              : Naming_Data;
281       Exception_Id        : out Ada_Naming_Exception_Id;
282       Unit_Name           : out Name_Id;
283       Unit_Kind           : out Spec_Or_Body;
284       Needs_Pragma        : out Boolean);
285    --  Find out, from a file name, the unit name, the unit kind and if a
286    --  specific SFN pragma is needed. If the file name corresponds to no
287    --  unit, then Unit_Name will be No_Name. If the file is a multi-unit source
288    --  or an exception to the naming scheme, then Exception_Id is set to
289    --  the unit or units that the source contains.
290
291    function Is_Illegal_Suffix
292      (Suffix                          : String;
293       Dot_Replacement_Is_A_Single_Dot : Boolean) return Boolean;
294    --  Returns True if the string Suffix cannot be used as
295    --  a spec suffix, a body suffix or a separate suffix.
296
297    procedure Locate_Directory
298      (Name    : Name_Id;
299       Parent  : Name_Id;
300       Dir     : out Name_Id;
301       Display : out Name_Id);
302    --  Locate a directory (returns No_Name for Dir and Display if directory
303    --  does not exist). Name is the directory name. Parent is the root
304    --  directory, if Name is a relative path name. Dir is the canonical case
305    --  path name of the directory, Display is the directory path name for
306    --  display purposes.
307
308    procedure Look_For_Sources
309      (Project      : Project_Id;
310       In_Tree      : Project_Tree_Ref;
311       Data         : in out Project_Data;
312       Follow_Links : Boolean);
313    --  Find all the sources of a project
314
315    function Path_Name_Of
316      (File_Name : Name_Id;
317       Directory : Name_Id) return String;
318    --  Returns the path name of a (non project) file.
319    --  Returns an empty string if file cannot be found.
320
321    procedure Prepare_Ada_Naming_Exceptions
322      (List    : Array_Element_Id;
323       In_Tree : Project_Tree_Ref;
324       Kind    : Spec_Or_Body);
325    --  Prepare the internal hash tables used for checking naming exceptions
326    --  for Ada. Insert all elements of List in the tables.
327
328    function Project_Extends
329      (Extending : Project_Id;
330       Extended  : Project_Id;
331       In_Tree   : Project_Tree_Ref) return Boolean;
332    --  Returns True if Extending is extending Extended either directly or
333    --  indirectly.
334
335    procedure Record_Ada_Source
336      (File_Name       : Name_Id;
337       Path_Name       : Name_Id;
338       Project         : Project_Id;
339       In_Tree         : Project_Tree_Ref;
340       Data            : in out Project_Data;
341       Location        : Source_Ptr;
342       Current_Source  : in out String_List_Id;
343       Source_Recorded : in out Boolean;
344       Follow_Links    : Boolean);
345    --  Put a unit in the list of units of a project, if the file name
346    --  corresponds to a valid unit name.
347
348    procedure Record_Other_Sources
349      (Project           : Project_Id;
350       In_Tree           : Project_Tree_Ref;
351       Data              : in out Project_Data;
352       Language          : Language_Index;
353       Naming_Exceptions : Boolean);
354    --  Record the sources of a language in a project.
355    --  When Naming_Exceptions is True, mark the found sources as such, to
356    --  later remove those that are not named in a list of sources.
357
358    procedure Report_No_Ada_Sources
359      (Project  : Project_Id;
360       In_Tree  : Project_Tree_Ref;
361       Location : Source_Ptr);
362    --  Report an error or a warning depending on the value of When_No_Sources
363
364    procedure Show_Source_Dirs
365      (Project : Project_Id; In_Tree : Project_Tree_Ref);
366    --  List all the source directories of a project
367
368    function Suffix_For
369      (Language : Language_Index;
370       Naming   : Naming_Data;
371       In_Tree  : Project_Tree_Ref) return Name_Id;
372    --  Get the suffix for the source of a language from a package naming.
373    --  If not specified, return the default for the language.
374
375    procedure Warn_If_Not_Sources
376      (Project     : Project_Id;
377       In_Tree     : Project_Tree_Ref;
378       Conventions : Array_Element_Id;
379       Specs       : Boolean;
380       Extending   : Boolean);
381    --  Check that individual naming conventions apply to immediate
382    --  sources of the project; if not, issue a warning.
383
384    -------------------
385    -- ALI_File_Name --
386    -------------------
387
388    function ALI_File_Name (Source : String) return String is
389    begin
390       --  If the source name has an extension, then replace it with
391       --  the ALI suffix.
392
393       for Index in reverse Source'First + 1 .. Source'Last loop
394          if Source (Index) = '.' then
395             return Source (Source'First .. Index - 1) & ALI_Suffix;
396          end if;
397       end loop;
398
399       --  If there is no dot, or if it is the first character, just add the
400       --  ALI suffix.
401
402       return Source & ALI_Suffix;
403    end ALI_File_Name;
404
405    -----------
406    -- Check --
407    -----------
408
409    procedure Check
410      (Project         : Project_Id;
411       In_Tree         : Project_Tree_Ref;
412       Report_Error    : Put_Line_Access;
413       Follow_Links    : Boolean;
414       When_No_Sources : Error_Warning)
415    is
416       Data      : Project_Data := In_Tree.Projects.Table (Project);
417       Extending : Boolean := False;
418
419    begin
420       Nmsc.When_No_Sources := When_No_Sources;
421       Error_Report := Report_Error;
422
423       Recursive_Dirs.Reset;
424
425       --  Object, exec and source directories
426
427       Get_Directories (Project, In_Tree, Data);
428
429       --  Get the programming languages
430
431       Check_Programming_Languages (In_Tree, Data);
432
433       --  Library attributes
434
435       Check_Library_Attributes (Project, In_Tree, Data);
436
437       Check_If_Externally_Built (Project, In_Tree, Data);
438
439       if Current_Verbosity = High then
440          Show_Source_Dirs (Project, In_Tree);
441       end if;
442
443       Check_Package_Naming (Project, In_Tree, Data);
444
445       Extending := Data.Extends /= No_Project;
446
447       Check_Naming_Scheme (Data, Project, In_Tree);
448
449       Prepare_Ada_Naming_Exceptions
450         (Data.Naming.Bodies, In_Tree, Body_Part);
451       Prepare_Ada_Naming_Exceptions
452         (Data.Naming.Specs, In_Tree, Specification);
453
454       --  Find the sources
455
456       if Data.Source_Dirs /= Nil_String then
457          Look_For_Sources (Project, In_Tree, Data, Follow_Links);
458       end if;
459
460       if Data.Ada_Sources_Present then
461
462          --  Check that all individual naming conventions apply to sources of
463          --  this project file.
464
465          Warn_If_Not_Sources
466            (Project, In_Tree, Data.Naming.Bodies,
467             Specs     => False,
468             Extending => Extending);
469          Warn_If_Not_Sources
470            (Project, In_Tree, Data.Naming.Specs,
471             Specs     => True,
472             Extending => Extending);
473       end if;
474
475       --  If it is a library project file, check if it is a standalone library
476
477       if Data.Library then
478          Check_Stand_Alone_Library (Project, In_Tree, Data, Extending);
479       end if;
480
481       --  Put the list of Mains, if any, in the project data
482
483       Get_Mains (Project, In_Tree, Data);
484
485       --  Update the project data in the Projects table
486
487       In_Tree.Projects.Table (Project) := Data;
488
489       Free_Ada_Naming_Exceptions;
490    end Check;
491
492    --------------------
493    -- Check_Ada_Name --
494    --------------------
495
496    procedure Check_Ada_Name (Name : String; Unit : out Name_Id) is
497       The_Name        : String := Name;
498       Real_Name       : Name_Id;
499       Need_Letter     : Boolean := True;
500       Last_Underscore : Boolean := False;
501       OK              : Boolean := The_Name'Length > 0;
502
503    begin
504       To_Lower (The_Name);
505
506       Name_Len := The_Name'Length;
507       Name_Buffer (1 .. Name_Len) := The_Name;
508
509       --  Special cases of children of packages A, G, I and S on VMS
510
511       if OpenVMS_On_Target and then
512         Name_Len > 3 and then
513         Name_Buffer (2 .. 3) = "__" and then
514         ((Name_Buffer (1) = 'a') or else (Name_Buffer (1) = 'g') or else
515          (Name_Buffer (1) = 'i') or else (Name_Buffer (1) = 's'))
516       then
517          Name_Buffer (2) := '.';
518          Name_Buffer (3 .. Name_Len - 1) := Name_Buffer (4 .. Name_Len);
519          Name_Len := Name_Len - 1;
520       end if;
521
522       Real_Name := Name_Find;
523
524       --  Check first that the given name is not an Ada reserved word
525
526       if Get_Name_Table_Byte (Real_Name) /= 0
527         and then Real_Name /= Name_Project
528         and then Real_Name /= Name_Extends
529         and then Real_Name /= Name_External
530       then
531          Unit := No_Name;
532
533          if Current_Verbosity = High then
534             Write_Str (The_Name);
535             Write_Line (" is an Ada reserved word.");
536          end if;
537
538          return;
539       end if;
540
541       for Index in The_Name'Range loop
542          if Need_Letter then
543
544             --  We need a letter (at the beginning, and following a dot),
545             --  but we don't have one.
546
547             if Is_Letter (The_Name (Index)) then
548                Need_Letter := False;
549
550             else
551                OK := False;
552
553                if Current_Verbosity = High then
554                   Write_Int  (Types.Int (Index));
555                   Write_Str  (": '");
556                   Write_Char (The_Name (Index));
557                   Write_Line ("' is not a letter.");
558                end if;
559
560                exit;
561             end if;
562
563          elsif Last_Underscore
564            and then (The_Name (Index) = '_' or else The_Name (Index) = '.')
565          then
566             --  Two underscores are illegal, and a dot cannot follow
567             --  an underscore.
568
569             OK := False;
570
571             if Current_Verbosity = High then
572                Write_Int  (Types.Int (Index));
573                Write_Str  (": '");
574                Write_Char (The_Name (Index));
575                Write_Line ("' is illegal here.");
576             end if;
577
578             exit;
579
580          elsif The_Name (Index) = '.' then
581
582             --  We need a letter after a dot
583
584             Need_Letter := True;
585
586          elsif The_Name (Index) = '_' then
587             Last_Underscore := True;
588
589          else
590             --  We need an letter or a digit
591
592             Last_Underscore := False;
593
594             if not Is_Alphanumeric (The_Name (Index)) then
595                OK := False;
596
597                if Current_Verbosity = High then
598                   Write_Int  (Types.Int (Index));
599                   Write_Str  (": '");
600                   Write_Char (The_Name (Index));
601                   Write_Line ("' is not alphanumeric.");
602                end if;
603
604                exit;
605             end if;
606          end if;
607       end loop;
608
609       --  Cannot end with an underscore or a dot
610
611       OK := OK and then not Need_Letter and then not Last_Underscore;
612
613       if OK then
614          Unit := Real_Name;
615
616       else
617          --  Signal a problem with No_Name
618
619          Unit := No_Name;
620       end if;
621    end Check_Ada_Name;
622
623    --------------------------------------
624    -- Check_Ada_Naming_Scheme_Validity --
625    --------------------------------------
626
627    procedure Check_Ada_Naming_Scheme_Validity
628      (Project : Project_Id;
629       In_Tree : Project_Tree_Ref;
630       Naming  : Naming_Data)
631    is
632    begin
633       --  Only check if we are not using the Default naming scheme
634
635       if Naming /= In_Tree.Private_Part.Default_Naming then
636          declare
637             Dot_Replacement       : constant String :=
638                                      Get_Name_String
639                                        (Naming.Dot_Replacement);
640
641             Spec_Suffix : constant String :=
642                                      Get_Name_String
643                                        (Naming.Ada_Spec_Suffix);
644
645             Body_Suffix : constant String :=
646                                      Get_Name_String
647                                        (Naming.Ada_Body_Suffix);
648
649             Separate_Suffix       : constant String :=
650                                      Get_Name_String
651                                        (Naming.Separate_Suffix);
652
653          begin
654             --  Dot_Replacement cannot
655             --   - be empty
656             --   - start or end with an alphanumeric
657             --   - be a single '_'
658             --   - start with an '_' followed by an alphanumeric
659             --   - contain a '.' except if it is "."
660
661             if Dot_Replacement'Length = 0
662               or else Is_Alphanumeric
663                         (Dot_Replacement (Dot_Replacement'First))
664               or else Is_Alphanumeric
665                         (Dot_Replacement (Dot_Replacement'Last))
666               or else (Dot_Replacement (Dot_Replacement'First) = '_'
667                         and then
668                         (Dot_Replacement'Length = 1
669                           or else
670                            Is_Alphanumeric
671                              (Dot_Replacement (Dot_Replacement'First + 1))))
672               or else (Dot_Replacement'Length > 1
673                          and then
674                            Index (Source => Dot_Replacement,
675                                   Pattern => ".") /= 0)
676             then
677                Error_Msg
678                  (Project, In_Tree,
679                   '"' & Dot_Replacement &
680                   """ is illegal for Dot_Replacement.",
681                   Naming.Dot_Repl_Loc);
682             end if;
683
684             --  Suffixes cannot
685             --   - be empty
686
687             if Is_Illegal_Suffix
688                  (Spec_Suffix, Dot_Replacement = ".")
689             then
690                Err_Vars.Error_Msg_Name_1 := Naming.Ada_Spec_Suffix;
691                Error_Msg
692                  (Project, In_Tree,
693                   "{ is illegal for Spec_Suffix",
694                   Naming.Spec_Suffix_Loc);
695             end if;
696
697             if Is_Illegal_Suffix
698                  (Body_Suffix, Dot_Replacement = ".")
699             then
700                Err_Vars.Error_Msg_Name_1 := Naming.Ada_Body_Suffix;
701                Error_Msg
702                  (Project, In_Tree,
703                   "{ is illegal for Body_Suffix",
704                   Naming.Body_Suffix_Loc);
705             end if;
706
707             if Body_Suffix /= Separate_Suffix then
708                if Is_Illegal_Suffix
709                     (Separate_Suffix, Dot_Replacement = ".")
710                then
711                   Err_Vars.Error_Msg_Name_1 := Naming.Separate_Suffix;
712                   Error_Msg
713                     (Project, In_Tree,
714                      "{ is illegal for Separate_Suffix",
715                      Naming.Sep_Suffix_Loc);
716                end if;
717             end if;
718
719             --  Spec_Suffix cannot have the same termination as
720             --  Body_Suffix or Separate_Suffix
721
722             if Spec_Suffix'Length <= Body_Suffix'Length
723               and then
724                 Body_Suffix (Body_Suffix'Last -
725                              Spec_Suffix'Length + 1 ..
726                              Body_Suffix'Last) = Spec_Suffix
727             then
728                Error_Msg
729                  (Project, In_Tree,
730                   "Body_Suffix (""" &
731                   Body_Suffix &
732                   """) cannot end with" &
733                   " Spec_Suffix  (""" &
734                   Spec_Suffix & """).",
735                   Naming.Body_Suffix_Loc);
736             end if;
737
738             if Body_Suffix /= Separate_Suffix
739               and then Spec_Suffix'Length <= Separate_Suffix'Length
740               and then
741                 Separate_Suffix
742                   (Separate_Suffix'Last - Spec_Suffix'Length + 1
743                     ..
744                    Separate_Suffix'Last) = Spec_Suffix
745             then
746                Error_Msg
747                  (Project, In_Tree,
748                   "Separate_Suffix (""" &
749                   Separate_Suffix &
750                   """) cannot end with" &
751                   " Spec_Suffix (""" &
752                   Spec_Suffix & """).",
753                   Naming.Sep_Suffix_Loc);
754             end if;
755          end;
756       end if;
757    end Check_Ada_Naming_Scheme_Validity;
758
759    ----------------------
760    -- Check_For_Source --
761    ----------------------
762
763    procedure Check_For_Source
764      (File_Name        : Name_Id;
765       Path_Name        : Name_Id;
766       Project          : Project_Id;
767       In_Tree          : Project_Tree_Ref;
768       Data             : in out Project_Data;
769       Location         : Source_Ptr;
770       Language         : Language_Index;
771       Suffix           : String;
772       Naming_Exception : Boolean)
773    is
774       Name : String := Get_Name_String (File_Name);
775       Real_Location : Source_Ptr := Location;
776
777    begin
778       Canonical_Case_File_Name (Name);
779
780       --  A file is a source of a language if Naming_Exception is True (case
781       --  of naming exceptions) or if its file name ends with the suffix.
782
783       if Naming_Exception or else
784         (Name'Length > Suffix'Length and then
785          Name (Name'Last - Suffix'Length + 1 .. Name'Last) = Suffix)
786       then
787          if Real_Location = No_Location then
788             Real_Location := Data.Location;
789          end if;
790
791          declare
792             Path : String := Get_Name_String (Path_Name);
793
794             Path_Id : Name_Id;
795             --  The path name id (in canonical case)
796
797             File_Id : Name_Id;
798             --  The file name id (in canonical case)
799
800             Obj_Id : Name_Id;
801             --  The object file name
802
803             Obj_Path_Id : Name_Id;
804             --  The object path name
805
806             Dep_Id : Name_Id;
807             --  The dependency file name
808
809             Dep_Path_Id : Name_Id;
810             --  The dependency path name
811
812             Dot_Pos : Natural := 0;
813             --  Position of the last dot in Name
814
815             Source    : Other_Source;
816             Source_Id : Other_Source_Id := Data.First_Other_Source;
817
818          begin
819             Canonical_Case_File_Name (Path);
820
821             --  Get the file name id
822
823             Name_Len := Name'Length;
824             Name_Buffer (1 .. Name_Len) := Name;
825             File_Id := Name_Find;
826
827             --  Get the path name id
828
829             Name_Len := Path'Length;
830             Name_Buffer (1 .. Name_Len) := Path;
831             Path_Id := Name_Find;
832
833             --  Find the position of the last dot
834
835             for J in reverse Name'Range loop
836                if Name (J) = '.' then
837                   Dot_Pos := J;
838                   exit;
839                end if;
840             end loop;
841
842             if Dot_Pos <= Name'First then
843                Dot_Pos := Name'Last + 1;
844             end if;
845
846             --  Compute the object file name
847
848             Get_Name_String (File_Id);
849             Name_Len := Dot_Pos - Name'First;
850
851             for J in Object_Suffix'Range loop
852                Name_Len := Name_Len + 1;
853                Name_Buffer (Name_Len) := Object_Suffix (J);
854             end loop;
855
856             Obj_Id := Name_Find;
857
858             --  Compute the object path name
859
860             Get_Name_String (Data.Object_Directory);
861
862             if Name_Buffer (Name_Len) /= Directory_Separator and then
863               Name_Buffer (Name_Len) /= '/'
864             then
865                Name_Len := Name_Len + 1;
866                Name_Buffer (Name_Len) := Directory_Separator;
867             end if;
868
869             Add_Str_To_Name_Buffer (Get_Name_String (Obj_Id));
870             Obj_Path_Id := Name_Find;
871
872             --  Compute the dependency file name
873
874             Get_Name_String (File_Id);
875             Name_Len := Dot_Pos - Name'First + 1;
876             Name_Buffer (Name_Len) := '.';
877             Name_Len := Name_Len + 1;
878             Name_Buffer (Name_Len) := 'd';
879             Dep_Id := Name_Find;
880
881             --  Compute the dependency path name
882
883             Get_Name_String (Data.Object_Directory);
884
885             if Name_Buffer (Name_Len) /= Directory_Separator and then
886               Name_Buffer (Name_Len) /= '/'
887             then
888                Name_Len := Name_Len + 1;
889                Name_Buffer (Name_Len) := Directory_Separator;
890             end if;
891
892             Add_Str_To_Name_Buffer (Get_Name_String (Dep_Id));
893             Dep_Path_Id := Name_Find;
894
895             --  Check if source is already in the list of source for this
896             --  project: it may have already been specified as a naming
897             --  exception for the same language or an other language, or
898             --  they may be two identical file names in different source
899             --  directories.
900
901             while Source_Id /= No_Other_Source loop
902                Source := In_Tree.Other_Sources.Table (Source_Id);
903
904                if Source.File_Name = File_Id then
905
906                   --  Two sources of different languages cannot have the same
907                   --  file name.
908
909                   if Source.Language /= Language then
910                      Error_Msg_Name_1 := File_Name;
911                      Error_Msg
912                        (Project, In_Tree,
913                         "{ cannot be a source of several languages",
914                         Real_Location);
915                      return;
916
917                   --  No problem if a file has already been specified as
918                   --  a naming exception of this language.
919
920                   elsif Source.Path_Name = Path_Id then
921
922                      --  Reset the naming exception flag, if this is not a
923                      --  naming exception.
924
925                      if not Naming_Exception then
926                         In_Tree.Other_Sources.Table
927                           (Source_Id).Naming_Exception := False;
928                      end if;
929
930                      return;
931
932                   --  There are several files with the same names, but the
933                   --  order of the source directories is known (no /**):
934                   --  only the first one encountered is kept, the other ones
935                   --  are ignored.
936
937                   elsif Data.Known_Order_Of_Source_Dirs then
938                      return;
939
940                   --  But it is an error if the order of the source directories
941                   --  is not known.
942
943                   else
944                      Error_Msg_Name_1 := File_Name;
945                      Error_Msg
946                        (Project, In_Tree,
947                         "{ is found in several source directories",
948                         Real_Location);
949                      return;
950                   end if;
951
952                --  Two sources with different file names cannot have the same
953                --  object file name.
954
955                elsif Source.Object_Name = Obj_Id then
956                   Error_Msg_Name_1 := File_Id;
957                   Error_Msg_Name_2 := Source.File_Name;
958                   Error_Msg_Name_3 := Obj_Id;
959                   Error_Msg
960                        (Project, In_Tree,
961                         "{ and { have the same object file {",
962                         Real_Location);
963                      return;
964                end if;
965
966                Source_Id := Source.Next;
967             end loop;
968
969             if Current_Verbosity = High then
970                Write_Str ("      found ");
971                Display_Language_Name (Language);
972                Write_Str (" source """);
973                Write_Str (Get_Name_String (File_Name));
974                Write_Line ("""");
975                Write_Str ("      object path = ");
976                Write_Line (Get_Name_String (Obj_Path_Id));
977             end if;
978
979             --  Create the Other_Source record
980
981             Source :=
982               (Language         => Language,
983                File_Name        => File_Id,
984                Path_Name        => Path_Id,
985                Source_TS        => File_Stamp (Path_Id),
986                Object_Name      => Obj_Id,
987                Object_Path      => Obj_Path_Id,
988                Object_TS        => File_Stamp (Obj_Path_Id),
989                Dep_Name         => Dep_Id,
990                Dep_Path         => Dep_Path_Id,
991                Dep_TS           => File_Stamp (Dep_Path_Id),
992                Naming_Exception => Naming_Exception,
993                Next             => No_Other_Source);
994
995             --  And add it to the Other_Sources table
996
997             Other_Source_Table.Increment_Last
998               (In_Tree.Other_Sources);
999             In_Tree.Other_Sources.Table
1000               (Other_Source_Table.Last (In_Tree.Other_Sources)) :=
1001                  Source;
1002
1003             --  There are sources of languages other than Ada in this project
1004
1005             Data.Other_Sources_Present := True;
1006
1007             --  And there are sources of this language in this project
1008
1009             Set (Language, True, Data, In_Tree);
1010
1011             --  Add this source to the list of sources of languages other than
1012             --  Ada of the project.
1013
1014             if Data.First_Other_Source = No_Other_Source then
1015                Data.First_Other_Source :=
1016                  Other_Source_Table.Last (In_Tree.Other_Sources);
1017
1018             else
1019                In_Tree.Other_Sources.Table (Data.Last_Other_Source).Next :=
1020                  Other_Source_Table.Last (In_Tree.Other_Sources);
1021             end if;
1022
1023             Data.Last_Other_Source :=
1024               Other_Source_Table.Last (In_Tree.Other_Sources);
1025          end;
1026       end if;
1027    end Check_For_Source;
1028
1029    -------------------------------
1030    -- Check_If_Externally_Built --
1031    -------------------------------
1032
1033    procedure Check_If_Externally_Built
1034      (Project : Project_Id;
1035       In_Tree : Project_Tree_Ref;
1036       Data    : in out Project_Data)
1037    is
1038       Externally_Built : constant Variable_Value :=
1039                            Util.Value_Of
1040                             (Name_Externally_Built,
1041                              Data.Decl.Attributes, In_Tree);
1042
1043    begin
1044       if not Externally_Built.Default then
1045          Get_Name_String (Externally_Built.Value);
1046          To_Lower (Name_Buffer (1 .. Name_Len));
1047
1048          if Name_Buffer (1 .. Name_Len) = "true" then
1049             Data.Externally_Built := True;
1050
1051          elsif Name_Buffer (1 .. Name_Len) /= "false" then
1052             Error_Msg (Project, In_Tree,
1053                        "Externally_Built may only be true or false",
1054                        Externally_Built.Location);
1055          end if;
1056       end if;
1057
1058       if Current_Verbosity = High then
1059          Write_Str ("Project is ");
1060
1061          if not Data.Externally_Built then
1062             Write_Str ("not ");
1063          end if;
1064
1065          Write_Line ("externally built.");
1066       end if;
1067    end Check_If_Externally_Built;
1068
1069    -----------------------------
1070    -- Check_Naming_Scheme --
1071    -----------------------------
1072
1073    procedure Check_Naming_Scheme
1074      (Data    : in out Project_Data;
1075       Project : Project_Id;
1076       In_Tree : Project_Tree_Ref)
1077    is
1078       Naming_Id : constant Package_Id :=
1079                     Util.Value_Of (Name_Naming, Data.Decl.Packages, In_Tree);
1080
1081       Naming : Package_Element;
1082
1083       procedure Check_Unit_Names (List : Array_Element_Id);
1084       --  Check that a list of unit names contains only valid names
1085
1086       ----------------------
1087       -- Check_Unit_Names --
1088       ----------------------
1089
1090       procedure Check_Unit_Names (List : Array_Element_Id) is
1091          Current   : Array_Element_Id := List;
1092          Element   : Array_Element;
1093          Unit_Name : Name_Id;
1094
1095       begin
1096          --  Loop through elements of the string list
1097
1098          while Current /= No_Array_Element loop
1099             Element := In_Tree.Array_Elements.Table (Current);
1100
1101             --  Put file name in canonical case
1102
1103             Get_Name_String (Element.Value.Value);
1104             Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1105             Element.Value.Value := Name_Find;
1106
1107             --  Check that it contains a valid unit name
1108
1109             Get_Name_String (Element.Index);
1110             Check_Ada_Name (Name_Buffer (1 .. Name_Len), Unit_Name);
1111
1112             if Unit_Name = No_Name then
1113                Err_Vars.Error_Msg_Name_1 := Element.Index;
1114                Error_Msg
1115                  (Project, In_Tree,
1116                   "{ is not a valid unit name.",
1117                   Element.Value.Location);
1118
1119             else
1120                if Current_Verbosity = High then
1121                   Write_Str ("    Unit (""");
1122                   Write_Str (Get_Name_String (Unit_Name));
1123                   Write_Line (""")");
1124                end if;
1125
1126                Element.Index := Unit_Name;
1127                In_Tree.Array_Elements.Table (Current) := Element;
1128             end if;
1129
1130             Current := Element.Next;
1131          end loop;
1132       end Check_Unit_Names;
1133
1134    --  Start of processing for Check_Naming_Scheme
1135
1136    begin
1137       --  If there is a package Naming, we will put in Data.Naming what is in
1138       --  this package Naming.
1139
1140       if Naming_Id /= No_Package then
1141          Naming := In_Tree.Packages.Table (Naming_Id);
1142
1143          if Current_Verbosity = High then
1144             Write_Line ("Checking ""Naming"" for Ada.");
1145          end if;
1146
1147          declare
1148             Bodies : constant Array_Element_Id :=
1149                        Util.Value_Of (Name_Body, Naming.Decl.Arrays, In_Tree);
1150
1151             Specs : constant Array_Element_Id :=
1152                       Util.Value_Of (Name_Spec, Naming.Decl.Arrays, In_Tree);
1153
1154          begin
1155             if Bodies /= No_Array_Element then
1156
1157                --  We have elements in the array Body_Part
1158
1159                if Current_Verbosity = High then
1160                   Write_Line ("Found Bodies.");
1161                end if;
1162
1163                Data.Naming.Bodies := Bodies;
1164                Check_Unit_Names (Bodies);
1165
1166             else
1167                if Current_Verbosity = High then
1168                   Write_Line ("No Bodies.");
1169                end if;
1170             end if;
1171
1172             if Specs /= No_Array_Element then
1173
1174                --  We have elements in the array Specs
1175
1176                if Current_Verbosity = High then
1177                   Write_Line ("Found Specs.");
1178                end if;
1179
1180                Data.Naming.Specs := Specs;
1181                Check_Unit_Names (Specs);
1182
1183             else
1184                if Current_Verbosity = High then
1185                   Write_Line ("No Specs.");
1186                end if;
1187             end if;
1188          end;
1189
1190          --  We are now checking if variables Dot_Replacement, Casing,
1191          --  Spec_Suffix, Body_Suffix and/or Separate_Suffix
1192          --  exist.
1193
1194          --  For each variable, if it does not exist, we do nothing,
1195          --  because we already have the default.
1196
1197          --  Check Dot_Replacement
1198
1199          declare
1200             Dot_Replacement : constant Variable_Value :=
1201                                 Util.Value_Of
1202                                   (Name_Dot_Replacement,
1203                                    Naming.Decl.Attributes, In_Tree);
1204
1205          begin
1206             pragma Assert (Dot_Replacement.Kind = Single,
1207                            "Dot_Replacement is not a single string");
1208
1209             if not Dot_Replacement.Default then
1210                Get_Name_String (Dot_Replacement.Value);
1211
1212                if Name_Len = 0 then
1213                   Error_Msg
1214                     (Project, In_Tree,
1215                      "Dot_Replacement cannot be empty",
1216                      Dot_Replacement.Location);
1217
1218                else
1219                   Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1220                   Data.Naming.Dot_Replacement := Name_Find;
1221                   Data.Naming.Dot_Repl_Loc := Dot_Replacement.Location;
1222                end if;
1223             end if;
1224          end;
1225
1226          if Current_Verbosity = High then
1227             Write_Str  ("  Dot_Replacement = """);
1228             Write_Str  (Get_Name_String (Data.Naming.Dot_Replacement));
1229             Write_Char ('"');
1230             Write_Eol;
1231          end if;
1232
1233          --  Check Casing
1234
1235          declare
1236             Casing_String : constant Variable_Value :=
1237                               Util.Value_Of
1238                                 (Name_Casing, Naming.Decl.Attributes, In_Tree);
1239
1240          begin
1241             pragma Assert (Casing_String.Kind = Single,
1242                            "Casing is not a single string");
1243
1244             if not Casing_String.Default then
1245                declare
1246                   Casing_Image : constant String :=
1247                                    Get_Name_String (Casing_String.Value);
1248                begin
1249                   declare
1250                      Casing_Value : constant Casing_Type :=
1251                                       Value (Casing_Image);
1252                   begin
1253                      Data.Naming.Casing := Casing_Value;
1254                   end;
1255
1256                exception
1257                   when Constraint_Error =>
1258                      if Casing_Image'Length = 0 then
1259                         Error_Msg
1260                           (Project, In_Tree,
1261                            "Casing cannot be an empty string",
1262                            Casing_String.Location);
1263
1264                      else
1265                         Name_Len := Casing_Image'Length;
1266                         Name_Buffer (1 .. Name_Len) := Casing_Image;
1267                         Err_Vars.Error_Msg_Name_1 := Name_Find;
1268                         Error_Msg
1269                           (Project, In_Tree,
1270                            "{ is not a correct Casing",
1271                            Casing_String.Location);
1272                      end if;
1273                end;
1274             end if;
1275          end;
1276
1277          if Current_Verbosity = High then
1278             Write_Str  ("  Casing = ");
1279             Write_Str  (Image (Data.Naming.Casing));
1280             Write_Char ('.');
1281             Write_Eol;
1282          end if;
1283
1284          --  Check Spec_Suffix
1285
1286          declare
1287             Ada_Spec_Suffix : constant Variable_Value :=
1288                                 Prj.Util.Value_Of
1289                                   (Index     => Name_Ada,
1290                                    Src_Index => 0,
1291                                    In_Array  => Data.Naming.Spec_Suffix,
1292                                    In_Tree   => In_Tree);
1293
1294          begin
1295             if Ada_Spec_Suffix.Kind = Single
1296               and then Get_Name_String (Ada_Spec_Suffix.Value) /= ""
1297             then
1298                Get_Name_String (Ada_Spec_Suffix.Value);
1299                Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1300                Data.Naming.Ada_Spec_Suffix := Name_Find;
1301                Data.Naming.Spec_Suffix_Loc := Ada_Spec_Suffix.Location;
1302
1303             else
1304                Data.Naming.Ada_Spec_Suffix := Default_Ada_Spec_Suffix;
1305             end if;
1306          end;
1307
1308          if Current_Verbosity = High then
1309             Write_Str  ("  Spec_Suffix = """);
1310             Write_Str  (Get_Name_String (Data.Naming.Ada_Spec_Suffix));
1311             Write_Char ('"');
1312             Write_Eol;
1313          end if;
1314
1315          --  Check Body_Suffix
1316
1317          declare
1318             Ada_Body_Suffix : constant Variable_Value :=
1319               Prj.Util.Value_Of
1320                 (Index     => Name_Ada,
1321                  Src_Index => 0,
1322                  In_Array  => Data.Naming.Body_Suffix,
1323                  In_Tree   => In_Tree);
1324
1325          begin
1326             if Ada_Body_Suffix.Kind = Single
1327               and then Get_Name_String (Ada_Body_Suffix.Value) /= ""
1328             then
1329                Get_Name_String (Ada_Body_Suffix.Value);
1330                Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1331                Data.Naming.Ada_Body_Suffix := Name_Find;
1332                Data.Naming.Body_Suffix_Loc := Ada_Body_Suffix.Location;
1333
1334             else
1335                Data.Naming.Ada_Body_Suffix := Default_Ada_Body_Suffix;
1336             end if;
1337          end;
1338
1339          if Current_Verbosity = High then
1340             Write_Str  ("  Body_Suffix = """);
1341             Write_Str  (Get_Name_String (Data.Naming.Ada_Body_Suffix));
1342             Write_Char ('"');
1343             Write_Eol;
1344          end if;
1345
1346          --  Check Separate_Suffix
1347
1348          declare
1349             Ada_Sep_Suffix : constant Variable_Value :=
1350                                Prj.Util.Value_Of
1351                                  (Variable_Name => Name_Separate_Suffix,
1352                                   In_Variables  => Naming.Decl.Attributes,
1353                                   In_Tree       => In_Tree);
1354
1355          begin
1356             if Ada_Sep_Suffix.Default then
1357                Data.Naming.Separate_Suffix :=
1358                  Data.Naming.Ada_Body_Suffix;
1359
1360             else
1361                Get_Name_String (Ada_Sep_Suffix.Value);
1362
1363                if Name_Len = 0 then
1364                   Error_Msg
1365                     (Project, In_Tree,
1366                      "Separate_Suffix cannot be empty",
1367                      Ada_Sep_Suffix.Location);
1368
1369                else
1370                   Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1371                   Data.Naming.Separate_Suffix := Name_Find;
1372                   Data.Naming.Sep_Suffix_Loc  := Ada_Sep_Suffix.Location;
1373                end if;
1374             end if;
1375          end;
1376
1377          if Current_Verbosity = High then
1378             Write_Str  ("  Separate_Suffix = """);
1379             Write_Str  (Get_Name_String (Data.Naming.Separate_Suffix));
1380             Write_Char ('"');
1381             Write_Eol;
1382          end if;
1383
1384          --  Check if Data.Naming is valid
1385
1386          Check_Ada_Naming_Scheme_Validity (Project, In_Tree, Data.Naming);
1387
1388       else
1389          Data.Naming.Ada_Spec_Suffix := Default_Ada_Spec_Suffix;
1390          Data.Naming.Ada_Body_Suffix := Default_Ada_Body_Suffix;
1391          Data.Naming.Separate_Suffix := Default_Ada_Body_Suffix;
1392       end if;
1393    end Check_Naming_Scheme;
1394
1395    ------------------------------
1396    -- Check_Library_Attributes --
1397    ------------------------------
1398
1399    procedure Check_Library_Attributes
1400      (Project : Project_Id;
1401       In_Tree : Project_Tree_Ref;
1402       Data    : in out Project_Data)
1403    is
1404       Attributes : constant Prj.Variable_Id := Data.Decl.Attributes;
1405
1406       Lib_Dir : constant Prj.Variable_Value :=
1407                   Prj.Util.Value_Of
1408                     (Snames.Name_Library_Dir, Attributes, In_Tree);
1409
1410       Lib_Name : constant Prj.Variable_Value :=
1411                    Prj.Util.Value_Of
1412                      (Snames.Name_Library_Name, Attributes, In_Tree);
1413
1414       Lib_Version : constant Prj.Variable_Value :=
1415                       Prj.Util.Value_Of
1416                         (Snames.Name_Library_Version, Attributes, In_Tree);
1417
1418       Lib_ALI_Dir : constant Prj.Variable_Value :=
1419                       Prj.Util.Value_Of
1420                         (Snames.Name_Library_Ali_Dir, Attributes, In_Tree);
1421
1422       The_Lib_Kind : constant Prj.Variable_Value :=
1423                        Prj.Util.Value_Of
1424                          (Snames.Name_Library_Kind, Attributes, In_Tree);
1425
1426    begin
1427       --  Special case of extending project
1428
1429       if Data.Extends /= No_Project then
1430          declare
1431             Extended_Data : constant Project_Data :=
1432                            In_Tree.Projects.Table (Data.Extends);
1433
1434          begin
1435             --  If the project extended is a library project, we inherit
1436             --  the library name, if it is not redefined; we check that
1437             --  the library directory is specified; and we reset the
1438             --  library flag for the extended project.
1439
1440             if Extended_Data.Library then
1441                if Lib_Name.Default then
1442                   Data.Library_Name := Extended_Data.Library_Name;
1443                end if;
1444
1445                if Lib_Dir.Default then
1446                   if not Data.Virtual then
1447                      Error_Msg
1448                        (Project, In_Tree,
1449                         "a project extending a library project must " &
1450                         "specify an attribute Library_Dir",
1451                         Data.Location);
1452                   end if;
1453                end if;
1454
1455                In_Tree.Projects.Table (Data.Extends).Library :=
1456                  False;
1457             end if;
1458          end;
1459       end if;
1460
1461       pragma Assert (Lib_Dir.Kind = Single);
1462
1463       if Lib_Dir.Value = Empty_String then
1464          if Current_Verbosity = High then
1465             Write_Line ("No library directory");
1466          end if;
1467
1468       else
1469          --  Find path name, check that it is a directory
1470
1471          Locate_Directory
1472            (Lib_Dir.Value, Data.Display_Directory,
1473             Data.Library_Dir, Data.Display_Library_Dir);
1474
1475          if Data.Library_Dir = No_Name then
1476
1477             --  Get the absolute name of the library directory that
1478             --  does not exist, to report an error.
1479
1480             declare
1481                Dir_Name : constant String := Get_Name_String (Lib_Dir.Value);
1482
1483             begin
1484                if Is_Absolute_Path (Dir_Name) then
1485                   Err_Vars.Error_Msg_Name_1 := Lib_Dir.Value;
1486
1487                else
1488                   Get_Name_String (Data.Display_Directory);
1489
1490                   if Name_Buffer (Name_Len) /= Directory_Separator then
1491                      Name_Len := Name_Len + 1;
1492                      Name_Buffer (Name_Len) := Directory_Separator;
1493                   end if;
1494
1495                   Name_Buffer
1496                     (Name_Len + 1 .. Name_Len + Dir_Name'Length) :=
1497                     Dir_Name;
1498                   Name_Len := Name_Len + Dir_Name'Length;
1499                   Err_Vars.Error_Msg_Name_1 := Name_Find;
1500                end if;
1501
1502                --  Report the error
1503
1504                Error_Msg
1505                  (Project, In_Tree,
1506                   "library directory { does not exist",
1507                   Lib_Dir.Location);
1508             end;
1509
1510          --  The library directory cannot be the same as the Object directory
1511
1512          elsif Data.Library_Dir = Data.Object_Directory then
1513             Error_Msg
1514               (Project, In_Tree,
1515                "library directory cannot be the same " &
1516                "as object directory",
1517                Lib_Dir.Location);
1518             Data.Library_Dir := No_Name;
1519             Data.Display_Library_Dir := No_Name;
1520
1521          else
1522             declare
1523                OK       : Boolean := True;
1524                Dirs_Id  : String_List_Id;
1525                Dir_Elem : String_Element;
1526
1527             begin
1528                --  The library directory cannot be the same as a source
1529                --  directory of the current project.
1530
1531                Dirs_Id := Data.Source_Dirs;
1532                while Dirs_Id /= Nil_String loop
1533                   Dir_Elem := In_Tree.String_Elements.Table (Dirs_Id);
1534                   Dirs_Id  := Dir_Elem.Next;
1535
1536                   if Data.Library_Dir = Dir_Elem.Value then
1537                      Err_Vars.Error_Msg_Name_1 := Dir_Elem.Value;
1538                      Error_Msg
1539                        (Project, In_Tree,
1540                         "library directory cannot be the same " &
1541                         "as source directory {",
1542                         Lib_Dir.Location);
1543                      OK := False;
1544                      exit;
1545                   end if;
1546                end loop;
1547
1548                if OK then
1549
1550                   --  The library directory cannot be the same as a source
1551                   --  directory of another project either.
1552
1553                   Project_Loop :
1554                   for Pid in 1 .. Project_Table.Last (In_Tree.Projects) loop
1555                      if Pid /= Project then
1556                         Dirs_Id := In_Tree.Projects.Table (Pid).Source_Dirs;
1557
1558                         Dir_Loop : while Dirs_Id /= Nil_String loop
1559                            Dir_Elem := In_Tree.String_Elements.Table (Dirs_Id);
1560                            Dirs_Id  := Dir_Elem.Next;
1561
1562                            if Data.Library_Dir = Dir_Elem.Value then
1563                               Err_Vars.Error_Msg_Name_1 := Dir_Elem.Value;
1564                               Err_Vars.Error_Msg_Name_2 :=
1565                                 In_Tree.Projects.Table (Pid).Name;
1566
1567                               Error_Msg
1568                                 (Project, In_Tree,
1569                                  "library directory cannot be the same " &
1570                                  "as source directory { of project {",
1571                                  Lib_Dir.Location);
1572                               OK := False;
1573                               exit Project_Loop;
1574                            end if;
1575                         end loop Dir_Loop;
1576                      end if;
1577                   end loop Project_Loop;
1578                end if;
1579
1580                if not OK then
1581                   Data.Library_Dir := No_Name;
1582                   Data.Display_Library_Dir := No_Name;
1583
1584                elsif Current_Verbosity = High then
1585
1586                   --  Display the Library directory in high verbosity
1587
1588                   Write_Str ("Library directory =""");
1589                   Write_Str (Get_Name_String (Data.Display_Library_Dir));
1590                   Write_Line ("""");
1591                end if;
1592             end;
1593          end if;
1594       end if;
1595
1596       pragma Assert (Lib_Name.Kind = Single);
1597
1598       if Lib_Name.Value = Empty_String then
1599          if Current_Verbosity = High
1600            and then Data.Library_Name = No_Name
1601          then
1602             Write_Line ("No library name");
1603          end if;
1604
1605       else
1606          --  There is no restriction on the syntax of library names
1607
1608          Data.Library_Name := Lib_Name.Value;
1609       end if;
1610
1611       if Data.Library_Name /= No_Name
1612         and then Current_Verbosity = High
1613       then
1614          Write_Str ("Library name = """);
1615          Write_Str (Get_Name_String (Data.Library_Name));
1616          Write_Line ("""");
1617       end if;
1618
1619       Data.Library :=
1620         Data.Library_Dir /= No_Name
1621         and then
1622       Data.Library_Name /= No_Name;
1623
1624       if Data.Library then
1625          if MLib.Tgt.Support_For_Libraries = MLib.Tgt.None then
1626             Error_Msg
1627               (Project, In_Tree,
1628                "?libraries are not supported on this platform",
1629                Lib_Name.Location);
1630             Data.Library := False;
1631
1632          else
1633             if Lib_ALI_Dir.Value = Empty_String then
1634                if Current_Verbosity = High then
1635                   Write_Line ("No library 'A'L'I directory specified");
1636                end if;
1637                Data.Library_ALI_Dir := Data.Library_Dir;
1638                Data.Display_Library_ALI_Dir := Data.Display_Library_Dir;
1639
1640             else
1641                --  Find path name, check that it is a directory
1642
1643                Locate_Directory
1644                  (Lib_ALI_Dir.Value, Data.Display_Directory,
1645                   Data.Library_ALI_Dir, Data.Display_Library_ALI_Dir);
1646
1647                if Data.Library_ALI_Dir = No_Name then
1648
1649                   --  Get the absolute name of the library ALI directory that
1650                   --  does not exist, to report an error.
1651
1652                   declare
1653                      Dir_Name : constant String :=
1654                                   Get_Name_String (Lib_ALI_Dir.Value);
1655
1656                   begin
1657                      if Is_Absolute_Path (Dir_Name) then
1658                         Err_Vars.Error_Msg_Name_1 := Lib_Dir.Value;
1659
1660                      else
1661                         Get_Name_String (Data.Display_Directory);
1662
1663                         if Name_Buffer (Name_Len) /= Directory_Separator then
1664                            Name_Len := Name_Len + 1;
1665                            Name_Buffer (Name_Len) := Directory_Separator;
1666                         end if;
1667
1668                         Name_Buffer
1669                           (Name_Len + 1 .. Name_Len + Dir_Name'Length) :=
1670                           Dir_Name;
1671                         Name_Len := Name_Len + Dir_Name'Length;
1672                         Err_Vars.Error_Msg_Name_1 := Name_Find;
1673                      end if;
1674
1675                      --  Report the error
1676
1677                      Error_Msg
1678                        (Project, In_Tree,
1679                         "library 'A'L'I directory { does not exist",
1680                         Lib_ALI_Dir.Location);
1681                   end;
1682                end if;
1683
1684                if Data.Library_ALI_Dir /= Data.Library_Dir then
1685
1686                   --  The library ALI directory cannot be the same as the
1687                   --  Object directory.
1688
1689                   if Data.Library_ALI_Dir = Data.Object_Directory then
1690                      Error_Msg
1691                        (Project, In_Tree,
1692                         "library 'A'L'I directory cannot be the same " &
1693                         "as object directory",
1694                         Lib_ALI_Dir.Location);
1695                      Data.Library_ALI_Dir := No_Name;
1696                      Data.Display_Library_ALI_Dir := No_Name;
1697
1698                   else
1699                      declare
1700                         OK       : Boolean := True;
1701                         Dirs_Id  : String_List_Id;
1702                         Dir_Elem : String_Element;
1703
1704                      begin
1705                         --  The library ALI directory cannot be the same as
1706                         --  a source directory of the current project.
1707
1708                         Dirs_Id := Data.Source_Dirs;
1709                         while Dirs_Id /= Nil_String loop
1710                            Dir_Elem := In_Tree.String_Elements.Table (Dirs_Id);
1711                            Dirs_Id  := Dir_Elem.Next;
1712
1713                            if Data.Library_ALI_Dir = Dir_Elem.Value then
1714                               Err_Vars.Error_Msg_Name_1 := Dir_Elem.Value;
1715                               Error_Msg
1716                                 (Project, In_Tree,
1717                                  "library 'A'L'I directory cannot be " &
1718                                  "the same as source directory {",
1719                                  Lib_ALI_Dir.Location);
1720                               OK := False;
1721                               exit;
1722                            end if;
1723                         end loop;
1724
1725                         if OK then
1726
1727                            --  The library ALI directory cannot be the same as
1728                            --  a source directory of another project either.
1729
1730                            ALI_Project_Loop :
1731                            for
1732                              Pid in 1 .. Project_Table.Last (In_Tree.Projects)
1733                            loop
1734                               if Pid /= Project then
1735                                  Dirs_Id :=
1736                                    In_Tree.Projects.Table (Pid).Source_Dirs;
1737
1738                                  ALI_Dir_Loop :
1739                                  while Dirs_Id /= Nil_String loop
1740                                     Dir_Elem :=
1741                                       In_Tree.String_Elements.Table (Dirs_Id);
1742                                     Dirs_Id  := Dir_Elem.Next;
1743
1744                                     if
1745                                       Data.Library_ALI_Dir = Dir_Elem.Value
1746                                     then
1747                                        Err_Vars.Error_Msg_Name_1 :=
1748                                          Dir_Elem.Value;
1749                                        Err_Vars.Error_Msg_Name_2 :=
1750                                          In_Tree.Projects.Table (Pid).Name;
1751
1752                                        Error_Msg
1753                                          (Project, In_Tree,
1754                                           "library 'A'L'I directory cannot " &
1755                                           "be the same as source directory " &
1756                                           "{ of project {",
1757                                           Lib_ALI_Dir.Location);
1758                                        OK := False;
1759                                        exit ALI_Project_Loop;
1760                                     end if;
1761                                  end loop ALI_Dir_Loop;
1762                               end if;
1763                            end loop ALI_Project_Loop;
1764                         end if;
1765
1766                         if not OK then
1767                            Data.Library_ALI_Dir := No_Name;
1768                            Data.Display_Library_ALI_Dir := No_Name;
1769
1770                         elsif Current_Verbosity = High then
1771
1772                            --  Display the Library ALI directory in high
1773                            --  verbosity.
1774
1775                            Write_Str ("Library ALI directory =""");
1776                            Write_Str
1777                              (Get_Name_String (Data.Display_Library_ALI_Dir));
1778                            Write_Line ("""");
1779                         end if;
1780                      end;
1781                   end if;
1782                end if;
1783             end if;
1784
1785             pragma Assert (Lib_Version.Kind = Single);
1786
1787             if Lib_Version.Value = Empty_String then
1788                if Current_Verbosity = High then
1789                   Write_Line ("No library version specified");
1790                end if;
1791
1792             else
1793                Data.Lib_Internal_Name := Lib_Version.Value;
1794             end if;
1795
1796             pragma Assert (The_Lib_Kind.Kind = Single);
1797
1798             if The_Lib_Kind.Value = Empty_String then
1799                if Current_Verbosity = High then
1800                   Write_Line ("No library kind specified");
1801                end if;
1802
1803             else
1804                Get_Name_String (The_Lib_Kind.Value);
1805
1806                declare
1807                   Kind_Name : constant String :=
1808                                 To_Lower (Name_Buffer (1 .. Name_Len));
1809
1810                   OK : Boolean := True;
1811
1812                begin
1813                   if Kind_Name = "static" then
1814                      Data.Library_Kind := Static;
1815
1816                   elsif Kind_Name = "dynamic" then
1817                      Data.Library_Kind := Dynamic;
1818
1819                   elsif Kind_Name = "relocatable" then
1820                      Data.Library_Kind := Relocatable;
1821
1822                   else
1823                      Error_Msg
1824                        (Project, In_Tree,
1825                         "illegal value for Library_Kind",
1826                         The_Lib_Kind.Location);
1827                      OK := False;
1828                   end if;
1829
1830                   if Current_Verbosity = High and then OK then
1831                      Write_Str ("Library kind = ");
1832                      Write_Line (Kind_Name);
1833                   end if;
1834
1835                   if Data.Library_Kind /= Static and then
1836                     MLib.Tgt.Support_For_Libraries = MLib.Tgt.Static_Only
1837                   then
1838                      Error_Msg
1839                        (Project, In_Tree,
1840                         "only static libraries are supported " &
1841                         "on this platform",
1842                         The_Lib_Kind.Location);
1843                      Data.Library := False;
1844                   end if;
1845                end;
1846             end if;
1847
1848             if Data.Library and then Current_Verbosity = High then
1849                Write_Line ("This is a library project file");
1850             end if;
1851
1852          end if;
1853       end if;
1854    end Check_Library_Attributes;
1855
1856    --------------------------
1857    -- Check_Package_Naming --
1858    --------------------------
1859
1860    procedure Check_Package_Naming
1861      (Project : Project_Id;
1862       In_Tree : Project_Tree_Ref;
1863       Data    : in out Project_Data)
1864    is
1865       Naming_Id : constant Package_Id :=
1866                     Util.Value_Of (Name_Naming, Data.Decl.Packages, In_Tree);
1867
1868       Naming : Package_Element;
1869
1870    begin
1871       --  If there is a package Naming, we will put in Data.Naming
1872       --  what is in this package Naming.
1873
1874       if Naming_Id /= No_Package then
1875          Naming := In_Tree.Packages.Table (Naming_Id);
1876
1877          if Current_Verbosity = High then
1878             Write_Line ("Checking ""Naming"".");
1879          end if;
1880
1881          --  Check Spec_Suffix
1882
1883          declare
1884             Spec_Suffixs : Array_Element_Id :=
1885                              Util.Value_Of
1886                                (Name_Spec_Suffix,
1887                                 Naming.Decl.Arrays,
1888                                 In_Tree);
1889
1890             Suffix  : Array_Element_Id;
1891             Element : Array_Element;
1892             Suffix2 : Array_Element_Id;
1893
1894          begin
1895             --  If some suffixs have been specified, we make sure that
1896             --  for each language for which a default suffix has been
1897             --  specified, there is a suffix specified, either the one
1898             --  in the project file or if there were none, the default.
1899
1900             if Spec_Suffixs /= No_Array_Element then
1901                Suffix := Data.Naming.Spec_Suffix;
1902
1903                while Suffix /= No_Array_Element loop
1904                   Element :=
1905                     In_Tree.Array_Elements.Table (Suffix);
1906                   Suffix2 := Spec_Suffixs;
1907
1908                   while Suffix2 /= No_Array_Element loop
1909                      exit when In_Tree.Array_Elements.Table
1910                                 (Suffix2).Index = Element.Index;
1911                      Suffix2 := In_Tree.Array_Elements.Table
1912                                  (Suffix2).Next;
1913                   end loop;
1914
1915                   --  There is a registered default suffix, but no
1916                   --  suffix specified in the project file.
1917                   --  Add the default to the array.
1918
1919                   if Suffix2 = No_Array_Element then
1920                      Array_Element_Table.Increment_Last
1921                        (In_Tree.Array_Elements);
1922                      In_Tree.Array_Elements.Table
1923                        (Array_Element_Table.Last
1924                           (In_Tree.Array_Elements)) :=
1925                        (Index                => Element.Index,
1926                         Src_Index            => Element.Src_Index,
1927                         Index_Case_Sensitive => False,
1928                         Value                => Element.Value,
1929                         Next                 => Spec_Suffixs);
1930                      Spec_Suffixs := Array_Element_Table.Last
1931                                        (In_Tree.Array_Elements);
1932                   end if;
1933
1934                   Suffix := Element.Next;
1935                end loop;
1936
1937                --  Put the resulting array as the specification suffixs
1938
1939                Data.Naming.Spec_Suffix := Spec_Suffixs;
1940             end if;
1941          end;
1942
1943          declare
1944             Current : Array_Element_Id := Data.Naming.Spec_Suffix;
1945             Element : Array_Element;
1946
1947          begin
1948             while Current /= No_Array_Element loop
1949                Element := In_Tree.Array_Elements.Table (Current);
1950                Get_Name_String (Element.Value.Value);
1951
1952                if Name_Len = 0 then
1953                   Error_Msg
1954                     (Project, In_Tree,
1955                      "Spec_Suffix cannot be empty",
1956                      Element.Value.Location);
1957                end if;
1958
1959                In_Tree.Array_Elements.Table (Current) := Element;
1960                Current := Element.Next;
1961             end loop;
1962          end;
1963
1964          --  Check Body_Suffix
1965
1966          declare
1967             Impl_Suffixs : Array_Element_Id :=
1968               Util.Value_Of
1969                 (Name_Body_Suffix,
1970                  Naming.Decl.Arrays,
1971                  In_Tree);
1972
1973             Suffix       : Array_Element_Id;
1974             Element      : Array_Element;
1975             Suffix2      : Array_Element_Id;
1976
1977          begin
1978             --  If some suffixes have been specified, we make sure that
1979             --  for each language for which a default suffix has been
1980             --  specified, there is a suffix specified, either the one
1981             --  in the project file or if there were noe, the default.
1982
1983             if Impl_Suffixs /= No_Array_Element then
1984                Suffix := Data.Naming.Body_Suffix;
1985
1986                while Suffix /= No_Array_Element loop
1987                   Element :=
1988                     In_Tree.Array_Elements.Table (Suffix);
1989                   Suffix2 := Impl_Suffixs;
1990
1991                   while Suffix2 /= No_Array_Element loop
1992                      exit when In_Tree.Array_Elements.Table
1993                                 (Suffix2).Index = Element.Index;
1994                      Suffix2 := In_Tree.Array_Elements.Table
1995                                   (Suffix2).Next;
1996                   end loop;
1997
1998                   --  There is a registered default suffix, but no suffix was
1999                   --  specified in the project file. Add the default to the
2000                   --  array.
2001
2002                   if Suffix2 = No_Array_Element then
2003                      Array_Element_Table.Increment_Last
2004                        (In_Tree.Array_Elements);
2005                      In_Tree.Array_Elements.Table
2006                        (Array_Element_Table.Last
2007                           (In_Tree.Array_Elements)) :=
2008                        (Index                => Element.Index,
2009                         Src_Index            => Element.Src_Index,
2010                         Index_Case_Sensitive => False,
2011                         Value                => Element.Value,
2012                         Next                 => Impl_Suffixs);
2013                      Impl_Suffixs := Array_Element_Table.Last
2014                                        (In_Tree.Array_Elements);
2015                   end if;
2016
2017                   Suffix := Element.Next;
2018                end loop;
2019
2020                --  Put the resulting array as the implementation suffixs
2021
2022                Data.Naming.Body_Suffix := Impl_Suffixs;
2023             end if;
2024          end;
2025
2026          declare
2027             Current : Array_Element_Id := Data.Naming.Body_Suffix;
2028             Element : Array_Element;
2029
2030          begin
2031             while Current /= No_Array_Element loop
2032                Element := In_Tree.Array_Elements.Table (Current);
2033                Get_Name_String (Element.Value.Value);
2034
2035                if Name_Len = 0 then
2036                   Error_Msg
2037                     (Project, In_Tree,
2038                      "Body_Suffix cannot be empty",
2039                      Element.Value.Location);
2040                end if;
2041
2042                In_Tree.Array_Elements.Table (Current) := Element;
2043                Current := Element.Next;
2044             end loop;
2045          end;
2046
2047          --  Get the exceptions, if any
2048
2049          Data.Naming.Specification_Exceptions :=
2050            Util.Value_Of
2051              (Name_Specification_Exceptions,
2052               In_Arrays => Naming.Decl.Arrays,
2053               In_Tree   => In_Tree);
2054
2055          Data.Naming.Implementation_Exceptions :=
2056            Util.Value_Of
2057              (Name_Implementation_Exceptions,
2058               In_Arrays => Naming.Decl.Arrays,
2059               In_Tree   => In_Tree);
2060       end if;
2061    end Check_Package_Naming;
2062
2063    ---------------------------------
2064    -- Check_Programming_Languages --
2065    ---------------------------------
2066
2067    procedure Check_Programming_Languages
2068      (In_Tree : Project_Tree_Ref;
2069       Data    : in out Project_Data)
2070    is
2071       Languages : Variable_Value := Nil_Variable_Value;
2072
2073    begin
2074       Languages :=
2075         Prj.Util.Value_Of (Name_Languages, Data.Decl.Attributes, In_Tree);
2076       Data.Ada_Sources_Present   := Data.Source_Dirs /= Nil_String;
2077       Data.Other_Sources_Present := Data.Source_Dirs /= Nil_String;
2078
2079       if Data.Source_Dirs /= Nil_String then
2080
2081          --  Check if languages are specified in this project
2082
2083          if Languages.Default then
2084
2085             --  Attribute Languages is not specified. So, it defaults to
2086             --  a project of language Ada only.
2087
2088             Data.Languages (Ada_Language_Index) := True;
2089
2090             --  No sources of languages other than Ada
2091
2092             Data.Other_Sources_Present := False;
2093
2094          else
2095             declare
2096                Current   : String_List_Id := Languages.Values;
2097                Element   : String_Element;
2098                Lang_Name : Name_Id;
2099                Index     : Language_Index;
2100
2101             begin
2102                --  Assume that there is no language specified yet
2103
2104                Data.Other_Sources_Present := False;
2105                Data.Ada_Sources_Present   := False;
2106
2107                --  Look through all the languages specified in attribute
2108                --  Languages, if any
2109
2110                while Current /= Nil_String loop
2111                   Element :=
2112                     In_Tree.String_Elements.Table (Current);
2113                   Get_Name_String (Element.Value);
2114                   To_Lower (Name_Buffer (1 .. Name_Len));
2115                   Lang_Name := Name_Find;
2116                   Index := Language_Indexes.Get (Lang_Name);
2117
2118                   if Index = No_Language_Index then
2119                      Add_Language_Name (Lang_Name);
2120                      Index := Last_Language_Index;
2121                   end if;
2122
2123                   Set (Index, True, Data, In_Tree);
2124                   Set (Language_Processing => Default_Language_Processing_Data,
2125                        For_Language        => Index,
2126                        In_Project          => Data,
2127                        In_Tree             => In_Tree);
2128
2129                   if Index = Ada_Language_Index then
2130                      Data.Ada_Sources_Present := True;
2131
2132                   else
2133                      Data.Other_Sources_Present := True;
2134                   end if;
2135
2136                   Current := Element.Next;
2137                end loop;
2138             end;
2139          end if;
2140       end if;
2141    end Check_Programming_Languages;
2142
2143    -------------------
2144    -- Check_Project --
2145    -------------------
2146
2147    function Check_Project
2148      (P            : Project_Id;
2149       Root_Project : Project_Id;
2150       In_Tree      : Project_Tree_Ref;
2151       Extending    : Boolean) return Boolean
2152    is
2153    begin
2154       if P = Root_Project then
2155          return True;
2156
2157       elsif Extending then
2158          declare
2159             Data : Project_Data := In_Tree.Projects.Table (Root_Project);
2160
2161          begin
2162             while Data.Extends /= No_Project loop
2163                if P = Data.Extends then
2164                   return True;
2165                end if;
2166
2167                Data := In_Tree.Projects.Table (Data.Extends);
2168             end loop;
2169          end;
2170       end if;
2171
2172       return False;
2173    end Check_Project;
2174
2175    -------------------------------
2176    -- Check_Stand_Alone_Library --
2177    -------------------------------
2178
2179    procedure Check_Stand_Alone_Library
2180      (Project   : Project_Id;
2181       In_Tree   : Project_Tree_Ref;
2182       Data      : in out Project_Data;
2183       Extending : Boolean)
2184    is
2185       Lib_Interfaces      : constant Prj.Variable_Value :=
2186                               Prj.Util.Value_Of
2187                                 (Snames.Name_Library_Interface,
2188                                  Data.Decl.Attributes,
2189                                  In_Tree);
2190
2191       Lib_Auto_Init       : constant Prj.Variable_Value :=
2192                               Prj.Util.Value_Of
2193                                 (Snames.Name_Library_Auto_Init,
2194                                  Data.Decl.Attributes,
2195                                  In_Tree);
2196
2197       Lib_Src_Dir         : constant Prj.Variable_Value :=
2198                               Prj.Util.Value_Of
2199                                 (Snames.Name_Library_Src_Dir,
2200                                  Data.Decl.Attributes,
2201                                  In_Tree);
2202
2203       Lib_Symbol_File     : constant Prj.Variable_Value :=
2204                               Prj.Util.Value_Of
2205                                 (Snames.Name_Library_Symbol_File,
2206                                  Data.Decl.Attributes,
2207                                  In_Tree);
2208
2209       Lib_Symbol_Policy   : constant Prj.Variable_Value :=
2210                               Prj.Util.Value_Of
2211                                 (Snames.Name_Library_Symbol_Policy,
2212                                  Data.Decl.Attributes,
2213                                  In_Tree);
2214
2215       Lib_Ref_Symbol_File : constant Prj.Variable_Value :=
2216                               Prj.Util.Value_Of
2217                                 (Snames.Name_Library_Reference_Symbol_File,
2218                                  Data.Decl.Attributes,
2219                                  In_Tree);
2220
2221       Auto_Init_Supported : constant Boolean :=
2222                               MLib.Tgt.
2223                                 Standalone_Library_Auto_Init_Is_Supported;
2224
2225       OK : Boolean := True;
2226
2227    begin
2228       pragma Assert (Lib_Interfaces.Kind = List);
2229
2230       --  It is a stand-alone library project file if attribute
2231       --  Library_Interface is defined.
2232
2233       if not Lib_Interfaces.Default then
2234          SAL_Library : declare
2235             Interfaces     : String_List_Id := Lib_Interfaces.Values;
2236             Interface_ALIs : String_List_Id := Nil_String;
2237             Unit           : Name_Id;
2238             The_Unit_Id    : Unit_Id;
2239             The_Unit_Data  : Unit_Data;
2240
2241             procedure Add_ALI_For (Source : Name_Id);
2242             --  Add an ALI file name to the list of Interface ALIs
2243
2244             -----------------
2245             -- Add_ALI_For --
2246             -----------------
2247
2248             procedure Add_ALI_For (Source : Name_Id) is
2249             begin
2250                Get_Name_String (Source);
2251
2252                declare
2253                   ALI         : constant String :=
2254                     ALI_File_Name (Name_Buffer (1 .. Name_Len));
2255                   ALI_Name_Id : Name_Id;
2256                begin
2257                   Name_Len := ALI'Length;
2258                   Name_Buffer (1 .. Name_Len) := ALI;
2259                   ALI_Name_Id := Name_Find;
2260
2261                   String_Element_Table.Increment_Last
2262                     (In_Tree.String_Elements);
2263                   In_Tree.String_Elements.Table
2264                     (String_Element_Table.Last
2265                       (In_Tree.String_Elements)) :=
2266                     (Value         => ALI_Name_Id,
2267                      Index         => 0,
2268                      Display_Value => ALI_Name_Id,
2269                      Location      =>
2270                        In_Tree.String_Elements.Table
2271                          (Interfaces).Location,
2272                      Flag          => False,
2273                      Next          => Interface_ALIs);
2274                   Interface_ALIs := String_Element_Table.Last
2275                                       (In_Tree.String_Elements);
2276                end;
2277             end Add_ALI_For;
2278
2279          --  Start of processing for SAL_Library
2280
2281          begin
2282             Data.Standalone_Library := True;
2283
2284             --  Library_Interface cannot be an empty list
2285
2286             if Interfaces = Nil_String then
2287                Error_Msg
2288                  (Project, In_Tree,
2289                   "Library_Interface cannot be an empty list",
2290                   Lib_Interfaces.Location);
2291             end if;
2292
2293             --  Process each unit name specified in the attribute
2294             --  Library_Interface.
2295
2296             while Interfaces /= Nil_String loop
2297                Get_Name_String
2298                  (In_Tree.String_Elements.Table
2299                                                      (Interfaces).Value);
2300                To_Lower (Name_Buffer (1 .. Name_Len));
2301
2302                if Name_Len = 0 then
2303                   Error_Msg
2304                     (Project, In_Tree,
2305                      "an interface cannot be an empty string",
2306                      In_Tree.String_Elements.Table
2307                                                    (Interfaces).Location);
2308
2309                else
2310                   Unit := Name_Find;
2311                   Error_Msg_Name_1 := Unit;
2312                   The_Unit_Id :=
2313                     Units_Htable.Get (In_Tree.Units_HT, Unit);
2314
2315                   if The_Unit_Id = No_Unit then
2316                      Error_Msg
2317                        (Project, In_Tree,
2318                         "unknown unit {",
2319                         In_Tree.String_Elements.Table
2320                           (Interfaces).Location);
2321
2322                   else
2323                      --  Check that the unit is part of the project
2324
2325                      The_Unit_Data :=
2326                        In_Tree.Units.Table (The_Unit_Id);
2327
2328                      if The_Unit_Data.File_Names (Body_Part).Name /= No_Name
2329                        and then The_Unit_Data.File_Names (Body_Part).Path /=
2330                                                                         Slash
2331                      then
2332                         if Check_Project
2333                           (The_Unit_Data.File_Names (Body_Part).Project,
2334                            Project, In_Tree, Extending)
2335                         then
2336                            --  There is a body for this unit.
2337                            --  If there is no spec, we need to check
2338                            --  that it is not a subunit.
2339
2340                            if The_Unit_Data.File_Names
2341                              (Specification).Name = No_Name
2342                            then
2343                               declare
2344                                  Src_Ind : Source_File_Index;
2345
2346                               begin
2347                                  Src_Ind := Sinput.P.Load_Project_File
2348                                    (Get_Name_String
2349                                       (The_Unit_Data.File_Names
2350                                          (Body_Part).Path));
2351
2352                                  if Sinput.P.Source_File_Is_Subunit
2353                                    (Src_Ind)
2354                                  then
2355                                     Error_Msg
2356                                       (Project, In_Tree,
2357                                        "{ is a subunit; " &
2358                                        "it cannot be an interface",
2359                                        In_Tree.
2360                                          String_Elements.Table
2361                                            (Interfaces).Location);
2362                                  end if;
2363                               end;
2364                            end if;
2365
2366                            --  The unit is not a subunit, so we add
2367                            --  to the Interface ALIs the ALI file
2368                            --  corresponding to the body.
2369
2370                            Add_ALI_For
2371                              (The_Unit_Data.File_Names (Body_Part).Name);
2372
2373                         else
2374                            Error_Msg
2375                              (Project, In_Tree,
2376                               "{ is not an unit of this project",
2377                               In_Tree.String_Elements.Table
2378                                 (Interfaces).Location);
2379                         end if;
2380
2381                      elsif The_Unit_Data.File_Names
2382                        (Specification).Name /= No_Name
2383                        and then The_Unit_Data.File_Names
2384                          (Specification).Path /= Slash
2385                        and then Check_Project
2386                          (The_Unit_Data.File_Names
2387                               (Specification).Project,
2388                           Project, In_Tree, Extending)
2389
2390                      then
2391                         --  The unit is part of the project, it has
2392                         --  a spec, but no body. We add to the Interface
2393                         --  ALIs the ALI file corresponding to the spec.
2394
2395                         Add_ALI_For
2396                           (The_Unit_Data.File_Names (Specification).Name);
2397
2398                      else
2399                         Error_Msg
2400                           (Project, In_Tree,
2401                            "{ is not an unit of this project",
2402                            In_Tree.String_Elements.Table
2403                                                     (Interfaces).Location);
2404                      end if;
2405                   end if;
2406
2407                end if;
2408
2409                Interfaces :=
2410                  In_Tree.String_Elements.Table (Interfaces).Next;
2411             end loop;
2412
2413             --  Put the list of Interface ALIs in the project data
2414
2415             Data.Lib_Interface_ALIs := Interface_ALIs;
2416
2417             --  Check value of attribute Library_Auto_Init and set
2418             --  Lib_Auto_Init accordingly.
2419
2420             if Lib_Auto_Init.Default then
2421
2422                --  If no attribute Library_Auto_Init is declared, then
2423                --  set auto init only if it is supported.
2424
2425                Data.Lib_Auto_Init := Auto_Init_Supported;
2426
2427             else
2428                Get_Name_String (Lib_Auto_Init.Value);
2429                To_Lower (Name_Buffer (1 .. Name_Len));
2430
2431                if Name_Buffer (1 .. Name_Len) = "false" then
2432                   Data.Lib_Auto_Init := False;
2433
2434                elsif Name_Buffer (1 .. Name_Len) = "true" then
2435                   if Auto_Init_Supported then
2436                      Data.Lib_Auto_Init := True;
2437
2438                   else
2439                      --  Library_Auto_Init cannot be "true" if auto init
2440                      --  is not supported
2441
2442                      Error_Msg
2443                        (Project, In_Tree,
2444                         "library auto init not supported " &
2445                         "on this platform",
2446                         Lib_Auto_Init.Location);
2447                   end if;
2448
2449                else
2450                   Error_Msg
2451                     (Project, In_Tree,
2452                      "invalid value for attribute Library_Auto_Init",
2453                      Lib_Auto_Init.Location);
2454                end if;
2455             end if;
2456          end SAL_Library;
2457
2458          --  If attribute Library_Src_Dir is defined and not the
2459          --  empty string, check if the directory exist and is not
2460          --  the object directory or one of the source directories.
2461          --  This is the directory where copies of the interface
2462          --  sources will be copied. Note that this directory may be
2463          --  the library directory.
2464
2465          if Lib_Src_Dir.Value /= Empty_String then
2466             declare
2467                Dir_Id : constant Name_Id := Lib_Src_Dir.Value;
2468
2469             begin
2470                Locate_Directory
2471                  (Dir_Id, Data.Display_Directory,
2472                   Data.Library_Src_Dir,
2473                   Data.Display_Library_Src_Dir);
2474
2475                --  If directory does not exist, report an error
2476
2477                if Data.Library_Src_Dir = No_Name then
2478
2479                   --  Get the absolute name of the library directory
2480                   --  that does not exist, to report an error.
2481
2482                   declare
2483                      Dir_Name : constant String :=
2484                        Get_Name_String (Dir_Id);
2485
2486                   begin
2487                      if Is_Absolute_Path (Dir_Name) then
2488                         Err_Vars.Error_Msg_Name_1 := Dir_Id;
2489
2490                      else
2491                         Get_Name_String (Data.Directory);
2492
2493                         if Name_Buffer (Name_Len) /=
2494                           Directory_Separator
2495                         then
2496                            Name_Len := Name_Len + 1;
2497                            Name_Buffer (Name_Len) :=
2498                              Directory_Separator;
2499                         end if;
2500
2501                         Name_Buffer
2502                           (Name_Len + 1 ..
2503                              Name_Len + Dir_Name'Length) :=
2504                             Dir_Name;
2505                         Name_Len := Name_Len + Dir_Name'Length;
2506                         Err_Vars.Error_Msg_Name_1 := Name_Find;
2507                      end if;
2508
2509                      --  Report the error
2510
2511                      Error_Msg
2512                        (Project, In_Tree,
2513                         "Directory { does not exist",
2514                         Lib_Src_Dir.Location);
2515                   end;
2516
2517                   --  Report an error if it is the same as the object
2518                   --  directory.
2519
2520                elsif Data.Library_Src_Dir = Data.Object_Directory then
2521                   Error_Msg
2522                     (Project, In_Tree,
2523                      "directory to copy interfaces cannot be " &
2524                      "the object directory",
2525                      Lib_Src_Dir.Location);
2526                   Data.Library_Src_Dir := No_Name;
2527
2528                else
2529                   declare
2530                      Src_Dirs : String_List_Id;
2531                      Src_Dir  : String_Element;
2532
2533                   begin
2534                      --  Interface copy directory cannot be one of the source
2535                      --  directory of the current project.
2536
2537                      Src_Dirs := Data.Source_Dirs;
2538                      while Src_Dirs /= Nil_String loop
2539                         Src_Dir := In_Tree.String_Elements.Table
2540                                                           (Src_Dirs);
2541
2542                         --  Report error if it is one of the source directories
2543
2544                         if Data.Library_Src_Dir = Src_Dir.Value then
2545                            Error_Msg
2546                              (Project, In_Tree,
2547                               "directory to copy interfaces cannot " &
2548                               "be one of the source directories",
2549                               Lib_Src_Dir.Location);
2550                            Data.Library_Src_Dir := No_Name;
2551                            exit;
2552                         end if;
2553
2554                         Src_Dirs := Src_Dir.Next;
2555                      end loop;
2556
2557                      if Data.Library_Src_Dir /= No_Name then
2558
2559                         --  It cannot be a source directory of any other
2560                         --  project either.
2561
2562                         Project_Loop : for Pid in 1 ..
2563                           Project_Table.Last (In_Tree.Projects)
2564                         loop
2565                            Src_Dirs :=
2566                              In_Tree.Projects.Table (Pid).Source_Dirs;
2567                            Dir_Loop : while Src_Dirs /= Nil_String loop
2568                               Src_Dir :=
2569                                 In_Tree.String_Elements.Table (Src_Dirs);
2570
2571                               --  Report error if it is one of the source
2572                               --  directories
2573
2574                               if Data.Library_Src_Dir = Src_Dir.Value then
2575                                  Error_Msg_Name_1 := Src_Dir.Value;
2576                                  Error_Msg_Name_2 :=
2577                                    In_Tree.Projects.Table (Pid).Name;
2578                                  Error_Msg
2579                                    (Project, In_Tree,
2580                                     "directory to copy interfaces cannot " &
2581                                     "be the same as source directory { of " &
2582                                     "project {",
2583                                     Lib_Src_Dir.Location);
2584                                  Data.Library_Src_Dir := No_Name;
2585                                  exit Project_Loop;
2586                               end if;
2587
2588                               Src_Dirs := Src_Dir.Next;
2589                            end loop Dir_Loop;
2590                         end loop Project_Loop;
2591                      end if;
2592                   end;
2593
2594                   --  In high verbosity, if there is a valid Library_Src_Dir,
2595                   --  display its path name.
2596
2597                   if Data.Library_Src_Dir /= No_Name
2598                     and then Current_Verbosity = High
2599                   then
2600                      Write_Str ("Directory to copy interfaces =""");
2601                      Write_Str (Get_Name_String (Data.Library_Src_Dir));
2602                      Write_Line ("""");
2603                   end if;
2604                end if;
2605             end;
2606          end if;
2607
2608          --  Check the symbol related attributes
2609
2610          --  First, the symbol policy
2611
2612          if not Lib_Symbol_Policy.Default then
2613             declare
2614                Value : constant String :=
2615                  To_Lower
2616                    (Get_Name_String (Lib_Symbol_Policy.Value));
2617
2618             begin
2619                --  Symbol policy must hove one of a limited number of values
2620
2621                if Value = "autonomous" or else Value = "default" then
2622                   Data.Symbol_Data.Symbol_Policy := Autonomous;
2623
2624                elsif Value = "compliant" then
2625                   Data.Symbol_Data.Symbol_Policy := Compliant;
2626
2627                elsif Value = "controlled" then
2628                   Data.Symbol_Data.Symbol_Policy := Controlled;
2629
2630                elsif Value = "restricted" then
2631                   Data.Symbol_Data.Symbol_Policy := Restricted;
2632
2633                else
2634                   Error_Msg
2635                     (Project, In_Tree,
2636                      "illegal value for Library_Symbol_Policy",
2637                      Lib_Symbol_Policy.Location);
2638                end if;
2639             end;
2640          end if;
2641
2642          --  If attribute Library_Symbol_File is not specified, symbol policy
2643          --  cannot be Restricted.
2644
2645          if Lib_Symbol_File.Default then
2646             if Data.Symbol_Data.Symbol_Policy = Restricted then
2647                Error_Msg
2648                  (Project, In_Tree,
2649                   "Library_Symbol_File needs to be defined when " &
2650                   "symbol policy is Restricted",
2651                   Lib_Symbol_Policy.Location);
2652             end if;
2653
2654          else
2655             --  Library_Symbol_File is defined. Check that the file exists
2656
2657             Data.Symbol_Data.Symbol_File := Lib_Symbol_File.Value;
2658
2659             Get_Name_String (Lib_Symbol_File.Value);
2660
2661             if Name_Len = 0 then
2662                Error_Msg
2663                  (Project, In_Tree,
2664                   "symbol file name cannot be an empty string",
2665                   Lib_Symbol_File.Location);
2666
2667             else
2668                OK := not Is_Absolute_Path (Name_Buffer (1 .. Name_Len));
2669
2670                if OK then
2671                   for J in 1 .. Name_Len loop
2672                      if Name_Buffer (J) = '/'
2673                        or else Name_Buffer (J) = Directory_Separator
2674                      then
2675                         OK := False;
2676                         exit;
2677                      end if;
2678                   end loop;
2679                end if;
2680
2681                if not OK then
2682                   Error_Msg_Name_1 := Lib_Symbol_File.Value;
2683                   Error_Msg
2684                     (Project, In_Tree,
2685                      "symbol file name { is illegal. " &
2686                      "Name canot include directory info.",
2687                      Lib_Symbol_File.Location);
2688                end if;
2689             end if;
2690          end if;
2691
2692          --  If attribute Library_Reference_Symbol_File is not defined,
2693          --  symbol policy cannot be Compilant or Controlled.
2694
2695          if Lib_Ref_Symbol_File.Default then
2696             if Data.Symbol_Data.Symbol_Policy = Compliant
2697               or else Data.Symbol_Data.Symbol_Policy = Controlled
2698             then
2699                Error_Msg
2700                  (Project, In_Tree,
2701                   "a reference symbol file need to be defined",
2702                   Lib_Symbol_Policy.Location);
2703             end if;
2704
2705          else
2706             --  Library_Reference_Symbol_File is defined, check file exists
2707
2708             Data.Symbol_Data.Reference := Lib_Ref_Symbol_File.Value;
2709
2710             Get_Name_String (Lib_Ref_Symbol_File.Value);
2711
2712             if Name_Len = 0 then
2713                Error_Msg
2714                  (Project, In_Tree,
2715                   "reference symbol file name cannot be an empty string",
2716                   Lib_Symbol_File.Location);
2717
2718             else
2719                OK := not Is_Absolute_Path (Name_Buffer (1 .. Name_Len));
2720
2721                if OK then
2722                   for J in 1 .. Name_Len loop
2723                      if Name_Buffer (J) = '/'
2724                        or else Name_Buffer (J) = Directory_Separator
2725                      then
2726                         OK := False;
2727                         exit;
2728                      end if;
2729                   end loop;
2730                end if;
2731
2732                if not OK then
2733                   Error_Msg_Name_1 := Lib_Ref_Symbol_File.Value;
2734                   Error_Msg
2735                     (Project, In_Tree,
2736                      "reference symbol file { name is illegal. " &
2737                      "Name canot include directory info.",
2738                      Lib_Ref_Symbol_File.Location);
2739                end if;
2740
2741                if not Is_Regular_File
2742                  (Get_Name_String (Data.Object_Directory) &
2743                   Directory_Separator &
2744                   Get_Name_String (Lib_Ref_Symbol_File.Value))
2745                then
2746                   Error_Msg_Name_1 := Lib_Ref_Symbol_File.Value;
2747
2748                   --  For controlled symbol policy, it is an error if the
2749                   --  reference symbol file does not exist. For other symbol
2750                   --  policies, this is just a warning
2751
2752                   Error_Msg_Warn :=
2753                     Data.Symbol_Data.Symbol_Policy /= Controlled;
2754
2755                   Error_Msg
2756                     (Project, In_Tree,
2757                      "<library reference symbol file { does not exist",
2758                      Lib_Ref_Symbol_File.Location);
2759
2760                   --  In addition in the non-controlled case, if symbol policy
2761                   --  is Compliant, it is changed to Autonomous, because there
2762                   --  is no reference to check against, and we don't want to
2763                   --  fail in this case.
2764
2765                   if Data.Symbol_Data.Symbol_Policy /= Controlled then
2766                      if Data.Symbol_Data.Symbol_Policy = Compliant then
2767                         Data.Symbol_Data.Symbol_Policy := Autonomous;
2768                      end if;
2769                   end if;
2770                end if;
2771             end if;
2772          end if;
2773       end if;
2774    end Check_Stand_Alone_Library;
2775
2776    ----------------------------
2777    -- Compute_Directory_Last --
2778    ----------------------------
2779
2780    function Compute_Directory_Last (Dir : String) return Natural is
2781    begin
2782       if Dir'Length > 1
2783         and then (Dir (Dir'Last - 1) = Directory_Separator
2784                   or else Dir (Dir'Last - 1) = '/')
2785       then
2786          return Dir'Last - 1;
2787       else
2788          return Dir'Last;
2789       end if;
2790    end Compute_Directory_Last;
2791
2792    --------------------
2793    -- Body_Suffix_Of --
2794    --------------------
2795
2796    function Body_Suffix_Of
2797      (Language   : Language_Index;
2798       In_Project : Project_Data;
2799       In_Tree    : Project_Tree_Ref) return String
2800    is
2801       Suffix_Id : constant Name_Id :=
2802                     Suffix_Of (Language, In_Project, In_Tree);
2803    begin
2804       if Suffix_Id /= No_Name then
2805          return Get_Name_String (Suffix_Id);
2806       else
2807          return "." & Get_Name_String (Language_Names.Table (Language));
2808       end if;
2809    end Body_Suffix_Of;
2810
2811    ---------------
2812    -- Error_Msg --
2813    ---------------
2814
2815    procedure Error_Msg
2816      (Project       : Project_Id;
2817       In_Tree       : Project_Tree_Ref;
2818       Msg           : String;
2819       Flag_Location : Source_Ptr)
2820    is
2821       Real_Location : Source_Ptr := Flag_Location;
2822       Error_Buffer : String (1 .. 5_000);
2823       Error_Last   : Natural := 0;
2824       Msg_Name     : Natural := 0;
2825       First        : Positive := Msg'First;
2826
2827       procedure Add (C : Character);
2828       --  Add a character to the buffer
2829
2830       procedure Add (S : String);
2831       --  Add a string to the buffer
2832
2833       procedure Add (Id : Name_Id);
2834       --  Add a name to the buffer
2835
2836       ---------
2837       -- Add --
2838       ---------
2839
2840       procedure Add (C : Character) is
2841       begin
2842          Error_Last := Error_Last + 1;
2843          Error_Buffer (Error_Last) := C;
2844       end Add;
2845
2846       procedure Add (S : String) is
2847       begin
2848          Error_Buffer (Error_Last + 1 .. Error_Last + S'Length) := S;
2849          Error_Last := Error_Last + S'Length;
2850       end Add;
2851
2852       procedure Add (Id : Name_Id) is
2853       begin
2854          Get_Name_String (Id);
2855          Add (Name_Buffer (1 .. Name_Len));
2856       end Add;
2857
2858    --  Start of processing for Error_Msg
2859
2860    begin
2861       --  If location of error is unknown, use the location of the project
2862
2863       if Real_Location = No_Location then
2864          Real_Location := In_Tree.Projects.Table (Project).Location;
2865       end if;
2866
2867       if Error_Report = null then
2868          Prj.Err.Error_Msg (Msg, Real_Location);
2869          return;
2870       end if;
2871
2872       --  Ignore continuation character
2873
2874       if Msg (First) = '\' then
2875          First := First + 1;
2876
2877          --  Warniung character is always the first one in this package
2878          --  this is an undoocumented kludge!!!
2879
2880       elsif Msg (First) = '?' then
2881          First := First + 1;
2882          Add ("Warning: ");
2883
2884       elsif Msg (First) = '<' then
2885          First := First + 1;
2886
2887          if Err_Vars.Error_Msg_Warn then
2888             Add ("Warning: ");
2889          end if;
2890       end if;
2891
2892       for Index in First .. Msg'Last loop
2893          if Msg (Index) = '{' or else Msg (Index) = '%' then
2894
2895             --  Include a name between double quotes
2896
2897             Msg_Name := Msg_Name + 1;
2898             Add ('"');
2899
2900             case Msg_Name is
2901                when 1 => Add (Err_Vars.Error_Msg_Name_1);
2902                when 2 => Add (Err_Vars.Error_Msg_Name_2);
2903                when 3 => Add (Err_Vars.Error_Msg_Name_3);
2904
2905                when others => null;
2906             end case;
2907
2908             Add ('"');
2909
2910          else
2911             Add (Msg (Index));
2912          end if;
2913
2914       end loop;
2915
2916       Error_Report (Error_Buffer (1 .. Error_Last), Project, In_Tree);
2917    end Error_Msg;
2918
2919    ------------------
2920    -- Find_Sources --
2921    ------------------
2922
2923    procedure Find_Sources
2924      (Project      : Project_Id;
2925       In_Tree      : Project_Tree_Ref;
2926       Data         : in out Project_Data;
2927       For_Language : Language_Index;
2928       Follow_Links : Boolean := False)
2929    is
2930       Source_Dir      : String_List_Id := Data.Source_Dirs;
2931       Element         : String_Element;
2932       Dir             : Dir_Type;
2933       Current_Source  : String_List_Id := Nil_String;
2934       Source_Recorded : Boolean := False;
2935
2936    begin
2937       if Current_Verbosity = High then
2938          Write_Line ("Looking for sources:");
2939       end if;
2940
2941       --  For each subdirectory
2942
2943       while Source_Dir /= Nil_String loop
2944          begin
2945             Source_Recorded := False;
2946             Element := In_Tree.String_Elements.Table (Source_Dir);
2947             if Element.Value /= No_Name then
2948                Get_Name_String (Element.Display_Value);
2949
2950                declare
2951                   Source_Directory : constant String :=
2952                     Name_Buffer (1 .. Name_Len) & Directory_Separator;
2953                   Dir_Last  : constant Natural :=
2954                      Compute_Directory_Last (Source_Directory);
2955
2956                begin
2957                   if Current_Verbosity = High then
2958                      Write_Str ("Source_Dir = ");
2959                      Write_Line (Source_Directory);
2960                   end if;
2961
2962                   --  We look to every entry in the source directory
2963
2964                   Open (Dir, Source_Directory
2965                                (Source_Directory'First .. Dir_Last));
2966
2967                   loop
2968                      Read (Dir, Name_Buffer, Name_Len);
2969
2970                      if Current_Verbosity = High then
2971                         Write_Str  ("   Checking ");
2972                         Write_Line (Name_Buffer (1 .. Name_Len));
2973                      end if;
2974
2975                      exit when Name_Len = 0;
2976
2977                      declare
2978                         File_Name : constant Name_Id := Name_Find;
2979                         Path      : constant String :=
2980                           Normalize_Pathname
2981                             (Name      => Name_Buffer (1 .. Name_Len),
2982                              Directory => Source_Directory
2983                                (Source_Directory'First .. Dir_Last),
2984                              Resolve_Links => Follow_Links,
2985                              Case_Sensitive => True);
2986                         Path_Name : Name_Id;
2987
2988                      begin
2989                         Name_Len := Path'Length;
2990                         Name_Buffer (1 .. Name_Len) := Path;
2991                         Path_Name := Name_Find;
2992
2993                         if For_Language = Ada_Language_Index then
2994
2995                            --  We attempt to register it as a source. However,
2996                            --  there is no error if the file does not contain
2997                            --  a valid source. But there is an error if we have
2998                            --  a duplicate unit name.
2999
3000                            Record_Ada_Source
3001                              (File_Name       => File_Name,
3002                               Path_Name       => Path_Name,
3003                               Project         => Project,
3004                               In_Tree         => In_Tree,
3005                               Data            => Data,
3006                               Location        => No_Location,
3007                               Current_Source  => Current_Source,
3008                               Source_Recorded => Source_Recorded,
3009                               Follow_Links    => Follow_Links);
3010
3011                         else
3012                            Check_For_Source
3013                              (File_Name        => File_Name,
3014                               Path_Name        => Path_Name,
3015                               Project          => Project,
3016                               In_Tree          => In_Tree,
3017                               Data             => Data,
3018                               Location         => No_Location,
3019                               Language         => For_Language,
3020                               Suffix           =>
3021                                 Body_Suffix_Of (For_Language, Data, In_Tree),
3022                               Naming_Exception => False);
3023                         end if;
3024                      end;
3025                   end loop;
3026
3027                   Close (Dir);
3028                end;
3029             end if;
3030
3031          exception
3032             when Directory_Error =>
3033                null;
3034          end;
3035
3036          if Source_Recorded then
3037             In_Tree.String_Elements.Table (Source_Dir).Flag :=
3038               True;
3039          end if;
3040
3041          Source_Dir := Element.Next;
3042       end loop;
3043
3044       if Current_Verbosity = High then
3045          Write_Line ("end Looking for sources.");
3046       end if;
3047
3048       if For_Language = Ada_Language_Index then
3049
3050          --  If we have looked for sources and found none, then
3051          --  it is an error, except if it is an extending project.
3052          --  If a non extending project is not supposed to contain
3053          --  any source, then we never call Find_Sources.
3054
3055          if Current_Source /= Nil_String then
3056             Data.Ada_Sources_Present := True;
3057
3058          elsif Data.Extends = No_Project then
3059             Report_No_Ada_Sources (Project, In_Tree, Data.Location);
3060          end if;
3061       end if;
3062    end Find_Sources;
3063
3064    --------------------------------
3065    -- Free_Ada_Naming_Exceptions --
3066    --------------------------------
3067
3068    procedure Free_Ada_Naming_Exceptions is
3069    begin
3070       Ada_Naming_Exception_Table.Set_Last (0);
3071       Ada_Naming_Exceptions.Reset;
3072       Reverse_Ada_Naming_Exceptions.Reset;
3073    end Free_Ada_Naming_Exceptions;
3074
3075    ---------------------
3076    -- Get_Directories --
3077    ---------------------
3078
3079    procedure Get_Directories
3080      (Project : Project_Id;
3081       In_Tree : Project_Tree_Ref;
3082       Data    : in out Project_Data)
3083    is
3084       Object_Dir : constant Variable_Value :=
3085                      Util.Value_Of
3086                        (Name_Object_Dir, Data.Decl.Attributes, In_Tree);
3087
3088       Exec_Dir   : constant Variable_Value :=
3089                      Util.Value_Of
3090                        (Name_Exec_Dir, Data.Decl.Attributes, In_Tree);
3091
3092       Source_Dirs : constant Variable_Value :=
3093                       Util.Value_Of
3094                         (Name_Source_Dirs, Data.Decl.Attributes, In_Tree);
3095
3096       Last_Source_Dir : String_List_Id  := Nil_String;
3097
3098       procedure Find_Source_Dirs (From : Name_Id; Location : Source_Ptr);
3099       --  Find one or several source directories, and add them
3100       --  to the list of source directories of the project.
3101
3102       ----------------------
3103       -- Find_Source_Dirs --
3104       ----------------------
3105
3106       procedure Find_Source_Dirs (From : Name_Id; Location : Source_Ptr) is
3107          Directory : constant String := Get_Name_String (From);
3108          Element   : String_Element;
3109
3110          procedure Recursive_Find_Dirs (Path : Name_Id);
3111          --  Find all the subdirectories (recursively) of Path and add them
3112          --  to the list of source directories of the project.
3113
3114          -------------------------
3115          -- Recursive_Find_Dirs --
3116          -------------------------
3117
3118          procedure Recursive_Find_Dirs (Path : Name_Id) is
3119             Dir      : Dir_Type;
3120             Name     : String (1 .. 250);
3121             Last     : Natural;
3122             List     : String_List_Id := Data.Source_Dirs;
3123             Element  : String_Element;
3124             Found    : Boolean := False;
3125
3126             Non_Canonical_Path : Name_Id := No_Name;
3127             Canonical_Path     : Name_Id := No_Name;
3128
3129             The_Path : constant String :=
3130                          Normalize_Pathname (Get_Name_String (Path)) &
3131                          Directory_Separator;
3132
3133             The_Path_Last : constant Natural :=
3134                               Compute_Directory_Last (The_Path);
3135
3136          begin
3137             Name_Len := The_Path_Last - The_Path'First + 1;
3138             Name_Buffer (1 .. Name_Len) :=
3139               The_Path (The_Path'First .. The_Path_Last);
3140             Non_Canonical_Path := Name_Find;
3141             Get_Name_String (Non_Canonical_Path);
3142             Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
3143             Canonical_Path := Name_Find;
3144
3145             --  To avoid processing the same directory several times, check
3146             --  if the directory is already in Recursive_Dirs. If it is,
3147             --  then there is nothing to do, just return. If it is not, put
3148             --  it there and continue recursive processing.
3149
3150             if Recursive_Dirs.Get (Canonical_Path) then
3151                return;
3152
3153             else
3154                Recursive_Dirs.Set (Canonical_Path, True);
3155             end if;
3156
3157             --  Check if directory is already in list
3158
3159             while List /= Nil_String loop
3160                Element := In_Tree.String_Elements.Table (List);
3161
3162                if Element.Value /= No_Name then
3163                   Found := Element.Value = Canonical_Path;
3164                   exit when Found;
3165                end if;
3166
3167                List := Element.Next;
3168             end loop;
3169
3170             --  If directory is not already in list, put it there
3171
3172             if not Found then
3173                if Current_Verbosity = High then
3174                   Write_Str  ("   ");
3175                   Write_Line (The_Path (The_Path'First .. The_Path_Last));
3176                end if;
3177
3178                String_Element_Table.Increment_Last
3179                  (In_Tree.String_Elements);
3180                Element :=
3181                  (Value    => Canonical_Path,
3182                   Display_Value => Non_Canonical_Path,
3183                   Location => No_Location,
3184                   Flag     => False,
3185                   Next     => Nil_String,
3186                   Index    => 0);
3187
3188                --  Case of first source directory
3189
3190                if Last_Source_Dir = Nil_String then
3191                   Data.Source_Dirs := String_Element_Table.Last
3192                                         (In_Tree.String_Elements);
3193
3194                   --  Here we already have source directories
3195
3196                else
3197                   --  Link the previous last to the new one
3198
3199                   In_Tree.String_Elements.Table
3200                     (Last_Source_Dir).Next :=
3201                       String_Element_Table.Last
3202                         (In_Tree.String_Elements);
3203                end if;
3204
3205                --  And register this source directory as the new last
3206
3207                Last_Source_Dir  := String_Element_Table.Last
3208                  (In_Tree.String_Elements);
3209                In_Tree.String_Elements.Table (Last_Source_Dir) :=
3210                  Element;
3211             end if;
3212
3213             --  Now look for subdirectories. We do that even when this
3214             --  directory is already in the list, because some of its
3215             --  subdirectories may not be in the list yet.
3216
3217             Open (Dir, The_Path (The_Path'First .. The_Path_Last));
3218
3219             loop
3220                Read (Dir, Name, Last);
3221                exit when Last = 0;
3222
3223                if Name (1 .. Last) /= "."
3224                  and then Name (1 .. Last) /= ".."
3225                then
3226                   --  Avoid . and .. directories
3227
3228                   if Current_Verbosity = High then
3229                      Write_Str  ("   Checking ");
3230                      Write_Line (Name (1 .. Last));
3231                   end if;
3232
3233                   declare
3234                      Path_Name : constant String :=
3235                                    Normalize_Pathname
3236                                      (Name      => Name (1 .. Last),
3237                                       Directory =>
3238                                         The_Path
3239                                           (The_Path'First .. The_Path_Last),
3240                                       Resolve_Links  => False,
3241                                       Case_Sensitive => True);
3242
3243                   begin
3244                      if Is_Directory (Path_Name) then
3245
3246                         --  We have found a new subdirectory, call self
3247
3248                         Name_Len := Path_Name'Length;
3249                         Name_Buffer (1 .. Name_Len) := Path_Name;
3250                         Recursive_Find_Dirs (Name_Find);
3251                      end if;
3252                   end;
3253                end if;
3254             end loop;
3255
3256             Close (Dir);
3257
3258          exception
3259             when Directory_Error =>
3260                null;
3261          end Recursive_Find_Dirs;
3262
3263       --  Start of processing for Find_Source_Dirs
3264
3265       begin
3266          if Current_Verbosity = High then
3267             Write_Str ("Find_Source_Dirs (""");
3268             Write_Str (Directory);
3269             Write_Line (""")");
3270          end if;
3271
3272          --  First, check if we are looking for a directory tree,
3273          --  indicated by "/**" at the end.
3274
3275          if Directory'Length >= 3
3276            and then Directory (Directory'Last - 1 .. Directory'Last) = "**"
3277            and then (Directory (Directory'Last - 2) = '/'
3278                        or else
3279                      Directory (Directory'Last - 2) = Directory_Separator)
3280          then
3281             Data.Known_Order_Of_Source_Dirs := False;
3282
3283             Name_Len := Directory'Length - 3;
3284
3285             if Name_Len = 0 then
3286
3287                --  This is the case of "/**": all directories
3288                --  in the file system.
3289
3290                Name_Len := 1;
3291                Name_Buffer (1) := Directory (Directory'First);
3292
3293             else
3294                Name_Buffer (1 .. Name_Len) :=
3295                  Directory (Directory'First .. Directory'Last - 3);
3296             end if;
3297
3298             if Current_Verbosity = High then
3299                Write_Str ("Looking for all subdirectories of """);
3300                Write_Str (Name_Buffer (1 .. Name_Len));
3301                Write_Line ("""");
3302             end if;
3303
3304             declare
3305                Base_Dir : constant Name_Id := Name_Find;
3306                Root_Dir : constant String :=
3307                             Normalize_Pathname
3308                               (Name      => Get_Name_String (Base_Dir),
3309                                Directory =>
3310                                  Get_Name_String (Data.Display_Directory),
3311                                Resolve_Links  => False,
3312                                Case_Sensitive => True);
3313
3314             begin
3315                if Root_Dir'Length = 0 then
3316                   Err_Vars.Error_Msg_Name_1 := Base_Dir;
3317
3318                   if Location = No_Location then
3319                      Error_Msg
3320                        (Project, In_Tree,
3321                         "{ is not a valid directory.",
3322                         Data.Location);
3323                   else
3324                      Error_Msg
3325                        (Project, In_Tree,
3326                         "{ is not a valid directory.",
3327                         Location);
3328                   end if;
3329
3330                else
3331                   --  We have an existing directory, we register it and all
3332                   --  of its subdirectories.
3333
3334                   if Current_Verbosity = High then
3335                      Write_Line ("Looking for source directories:");
3336                   end if;
3337
3338                   Name_Len := Root_Dir'Length;
3339                   Name_Buffer (1 .. Name_Len) := Root_Dir;
3340                   Recursive_Find_Dirs (Name_Find);
3341
3342                   if Current_Verbosity = High then
3343                      Write_Line ("End of looking for source directories.");
3344                   end if;
3345                end if;
3346             end;
3347
3348          --  We have a single directory
3349
3350          else
3351             declare
3352                Path_Name         : Name_Id;
3353                Display_Path_Name : Name_Id;
3354
3355             begin
3356                Locate_Directory
3357                  (From, Data.Display_Directory, Path_Name, Display_Path_Name);
3358
3359                if Path_Name = No_Name then
3360                   Err_Vars.Error_Msg_Name_1 := From;
3361
3362                   if Location = No_Location then
3363                      Error_Msg
3364                        (Project, In_Tree,
3365                         "{ is not a valid directory",
3366                         Data.Location);
3367                   else
3368                      Error_Msg
3369                        (Project, In_Tree,
3370                         "{ is not a valid directory",
3371                         Location);
3372                   end if;
3373
3374                else
3375                   --  As it is an existing directory, we add it to
3376                   --  the list of directories.
3377
3378                   String_Element_Table.Increment_Last
3379                     (In_Tree.String_Elements);
3380                   Element.Value := Path_Name;
3381                   Element.Display_Value := Display_Path_Name;
3382
3383                   if Last_Source_Dir = Nil_String then
3384
3385                      --  This is the first source directory
3386
3387                      Data.Source_Dirs := String_Element_Table.Last
3388                                         (In_Tree.String_Elements);
3389
3390                   else
3391                      --  We already have source directories,
3392                      --  link the previous last to the new one.
3393
3394                      In_Tree.String_Elements.Table
3395                        (Last_Source_Dir).Next :=
3396                          String_Element_Table.Last
3397                            (In_Tree.String_Elements);
3398                   end if;
3399
3400                   --  And register this source directory as the new last
3401
3402                   Last_Source_Dir := String_Element_Table.Last
3403                     (In_Tree.String_Elements);
3404                   In_Tree.String_Elements.Table
3405                     (Last_Source_Dir) := Element;
3406                end if;
3407             end;
3408          end if;
3409       end Find_Source_Dirs;
3410
3411    --  Start of processing for Get_Directories
3412
3413    begin
3414       if Current_Verbosity = High then
3415          Write_Line ("Starting to look for directories");
3416       end if;
3417
3418       --  Check the object directory
3419
3420       pragma Assert (Object_Dir.Kind = Single,
3421                      "Object_Dir is not a single string");
3422
3423       --  We set the object directory to its default
3424
3425       Data.Object_Directory   := Data.Directory;
3426       Data.Display_Object_Dir := Data.Display_Directory;
3427
3428       if Object_Dir.Value /= Empty_String then
3429          Get_Name_String (Object_Dir.Value);
3430
3431          if Name_Len = 0 then
3432             Error_Msg
3433               (Project, In_Tree,
3434                "Object_Dir cannot be empty",
3435                Object_Dir.Location);
3436
3437          else
3438             --  We check that the specified object directory does exist
3439
3440             Locate_Directory
3441               (Object_Dir.Value, Data.Display_Directory,
3442                Data.Object_Directory, Data.Display_Object_Dir);
3443
3444             if Data.Object_Directory = No_Name then
3445
3446                --  The object directory does not exist, report an error
3447
3448                Err_Vars.Error_Msg_Name_1 := Object_Dir.Value;
3449                Error_Msg
3450                  (Project, In_Tree,
3451                   "the object directory { cannot be found",
3452                   Data.Location);
3453
3454                --  Do not keep a nil Object_Directory. Set it to the specified
3455                --  (relative or absolute) path. This is for the benefit of
3456                --  tools that recover from errors; for example, these tools
3457                --  could create the non existent directory.
3458
3459                Data.Display_Object_Dir := Object_Dir.Value;
3460                Get_Name_String (Object_Dir.Value);
3461                Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
3462                Data.Object_Directory := Name_Find;
3463             end if;
3464          end if;
3465       end if;
3466
3467       if Current_Verbosity = High then
3468          if Data.Object_Directory = No_Name then
3469             Write_Line ("No object directory");
3470          else
3471             Write_Str ("Object directory: """);
3472             Write_Str (Get_Name_String (Data.Display_Object_Dir));
3473             Write_Line ("""");
3474          end if;
3475       end if;
3476
3477       --  Check the exec directory
3478
3479       pragma Assert (Exec_Dir.Kind = Single,
3480                      "Exec_Dir is not a single string");
3481
3482       --  We set the object directory to its default
3483
3484       Data.Exec_Directory   := Data.Object_Directory;
3485       Data.Display_Exec_Dir := Data.Display_Object_Dir;
3486
3487       if Exec_Dir.Value /= Empty_String then
3488          Get_Name_String (Exec_Dir.Value);
3489
3490          if Name_Len = 0 then
3491             Error_Msg
3492               (Project, In_Tree,
3493                "Exec_Dir cannot be empty",
3494                Exec_Dir.Location);
3495
3496          else
3497             --  We check that the specified object directory
3498             --  does exist.
3499
3500             Locate_Directory
3501               (Exec_Dir.Value, Data.Directory,
3502                Data.Exec_Directory, Data.Display_Exec_Dir);
3503
3504             if Data.Exec_Directory = No_Name then
3505                Err_Vars.Error_Msg_Name_1 := Exec_Dir.Value;
3506                Error_Msg
3507                  (Project, In_Tree,
3508                   "the exec directory { cannot be found",
3509                   Data.Location);
3510             end if;
3511          end if;
3512       end if;
3513
3514       if Current_Verbosity = High then
3515          if Data.Exec_Directory = No_Name then
3516             Write_Line ("No exec directory");
3517          else
3518             Write_Str ("Exec directory: """);
3519             Write_Str (Get_Name_String (Data.Display_Exec_Dir));
3520             Write_Line ("""");
3521          end if;
3522       end if;
3523
3524       --  Look for the source directories
3525
3526       if Current_Verbosity = High then
3527          Write_Line ("Starting to look for source directories");
3528       end if;
3529
3530       pragma Assert (Source_Dirs.Kind = List, "Source_Dirs is not a list");
3531
3532       if Source_Dirs.Default then
3533
3534          --  No Source_Dirs specified: the single source directory
3535          --  is the one containing the project file
3536
3537          String_Element_Table.Increment_Last
3538            (In_Tree.String_Elements);
3539          Data.Source_Dirs := String_Element_Table.Last
3540            (In_Tree.String_Elements);
3541          In_Tree.String_Elements.Table (Data.Source_Dirs) :=
3542            (Value         => Data.Directory,
3543             Display_Value => Data.Display_Directory,
3544             Location      => No_Location,
3545             Flag          => False,
3546             Next          => Nil_String,
3547             Index         => 0);
3548
3549          if Current_Verbosity = High then
3550             Write_Line ("Single source directory:");
3551             Write_Str ("    """);
3552             Write_Str (Get_Name_String (Data.Display_Directory));
3553             Write_Line ("""");
3554          end if;
3555
3556       elsif Source_Dirs.Values = Nil_String then
3557
3558          --  If Source_Dirs is an empty string list, this means
3559          --  that this project contains no source. For projects that
3560          --  don't extend other projects, this also means that there is no
3561          --  need for an object directory, if not specified.
3562
3563          if Data.Extends = No_Project
3564            and then  Data.Object_Directory = Data.Directory
3565          then
3566             Data.Object_Directory := No_Name;
3567          end if;
3568
3569          Data.Source_Dirs           := Nil_String;
3570          Data.Ada_Sources_Present   := False;
3571          Data.Other_Sources_Present := False;
3572
3573       else
3574          declare
3575             Source_Dir : String_List_Id := Source_Dirs.Values;
3576             Element    : String_Element;
3577
3578          begin
3579             --  We will find the source directories for each
3580             --  element of the list
3581
3582             while Source_Dir /= Nil_String loop
3583                Element :=
3584                  In_Tree.String_Elements.Table (Source_Dir);
3585                Find_Source_Dirs (Element.Value, Element.Location);
3586                Source_Dir := Element.Next;
3587             end loop;
3588          end;
3589       end if;
3590
3591       if Current_Verbosity = High then
3592          Write_Line ("Putting source directories in canonical cases");
3593       end if;
3594
3595       declare
3596          Current : String_List_Id := Data.Source_Dirs;
3597          Element : String_Element;
3598
3599       begin
3600          while Current /= Nil_String loop
3601             Element := In_Tree.String_Elements.Table (Current);
3602             if Element.Value /= No_Name then
3603                Get_Name_String (Element.Value);
3604                Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
3605                Element.Value := Name_Find;
3606                In_Tree.String_Elements.Table (Current) := Element;
3607             end if;
3608
3609             Current := Element.Next;
3610          end loop;
3611       end;
3612
3613    end Get_Directories;
3614
3615    ---------------
3616    -- Get_Mains --
3617    ---------------
3618
3619    procedure Get_Mains
3620      (Project : Project_Id;
3621       In_Tree : Project_Tree_Ref;
3622       Data    : in out Project_Data) is
3623       Mains : constant Variable_Value :=
3624                 Prj.Util.Value_Of (Name_Main, Data.Decl.Attributes, In_Tree);
3625
3626    begin
3627       Data.Mains := Mains.Values;
3628
3629       --  If no Mains were specified, and if we are an extending
3630       --  project, inherit the Mains from the project we are extending.
3631
3632       if Mains.Default then
3633          if Data.Extends /= No_Project then
3634             Data.Mains :=
3635               In_Tree.Projects.Table (Data.Extends).Mains;
3636          end if;
3637
3638       --  In a library project file, Main cannot be specified
3639
3640       elsif Data.Library then
3641          Error_Msg
3642            (Project, In_Tree,
3643             "a library project file cannot have Main specified",
3644             Mains.Location);
3645       end if;
3646    end Get_Mains;
3647
3648    ---------------------------
3649    -- Get_Sources_From_File --
3650    ---------------------------
3651
3652    procedure Get_Sources_From_File
3653      (Path     : String;
3654       Location : Source_Ptr;
3655       Project  : Project_Id;
3656       In_Tree  : Project_Tree_Ref)
3657    is
3658       File        : Prj.Util.Text_File;
3659       Line        : String (1 .. 250);
3660       Last        : Natural;
3661       Source_Name : Name_Id;
3662
3663    begin
3664       Source_Names.Reset;
3665
3666       if Current_Verbosity = High then
3667          Write_Str  ("Opening """);
3668          Write_Str  (Path);
3669          Write_Line (""".");
3670       end if;
3671
3672       --  Open the file
3673
3674       Prj.Util.Open (File, Path);
3675
3676       if not Prj.Util.Is_Valid (File) then
3677          Error_Msg (Project, In_Tree, "file does not exist", Location);
3678       else
3679          --  Read the lines one by one
3680
3681          while not Prj.Util.End_Of_File (File) loop
3682             Prj.Util.Get_Line (File, Line, Last);
3683
3684             --  A non empty, non comment line should contain a file name
3685
3686             if Last /= 0
3687               and then (Last = 1 or else Line (1 .. 2) /= "--")
3688             then
3689                --  ??? we should check that there is no directory information
3690
3691                Name_Len := Last;
3692                Name_Buffer (1 .. Name_Len) := Line (1 .. Last);
3693                Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
3694                Source_Name := Name_Find;
3695                Source_Names.Set
3696                  (K => Source_Name,
3697                   E =>
3698                     (Name     => Source_Name,
3699                      Location => Location,
3700                      Found    => False));
3701             end if;
3702          end loop;
3703
3704          Prj.Util.Close (File);
3705
3706       end if;
3707    end Get_Sources_From_File;
3708
3709    --------------
3710    -- Get_Unit --
3711    --------------
3712
3713    procedure Get_Unit
3714      (Canonical_File_Name : Name_Id;
3715       Naming              : Naming_Data;
3716       Exception_Id        : out Ada_Naming_Exception_Id;
3717       Unit_Name           : out Name_Id;
3718       Unit_Kind           : out Spec_Or_Body;
3719       Needs_Pragma        : out Boolean)
3720    is
3721       Info_Id  : Ada_Naming_Exception_Id
3722         := Ada_Naming_Exceptions.Get (Canonical_File_Name);
3723       VMS_Name : Name_Id;
3724
3725    begin
3726       if Info_Id = No_Ada_Naming_Exception then
3727          if Hostparm.OpenVMS then
3728             VMS_Name := Canonical_File_Name;
3729             Get_Name_String (VMS_Name);
3730
3731             if Name_Buffer (Name_Len) = '.' then
3732                Name_Len := Name_Len - 1;
3733                VMS_Name := Name_Find;
3734             end if;
3735
3736             Info_Id := Ada_Naming_Exceptions.Get (VMS_Name);
3737          end if;
3738
3739       end if;
3740
3741       if Info_Id /= No_Ada_Naming_Exception then
3742          Exception_Id := Info_Id;
3743          Unit_Name := No_Name;
3744          Unit_Kind := Specification;
3745          Needs_Pragma := True;
3746          return;
3747       end if;
3748
3749       Needs_Pragma := False;
3750       Exception_Id := No_Ada_Naming_Exception;
3751
3752       Get_Name_String (Canonical_File_Name);
3753
3754       declare
3755          File          : String := Name_Buffer (1 .. Name_Len);
3756          First         : constant Positive := File'First;
3757          Last          : Natural           := File'Last;
3758          Standard_GNAT : Boolean;
3759
3760       begin
3761          Standard_GNAT :=
3762            Naming.Ada_Spec_Suffix = Default_Ada_Spec_Suffix
3763              and then Naming.Ada_Body_Suffix = Default_Ada_Body_Suffix;
3764
3765          --  Check if the end of the file name is Specification_Append
3766
3767          Get_Name_String (Naming.Ada_Spec_Suffix);
3768
3769          if File'Length > Name_Len
3770            and then File (Last - Name_Len + 1 .. Last) =
3771                                                 Name_Buffer (1 .. Name_Len)
3772          then
3773             --  We have a spec
3774
3775             Unit_Kind := Specification;
3776             Last := Last - Name_Len;
3777
3778             if Current_Verbosity = High then
3779                Write_Str  ("   Specification: ");
3780                Write_Line (File (First .. Last));
3781             end if;
3782
3783          else
3784             Get_Name_String (Naming.Ada_Body_Suffix);
3785
3786             --  Check if the end of the file name is Body_Append
3787
3788             if File'Length > Name_Len
3789               and then File (Last - Name_Len + 1 .. Last) =
3790                                                 Name_Buffer (1 .. Name_Len)
3791             then
3792                --  We have a body
3793
3794                Unit_Kind := Body_Part;
3795                Last := Last - Name_Len;
3796
3797                if Current_Verbosity = High then
3798                   Write_Str  ("   Body: ");
3799                   Write_Line (File (First .. Last));
3800                end if;
3801
3802             elsif Naming.Separate_Suffix /= Naming.Ada_Spec_Suffix then
3803                Get_Name_String (Naming.Separate_Suffix);
3804
3805                --  Check if the end of the file name is Separate_Append
3806
3807                if File'Length > Name_Len
3808                  and then File (Last - Name_Len + 1 .. Last) =
3809                                                 Name_Buffer (1 .. Name_Len)
3810                then
3811                   --  We have a separate (a body)
3812
3813                   Unit_Kind := Body_Part;
3814                   Last := Last - Name_Len;
3815
3816                   if Current_Verbosity = High then
3817                      Write_Str  ("   Separate: ");
3818                      Write_Line (File (First .. Last));
3819                   end if;
3820
3821                else
3822                   Last := 0;
3823                end if;
3824
3825             else
3826                Last := 0;
3827             end if;
3828          end if;
3829
3830          if Last = 0 then
3831
3832             --  This is not a source file
3833
3834             Unit_Name := No_Name;
3835             Unit_Kind := Specification;
3836
3837             if Current_Verbosity = High then
3838                Write_Line ("   Not a valid file name.");
3839             end if;
3840
3841             return;
3842          end if;
3843
3844          Get_Name_String (Naming.Dot_Replacement);
3845          Standard_GNAT :=
3846            Standard_GNAT and then Name_Buffer (1 .. Name_Len) = "-";
3847
3848          if Name_Buffer (1 .. Name_Len) /= "." then
3849
3850             --  If Dot_Replacement is not a single dot, then there should
3851             --  not be any dot in the name.
3852
3853             for Index in First .. Last loop
3854                if File (Index) = '.' then
3855                   if Current_Verbosity = High then
3856                      Write_Line
3857                        ("   Not a valid file name (some dot not replaced).");
3858                   end if;
3859
3860                   Unit_Name := No_Name;
3861                   return;
3862
3863                end if;
3864             end loop;
3865
3866             --  Replace the substring Dot_Replacement with dots
3867
3868             declare
3869                Index : Positive := First;
3870
3871             begin
3872                while Index <= Last - Name_Len + 1 loop
3873
3874                   if File (Index .. Index + Name_Len - 1) =
3875                     Name_Buffer (1 .. Name_Len)
3876                   then
3877                      File (Index) := '.';
3878
3879                      if Name_Len > 1 and then Index < Last then
3880                         File (Index + 1 .. Last - Name_Len + 1) :=
3881                           File (Index + Name_Len .. Last);
3882                      end if;
3883
3884                      Last := Last - Name_Len + 1;
3885                   end if;
3886
3887                   Index := Index + 1;
3888                end loop;
3889             end;
3890          end if;
3891
3892          --  Check if the casing is right
3893
3894          declare
3895             Src      : String := File (First .. Last);
3896             Src_Last : Positive := Last;
3897
3898          begin
3899             case Naming.Casing is
3900                when All_Lower_Case =>
3901                   Fixed.Translate
3902                     (Source  => Src,
3903                      Mapping => Lower_Case_Map);
3904
3905                when All_Upper_Case =>
3906                   Fixed.Translate
3907                     (Source  => Src,
3908                      Mapping => Upper_Case_Map);
3909
3910                when Mixed_Case | Unknown =>
3911                   null;
3912             end case;
3913
3914             if Src /= File (First .. Last) then
3915                if Current_Verbosity = High then
3916                   Write_Line ("   Not a valid file name (casing).");
3917                end if;
3918
3919                Unit_Name := No_Name;
3920                return;
3921             end if;
3922
3923             --  We put the name in lower case
3924
3925             Fixed.Translate
3926               (Source  => Src,
3927                Mapping => Lower_Case_Map);
3928
3929             --  In the standard GNAT naming scheme, check for special cases:
3930             --  children or separates of A, G, I or S, and run time sources.
3931
3932             if Standard_GNAT and then Src'Length >= 3 then
3933                declare
3934                   S1 : constant Character := Src (Src'First);
3935                   S2 : constant Character := Src (Src'First + 1);
3936                   S3 : constant Character := Src (Src'First + 2);
3937
3938                begin
3939                   if S1 = 'a' or else
3940                      S1 = 'g' or else
3941                      S1 = 'i' or else
3942                      S1 = 's'
3943                   then
3944                      --  Children or separates of packages A, G, I or S. On
3945                      --  VMS these names are x__ ... and on other systems the
3946                      --  names are x~... (where x is a, g, i, or s).
3947
3948                      if (OpenVMS_On_Target
3949                           and then S2 = '_'
3950                           and then S3 = '_')
3951                        or else
3952                          (not OpenVMS_On_Target
3953                            and then S2 = '~')
3954                      then
3955                         Src (Src'First + 1) := '.';
3956
3957                         if OpenVMS_On_Target then
3958                            Src_Last := Src_Last - 1;
3959                            Src (Src'First + 2 .. Src_Last) :=
3960                              Src (Src'First + 3 .. Src_Last + 1);
3961                         end if;
3962
3963                      --  If it is potentially a run time source, disable
3964                      --  filling of the mapping file to avoid warnings.
3965
3966                      elsif S2 = '.' then
3967                         Set_Mapping_File_Initial_State_To_Empty;
3968                      end if;
3969                   end if;
3970                end;
3971             end if;
3972
3973             if Current_Verbosity = High then
3974                Write_Str  ("      ");
3975                Write_Line (Src (Src'First .. Src_Last));
3976             end if;
3977
3978             --  Now, we check if this name is a valid unit name
3979
3980             Check_Ada_Name
3981               (Name => Src (Src'First .. Src_Last), Unit => Unit_Name);
3982          end;
3983
3984       end;
3985    end Get_Unit;
3986
3987    ----------
3988    -- Hash --
3989    ----------
3990
3991    function Hash (Unit : Unit_Info) return Header_Num is
3992    begin
3993       return Header_Num (Unit.Unit mod 2048);
3994    end Hash;
3995
3996    -----------------------
3997    -- Is_Illegal_Suffix --
3998    -----------------------
3999
4000    function Is_Illegal_Suffix
4001      (Suffix                          : String;
4002       Dot_Replacement_Is_A_Single_Dot : Boolean) return Boolean
4003    is
4004    begin
4005       if Suffix'Length = 0 or else Index (Suffix, ".") = 0 then
4006          return True;
4007       end if;
4008
4009       --  If dot replacement is a single dot, and first character of
4010       --  suffix is also a dot
4011
4012       if Dot_Replacement_Is_A_Single_Dot
4013         and then Suffix (Suffix'First) = '.'
4014       then
4015          for Index in Suffix'First + 1 .. Suffix'Last loop
4016
4017             --  If there is another dot
4018
4019             if Suffix (Index) = '.' then
4020
4021                --  It is illegal to have a letter following the initial dot
4022
4023                return Is_Letter (Suffix (Suffix'First + 1));
4024             end if;
4025          end loop;
4026       end if;
4027
4028       --  Everything is OK
4029
4030       return False;
4031    end Is_Illegal_Suffix;
4032
4033    ----------------------
4034    -- Locate_Directory --
4035    ----------------------
4036
4037    procedure Locate_Directory
4038      (Name    : Name_Id;
4039       Parent  : Name_Id;
4040       Dir     : out Name_Id;
4041       Display : out Name_Id)
4042    is
4043       The_Name   : constant String := Get_Name_String (Name);
4044
4045       The_Parent : constant String :=
4046                      Get_Name_String (Parent) & Directory_Separator;
4047
4048       The_Parent_Last : constant Natural :=
4049                      Compute_Directory_Last (The_Parent);
4050
4051    begin
4052       if Current_Verbosity = High then
4053          Write_Str ("Locate_Directory (""");
4054          Write_Str (The_Name);
4055          Write_Str (""", """);
4056          Write_Str (The_Parent);
4057          Write_Line (""")");
4058       end if;
4059
4060       Dir     := No_Name;
4061       Display := No_Name;
4062
4063       if Is_Absolute_Path (The_Name) then
4064          if Is_Directory (The_Name) then
4065             declare
4066                Normed : constant String :=
4067                           Normalize_Pathname
4068                             (The_Name,
4069                              Resolve_Links  => False,
4070                              Case_Sensitive => True);
4071
4072                Canonical_Path : constant String :=
4073                                   Normalize_Pathname
4074                                     (Normed,
4075                                      Resolve_Links  => True,
4076                                      Case_Sensitive => False);
4077
4078             begin
4079                Name_Len := Normed'Length;
4080                Name_Buffer (1 .. Name_Len) := Normed;
4081                Display := Name_Find;
4082
4083                Name_Len := Canonical_Path'Length;
4084                Name_Buffer (1 .. Name_Len) := Canonical_Path;
4085                Dir := Name_Find;
4086             end;
4087          end if;
4088
4089       else
4090          declare
4091             Full_Path : constant String :=
4092                           The_Parent (The_Parent'First .. The_Parent_Last) &
4093                           The_Name;
4094
4095          begin
4096             if Is_Directory (Full_Path) then
4097                declare
4098                   Normed : constant String :=
4099                              Normalize_Pathname
4100                                (Full_Path,
4101                                 Resolve_Links  => False,
4102                                 Case_Sensitive => True);
4103
4104                   Canonical_Path : constant String :=
4105                                      Normalize_Pathname
4106                                        (Normed,
4107                                         Resolve_Links  => True,
4108                                         Case_Sensitive => False);
4109
4110                begin
4111                   Name_Len := Normed'Length;
4112                   Name_Buffer (1 .. Name_Len) := Normed;
4113                   Display := Name_Find;
4114
4115                   Name_Len := Canonical_Path'Length;
4116                   Name_Buffer (1 .. Name_Len) := Canonical_Path;
4117                   Dir := Name_Find;
4118                end;
4119             end if;
4120          end;
4121       end if;
4122    end Locate_Directory;
4123
4124    ----------------------
4125    -- Look_For_Sources --
4126    ----------------------
4127
4128    procedure Look_For_Sources
4129      (Project      : Project_Id;
4130       In_Tree      : Project_Tree_Ref;
4131       Data         : in out Project_Data;
4132       Follow_Links : Boolean)
4133    is
4134       procedure Get_Path_Names_And_Record_Sources (Follow_Links : Boolean);
4135       --  Find the path names of the source files in the Source_Names table
4136       --  in the source directories and record those that are Ada sources.
4137
4138       procedure Get_Sources_From_File
4139         (Path     : String;
4140          Location : Source_Ptr);
4141       --  Get the sources of a project from a text file
4142
4143       ---------------------------------------
4144       -- Get_Path_Names_And_Record_Sources --
4145       ---------------------------------------
4146
4147       procedure Get_Path_Names_And_Record_Sources (Follow_Links : Boolean) is
4148          Source_Dir : String_List_Id := Data.Source_Dirs;
4149          Element    : String_Element;
4150          Path       : Name_Id;
4151
4152          Dir      : Dir_Type;
4153          Name     : Name_Id;
4154          Canonical_Name : Name_Id;
4155          Name_Str : String (1 .. 1_024);
4156          Last     : Natural := 0;
4157          NL       : Name_Location;
4158
4159          Current_Source : String_List_Id := Nil_String;
4160
4161          First_Error : Boolean := True;
4162
4163          Source_Recorded : Boolean := False;
4164
4165       begin
4166          --  We look in all source directories for the file names in the
4167          --  hash table Source_Names
4168
4169          while Source_Dir /= Nil_String loop
4170             Source_Recorded := False;
4171             Element := In_Tree.String_Elements.Table (Source_Dir);
4172
4173             declare
4174                Dir_Path : constant String := Get_Name_String (Element.Value);
4175             begin
4176                if Current_Verbosity = High then
4177                   Write_Str ("checking directory """);
4178                   Write_Str (Dir_Path);
4179                   Write_Line ("""");
4180                end if;
4181
4182                Open (Dir, Dir_Path);
4183
4184                loop
4185                   Read (Dir, Name_Str, Last);
4186                   exit when Last = 0;
4187                   Name_Len := Last;
4188                   Name_Buffer (1 .. Name_Len) := Name_Str (1 .. Last);
4189                   Name := Name_Find;
4190                   Canonical_Case_File_Name (Name_Str (1 .. Last));
4191                   Name_Len := Last;
4192                   Name_Buffer (1 .. Name_Len) := Name_Str (1 .. Last);
4193                   Canonical_Name := Name_Find;
4194                   NL := Source_Names.Get (Canonical_Name);
4195
4196                   if NL /= No_Name_Location and then not NL.Found then
4197                      NL.Found := True;
4198                      Source_Names.Set (Canonical_Name, NL);
4199                      Name_Len := Dir_Path'Length;
4200                      Name_Buffer (1 .. Name_Len) := Dir_Path;
4201
4202                      if Name_Buffer (Name_Len) /= Directory_Separator then
4203                         Add_Char_To_Name_Buffer (Directory_Separator);
4204                      end if;
4205
4206                      Add_Str_To_Name_Buffer (Name_Str (1 .. Last));
4207                      Path := Name_Find;
4208
4209                      if Current_Verbosity = High then
4210                         Write_Str  ("  found ");
4211                         Write_Line (Get_Name_String (Name));
4212                      end if;
4213
4214                      --  Register the source if it is an Ada compilation unit
4215
4216                      Record_Ada_Source
4217                        (File_Name       => Name,
4218                         Path_Name       => Path,
4219                         Project         => Project,
4220                         In_Tree         => In_Tree,
4221                         Data            => Data,
4222                         Location        => NL.Location,
4223                         Current_Source  => Current_Source,
4224                         Source_Recorded => Source_Recorded,
4225                         Follow_Links    => Follow_Links);
4226                   end if;
4227                end loop;
4228
4229                Close (Dir);
4230             end;
4231
4232             if Source_Recorded then
4233                In_Tree.String_Elements.Table (Source_Dir).Flag :=
4234                  True;
4235             end if;
4236
4237             Source_Dir := Element.Next;
4238          end loop;
4239
4240          --  It is an error if a source file name in a source list or
4241          --  in a source list file is not found.
4242
4243          NL := Source_Names.Get_First;
4244
4245          while NL /= No_Name_Location loop
4246             if not NL.Found then
4247                Err_Vars.Error_Msg_Name_1 := NL.Name;
4248
4249                if First_Error then
4250                   Error_Msg
4251                     (Project, In_Tree,
4252                      "source file { cannot be found",
4253                      NL.Location);
4254                   First_Error := False;
4255
4256                else
4257                   Error_Msg
4258                     (Project, In_Tree,
4259                      "\source file { cannot be found",
4260                      NL.Location);
4261                end if;
4262             end if;
4263
4264             NL := Source_Names.Get_Next;
4265          end loop;
4266       end Get_Path_Names_And_Record_Sources;
4267
4268       ---------------------------
4269       -- Get_Sources_From_File --
4270       ---------------------------
4271
4272       procedure Get_Sources_From_File
4273         (Path     : String;
4274          Location : Source_Ptr)
4275       is
4276       begin
4277          --  Get the list of sources from the file and put them in hash table
4278          --  Source_Names.
4279
4280          Get_Sources_From_File (Path, Location, Project, In_Tree);
4281
4282          --  Look in the source directories to find those sources
4283
4284          Get_Path_Names_And_Record_Sources (Follow_Links);
4285
4286          --  We should have found at least one source.
4287          --  If not, report an error/warning.
4288
4289          if Data.Sources = Nil_String then
4290             Report_No_Ada_Sources (Project, In_Tree, Location);
4291          end if;
4292       end Get_Sources_From_File;
4293
4294    begin
4295       if Data.Ada_Sources_Present then
4296          declare
4297             Sources          : constant Variable_Value :=
4298                                  Util.Value_Of
4299                                    (Name_Source_Files,
4300                                     Data.Decl.Attributes,
4301                                     In_Tree);
4302
4303             Source_List_File : constant Variable_Value :=
4304                                  Util.Value_Of
4305                                    (Name_Source_List_File,
4306                                     Data.Decl.Attributes,
4307                                     In_Tree);
4308
4309             Locally_Removed  : constant Variable_Value :=
4310                                  Util.Value_Of
4311                                    (Name_Locally_Removed_Files,
4312                                     Data.Decl.Attributes,
4313                                     In_Tree);
4314
4315          begin
4316             pragma Assert
4317               (Sources.Kind = List,
4318                "Source_Files is not a list");
4319
4320             pragma Assert
4321               (Source_List_File.Kind = Single,
4322                "Source_List_File is not a single string");
4323
4324             if not Sources.Default then
4325                if not Source_List_File.Default then
4326                   Error_Msg
4327                     (Project, In_Tree,
4328                      "?both variables source_files and " &
4329                      "source_list_file are present",
4330                      Source_List_File.Location);
4331                end if;
4332
4333                --  Sources is a list of file names
4334
4335                declare
4336                   Current  : String_List_Id := Sources.Values;
4337                   Element  : String_Element;
4338                   Location : Source_Ptr;
4339                   Name     : Name_Id;
4340
4341                begin
4342                   Source_Names.Reset;
4343
4344                   Data.Ada_Sources_Present := Current /= Nil_String;
4345
4346                   while Current /= Nil_String loop
4347                      Element :=
4348                        In_Tree.String_Elements.Table (Current);
4349                      Get_Name_String (Element.Value);
4350                      Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
4351                      Name := Name_Find;
4352
4353                      --  If the element has no location, then use the
4354                      --  location of Sources to report possible errors.
4355
4356                      if Element.Location = No_Location then
4357                         Location := Sources.Location;
4358                      else
4359                         Location := Element.Location;
4360                      end if;
4361
4362                      Source_Names.Set
4363                        (K => Name,
4364                         E =>
4365                           (Name     => Name,
4366                            Location => Location,
4367                            Found    => False));
4368
4369                      Current := Element.Next;
4370                   end loop;
4371
4372                   Get_Path_Names_And_Record_Sources (Follow_Links);
4373                end;
4374
4375                --  No source_files specified
4376
4377                --  We check Source_List_File has been specified
4378
4379             elsif not Source_List_File.Default then
4380
4381                --  Source_List_File is the name of the file
4382                --  that contains the source file names
4383
4384                declare
4385                   Source_File_Path_Name : constant String :=
4386                                             Path_Name_Of
4387                                               (Source_List_File.Value,
4388                                                Data.Directory);
4389
4390                begin
4391                   if Source_File_Path_Name'Length = 0 then
4392                      Err_Vars.Error_Msg_Name_1 := Source_List_File.Value;
4393                      Error_Msg
4394                        (Project, In_Tree,
4395                         "file with sources { does not exist",
4396                         Source_List_File.Location);
4397
4398                   else
4399                      Get_Sources_From_File
4400                        (Source_File_Path_Name,
4401                         Source_List_File.Location);
4402                   end if;
4403                end;
4404
4405             else
4406                --  Neither Source_Files nor Source_List_File has been
4407                --  specified. Find all the files that satisfy the naming
4408                --  scheme in all the source directories.
4409
4410                Find_Sources
4411                  (Project, In_Tree, Data, Ada_Language_Index, Follow_Links);
4412             end if;
4413
4414             --  If there are sources that are locally removed, mark them as
4415             --  such in the Units table.
4416
4417             if not Locally_Removed.Default then
4418
4419                --  Sources can be locally removed only in extending
4420                --  project files.
4421
4422                if Data.Extends = No_Project then
4423                   Error_Msg
4424                     (Project, In_Tree,
4425                      "Locally_Removed_Files can only be used " &
4426                      "in an extending project file",
4427                      Locally_Removed.Location);
4428
4429                else
4430                   declare
4431                      Current  : String_List_Id := Locally_Removed.Values;
4432                      Element  : String_Element;
4433                      Location : Source_Ptr;
4434                      OK       : Boolean;
4435                      Unit     : Unit_Data;
4436                      Name     : Name_Id;
4437                      Extended : Project_Id;
4438
4439                   begin
4440                      while Current /= Nil_String loop
4441                         Element :=
4442                           In_Tree.String_Elements.Table (Current);
4443                         Get_Name_String (Element.Value);
4444                         Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
4445                         Name := Name_Find;
4446
4447                         --  If the element has no location, then use the
4448                         --  location of Locally_Removed to report
4449                         --  possible errors.
4450
4451                         if Element.Location = No_Location then
4452                            Location := Locally_Removed.Location;
4453                         else
4454                            Location := Element.Location;
4455                         end if;
4456
4457                         OK := False;
4458
4459                         for Index in Unit_Table.First ..
4460                                   Unit_Table.Last (In_Tree.Units)
4461                         loop
4462                            Unit := In_Tree.Units.Table (Index);
4463
4464                            if Unit.File_Names (Specification).Name = Name then
4465                               OK := True;
4466
4467                               --  Check that this is from a project that
4468                               --  the current project extends, but not the
4469                               --  current project.
4470
4471                               Extended := Unit.File_Names
4472                                 (Specification).Project;
4473
4474                               if Extended = Project then
4475                                  Error_Msg
4476                                    (Project, In_Tree,
4477                                     "cannot remove a source " &
4478                                     "of the same project",
4479                                     Location);
4480
4481                               elsif
4482                                 Project_Extends (Project, Extended, In_Tree)
4483                               then
4484                                  Unit.File_Names
4485                                    (Specification).Path := Slash;
4486                                  Unit.File_Names
4487                                    (Specification).Needs_Pragma := False;
4488                                  In_Tree.Units.Table (Index) :=
4489                                    Unit;
4490                                  Add_Forbidden_File_Name
4491                                    (Unit.File_Names (Specification).Name);
4492                                  exit;
4493
4494                               else
4495                                  Error_Msg
4496                                    (Project, In_Tree,
4497                                     "cannot remove a source from " &
4498                                     "another project",
4499                                     Location);
4500                               end if;
4501
4502                            elsif
4503                              Unit.File_Names (Body_Part).Name = Name
4504                            then
4505                               OK := True;
4506
4507                               --  Check that this is from a project that
4508                               --  the current project extends, but not the
4509                               --  current project.
4510
4511                               Extended := Unit.File_Names
4512                                 (Body_Part).Project;
4513
4514                               if Extended = Project then
4515                                  Error_Msg
4516                                    (Project, In_Tree,
4517                                     "cannot remove a source " &
4518                                     "of the same project",
4519                                     Location);
4520
4521                               elsif
4522                                 Project_Extends (Project, Extended, In_Tree)
4523                               then
4524                                  Unit.File_Names (Body_Part).Path := Slash;
4525                                  Unit.File_Names (Body_Part).Needs_Pragma
4526                                    := False;
4527                                  In_Tree.Units.Table (Index) :=
4528                                    Unit;
4529                                  Add_Forbidden_File_Name
4530                                    (Unit.File_Names (Body_Part).Name);
4531                                  exit;
4532                               end if;
4533
4534                            end if;
4535                         end loop;
4536
4537                         if not OK then
4538                            Err_Vars.Error_Msg_Name_1 := Name;
4539                            Error_Msg
4540                              (Project, In_Tree, "unknown file {", Location);
4541                         end if;
4542
4543                         Current := Element.Next;
4544                      end loop;
4545                   end;
4546                end if;
4547             end if;
4548          end;
4549       end if;
4550
4551       if Data.Other_Sources_Present then
4552
4553          --  Set Source_Present to False. It will be set back to True
4554          --  whenever a source is found.
4555
4556          Data.Other_Sources_Present := False;
4557          for Lang in Ada_Language_Index + 1 .. Last_Language_Index loop
4558
4559             --  For each language (other than Ada) in the project file
4560
4561             if Is_Present (Lang, Data, In_Tree) then
4562
4563                --  Reset the indication that there are sources of this
4564                --  language. It will be set back to True whenever we find a
4565                --  source of the language.
4566
4567                Set (Lang, False, Data, In_Tree);
4568
4569                --  First, get the source suffix for the language
4570
4571                Set (Suffix       => Suffix_For (Lang, Data.Naming, In_Tree),
4572                     For_Language => Lang,
4573                     In_Project   => Data,
4574                     In_Tree      => In_Tree);
4575
4576                --  Then, deal with the naming exceptions, if any
4577
4578                Source_Names.Reset;
4579
4580                declare
4581                   Naming_Exceptions : constant Variable_Value :=
4582                     Value_Of
4583                       (Index     => Language_Names.Table (Lang),
4584                        Src_Index => 0,
4585                        In_Array  => Data.Naming.Implementation_Exceptions,
4586                        In_Tree   => In_Tree);
4587                   Element_Id        : String_List_Id;
4588                   Element           : String_Element;
4589                   File_Id           : Name_Id;
4590                   Source_Found      : Boolean := False;
4591
4592                begin
4593                   --  If there are naming exceptions, look through them one
4594                   --  by one.
4595
4596                   if Naming_Exceptions /= Nil_Variable_Value then
4597                      Element_Id := Naming_Exceptions.Values;
4598
4599                      while Element_Id /= Nil_String loop
4600                         Element := In_Tree.String_Elements.Table
4601                                                           (Element_Id);
4602                         Get_Name_String (Element.Value);
4603                         Canonical_Case_File_Name
4604                           (Name_Buffer (1 .. Name_Len));
4605                         File_Id := Name_Find;
4606
4607                         --  Put each naming exception in the Source_Names
4608                         --  hash table, but if there are repetition, don't
4609                         --  bother after the first instance.
4610
4611                         if
4612                           Source_Names.Get (File_Id) = No_Name_Location
4613                         then
4614                            Source_Found := True;
4615                            Source_Names.Set
4616                              (File_Id,
4617                               (Name     => File_Id,
4618                                Location => Element.Location,
4619                                Found    => False));
4620                         end if;
4621
4622                         Element_Id := Element.Next;
4623                      end loop;
4624
4625                      --  If there is at least one naming exception, record
4626                      --  those that are found in the source directories.
4627
4628                      if Source_Found then
4629                         Record_Other_Sources
4630                           (Project           => Project,
4631                            In_Tree           => In_Tree,
4632                            Data              => Data,
4633                            Language          => Lang,
4634                            Naming_Exceptions => True);
4635                      end if;
4636
4637                   end if;
4638                end;
4639
4640                --  Now, check if a list of sources is declared either through
4641                --  a string list (attribute Source_Files) or a text file
4642                --  (attribute Source_List_File). If a source list is declared,
4643                --  we will consider only those naming exceptions that are
4644                --  on the list.
4645
4646                declare
4647                   Sources          : constant Variable_Value :=
4648                                        Util.Value_Of
4649                                          (Name_Source_Files,
4650                                           Data.Decl.Attributes,
4651                                           In_Tree);
4652
4653                   Source_List_File : constant Variable_Value :=
4654                                        Util.Value_Of
4655                                          (Name_Source_List_File,
4656                                           Data.Decl.Attributes,
4657                                           In_Tree);
4658
4659                begin
4660                   pragma Assert
4661                     (Sources.Kind = List,
4662                      "Source_Files is not a list");
4663
4664                   pragma Assert
4665                     (Source_List_File.Kind = Single,
4666                      "Source_List_File is not a single string");
4667
4668                   if not Sources.Default then
4669                      if not Source_List_File.Default then
4670                         Error_Msg
4671                           (Project, In_Tree,
4672                            "?both variables source_files and " &
4673                            "source_list_file are present",
4674                            Source_List_File.Location);
4675                      end if;
4676
4677                      --  Sources is a list of file names
4678
4679                      declare
4680                         Current  : String_List_Id := Sources.Values;
4681                         Element  : String_Element;
4682                         Location : Source_Ptr;
4683                         Name     : Name_Id;
4684
4685                      begin
4686                         Source_Names.Reset;
4687
4688                         --  Put all the sources in the Source_Names hash table
4689
4690                         while Current /= Nil_String loop
4691                            Element :=
4692                              In_Tree.String_Elements.Table
4693                                (Current);
4694                            Get_Name_String (Element.Value);
4695                            Canonical_Case_File_Name
4696                              (Name_Buffer (1 .. Name_Len));
4697                            Name := Name_Find;
4698
4699                            --  If the element has no location, then use the
4700                            --  location of Sources to report possible errors.
4701
4702                            if Element.Location = No_Location then
4703                               Location := Sources.Location;
4704                            else
4705                               Location := Element.Location;
4706                            end if;
4707
4708                            Source_Names.Set
4709                              (K => Name,
4710                               E =>
4711                                 (Name     => Name,
4712                                  Location => Location,
4713                                  Found    => False));
4714
4715                            Current := Element.Next;
4716                         end loop;
4717
4718                         --  And look for their directories
4719
4720                         Record_Other_Sources
4721                           (Project           => Project,
4722                            In_Tree           => In_Tree,
4723                            Data              => Data,
4724                            Language          => Lang,
4725                            Naming_Exceptions => False);
4726                      end;
4727
4728                      --  No source_files specified
4729
4730                      --  We check if Source_List_File has been specified
4731
4732                   elsif not Source_List_File.Default then
4733
4734                      --  Source_List_File is the name of the file
4735                      --  that contains the source file names
4736
4737                      declare
4738                         Source_File_Path_Name : constant String :=
4739                           Path_Name_Of
4740                             (Source_List_File.Value,
4741                              Data.Directory);
4742
4743                      begin
4744                         if Source_File_Path_Name'Length = 0 then
4745                            Err_Vars.Error_Msg_Name_1 :=
4746                              Source_List_File.Value;
4747                            Error_Msg
4748                              (Project, In_Tree,
4749                               "file with sources { does not exist",
4750                               Source_List_File.Location);
4751
4752                         else
4753                            --  Read the file, putting each source in the
4754                            --  Source_Names hash table.
4755
4756                            Get_Sources_From_File
4757                              (Source_File_Path_Name,
4758                               Source_List_File.Location,
4759                               Project, In_Tree);
4760
4761                            --  And look for their directories
4762
4763                            Record_Other_Sources
4764                              (Project           => Project,
4765                               In_Tree           => In_Tree,
4766                               Data              => Data,
4767                               Language          => Lang,
4768                               Naming_Exceptions => False);
4769                         end if;
4770                      end;
4771
4772                   --  Neither Source_Files nor Source_List_File was specified
4773
4774                   else
4775                      --  Find all the files that satisfy the naming scheme in
4776                      --  all the source directories. All the naming exceptions
4777                      --  that effectively exist are also part of the source
4778                      --  of this language.
4779
4780                      Find_Sources (Project, In_Tree, Data, Lang);
4781                   end if;
4782                end;
4783             end if;
4784          end loop;
4785       end if;
4786    end Look_For_Sources;
4787
4788    ------------------
4789    -- Path_Name_Of --
4790    ------------------
4791
4792    function Path_Name_Of
4793      (File_Name : Name_Id;
4794       Directory : Name_Id) return String
4795    is
4796       Result : String_Access;
4797
4798       The_Directory : constant String := Get_Name_String (Directory);
4799
4800    begin
4801       Get_Name_String (File_Name);
4802       Result := Locate_Regular_File
4803         (File_Name => Name_Buffer (1 .. Name_Len),
4804          Path      => The_Directory);
4805
4806       if Result = null then
4807          return "";
4808       else
4809          Canonical_Case_File_Name (Result.all);
4810          return Result.all;
4811       end if;
4812    end Path_Name_Of;
4813
4814    -------------------------------
4815    -- Prepare_Ada_Naming_Exceptions --
4816    -------------------------------
4817
4818    procedure Prepare_Ada_Naming_Exceptions
4819      (List    : Array_Element_Id;
4820       In_Tree : Project_Tree_Ref;
4821       Kind    : Spec_Or_Body)
4822    is
4823       Current : Array_Element_Id := List;
4824       Element : Array_Element;
4825
4826       Unit : Unit_Info;
4827
4828    begin
4829       --  Traverse the list
4830
4831       while Current /= No_Array_Element loop
4832          Element := In_Tree.Array_Elements.Table (Current);
4833
4834          if Element.Index /= No_Name then
4835             Unit :=
4836               (Kind => Kind,
4837                Unit => Element.Index,
4838                Next => No_Ada_Naming_Exception);
4839             Reverse_Ada_Naming_Exceptions.Set
4840               (Unit, (Element.Value.Value, Element.Value.Index));
4841             Unit.Next := Ada_Naming_Exceptions.Get (Element.Value.Value);
4842             Ada_Naming_Exception_Table.Increment_Last;
4843             Ada_Naming_Exception_Table.Table
4844               (Ada_Naming_Exception_Table.Last) := Unit;
4845             Ada_Naming_Exceptions.Set
4846               (Element.Value.Value, Ada_Naming_Exception_Table.Last);
4847          end if;
4848
4849          Current := Element.Next;
4850       end loop;
4851    end Prepare_Ada_Naming_Exceptions;
4852
4853    ---------------------
4854    -- Project_Extends --
4855    ---------------------
4856
4857    function Project_Extends
4858      (Extending : Project_Id;
4859       Extended  : Project_Id;
4860       In_Tree   : Project_Tree_Ref) return Boolean
4861    is
4862       Current : Project_Id := Extending;
4863    begin
4864       loop
4865          if Current = No_Project then
4866             return False;
4867
4868          elsif Current = Extended then
4869             return True;
4870          end if;
4871
4872          Current := In_Tree.Projects.Table (Current).Extends;
4873       end loop;
4874    end Project_Extends;
4875
4876    -----------------------
4877    -- Record_Ada_Source --
4878    -----------------------
4879
4880    procedure Record_Ada_Source
4881      (File_Name       : Name_Id;
4882       Path_Name       : Name_Id;
4883       Project         : Project_Id;
4884       In_Tree         : Project_Tree_Ref;
4885       Data            : in out Project_Data;
4886       Location        : Source_Ptr;
4887       Current_Source  : in out String_List_Id;
4888       Source_Recorded : in out Boolean;
4889       Follow_Links    : Boolean)
4890    is
4891       Canonical_File_Name : Name_Id;
4892       Canonical_Path_Name : Name_Id;
4893
4894       Exception_Id : Ada_Naming_Exception_Id;
4895       Unit_Name    : Name_Id;
4896       Unit_Kind    : Spec_Or_Body;
4897       Unit_Index   : Int := 0;
4898       Info         : Unit_Info;
4899       Name_Index   : Name_And_Index;
4900       Needs_Pragma : Boolean;
4901
4902       The_Location    : Source_Ptr              := Location;
4903       Previous_Source : constant String_List_Id := Current_Source;
4904       Except_Name     : Name_And_Index          := No_Name_And_Index;
4905
4906       Unit_Prj : Unit_Project;
4907
4908       File_Name_Recorded : Boolean := False;
4909
4910    begin
4911       Get_Name_String (File_Name);
4912       Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
4913       Canonical_File_Name := Name_Find;
4914
4915       declare
4916          Canonical_Path : constant String :=
4917                             Normalize_Pathname
4918                               (Get_Name_String (Path_Name),
4919                                Resolve_Links => Follow_Links,
4920                                Case_Sensitive => False);
4921       begin
4922          Name_Len := 0;
4923          Add_Str_To_Name_Buffer (Canonical_Path);
4924          Canonical_Path_Name := Name_Find;
4925       end;
4926
4927       --  Find out the unit name, the unit kind and if it needs
4928       --  a specific SFN pragma.
4929
4930       Get_Unit
4931         (Canonical_File_Name => Canonical_File_Name,
4932          Naming              => Data.Naming,
4933          Exception_Id        => Exception_Id,
4934          Unit_Name           => Unit_Name,
4935          Unit_Kind           => Unit_Kind,
4936          Needs_Pragma        => Needs_Pragma);
4937
4938       if Exception_Id = No_Ada_Naming_Exception and then
4939         Unit_Name = No_Name
4940       then
4941          if Current_Verbosity = High then
4942             Write_Str  ("   """);
4943             Write_Str  (Get_Name_String (Canonical_File_Name));
4944             Write_Line (""" is not a valid source file name (ignored).");
4945          end if;
4946
4947       else
4948          --  Check to see if the source has been hidden by an exception,
4949          --  but only if it is not an exception.
4950
4951          if not Needs_Pragma then
4952             Except_Name :=
4953               Reverse_Ada_Naming_Exceptions.Get
4954                 ((Unit_Kind, Unit_Name, No_Ada_Naming_Exception));
4955
4956             if Except_Name /= No_Name_And_Index then
4957                if Current_Verbosity = High then
4958                   Write_Str  ("   """);
4959                   Write_Str  (Get_Name_String (Canonical_File_Name));
4960                   Write_Str  (""" contains a unit that is found in """);
4961                   Write_Str  (Get_Name_String (Except_Name.Name));
4962                   Write_Line (""" (ignored).");
4963                end if;
4964
4965                --  The file is not included in the source of the project,
4966                --  because it is hidden by the exception.
4967                --  So, there is nothing else to do.
4968
4969                return;
4970             end if;
4971          end if;
4972
4973          loop
4974             if Exception_Id /= No_Ada_Naming_Exception then
4975                Info := Ada_Naming_Exception_Table.Table (Exception_Id);
4976                Exception_Id := Info.Next;
4977                Info.Next := No_Ada_Naming_Exception;
4978                Name_Index := Reverse_Ada_Naming_Exceptions.Get (Info);
4979
4980                Unit_Name  := Info.Unit;
4981                Unit_Index := Name_Index.Index;
4982                Unit_Kind  := Info.Kind;
4983             end if;
4984
4985             --  Put the file name in the list of sources of the project
4986
4987             String_Element_Table.Increment_Last
4988               (In_Tree.String_Elements);
4989             In_Tree.String_Elements.Table
4990               (String_Element_Table.Last
4991                  (In_Tree.String_Elements)) :=
4992               (Value         => Canonical_File_Name,
4993                Display_Value => File_Name,
4994                Location      => No_Location,
4995                Flag          => False,
4996                Next          => Nil_String,
4997                Index         => Unit_Index);
4998
4999             if Current_Source = Nil_String then
5000                Data.Sources := String_Element_Table.Last
5001                                  (In_Tree.String_Elements);
5002             else
5003                In_Tree.String_Elements.Table
5004                  (Current_Source).Next :=
5005                  String_Element_Table.Last
5006                    (In_Tree.String_Elements);
5007             end if;
5008
5009             Current_Source := String_Element_Table.Last
5010                                 (In_Tree.String_Elements);
5011
5012             --  Put the unit in unit list
5013
5014             declare
5015                The_Unit      : Unit_Id :=
5016                  Units_Htable.Get (In_Tree.Units_HT, Unit_Name);
5017                The_Unit_Data : Unit_Data;
5018
5019             begin
5020                if Current_Verbosity = High then
5021                   Write_Str  ("Putting ");
5022                   Write_Str  (Get_Name_String (Unit_Name));
5023                   Write_Line (" in the unit list.");
5024                end if;
5025
5026                --  The unit is already in the list, but may be it is
5027                --  only the other unit kind (spec or body), or what is
5028                --  in the unit list is a unit of a project we are extending.
5029
5030                if The_Unit /= No_Unit then
5031                   The_Unit_Data := In_Tree.Units.Table (The_Unit);
5032
5033                   if The_Unit_Data.File_Names (Unit_Kind).Name = No_Name
5034                     or else Project_Extends
5035                       (Data.Extends,
5036                        The_Unit_Data.File_Names (Unit_Kind).Project,
5037                        In_Tree)
5038                   then
5039                      if The_Unit_Data.File_Names (Unit_Kind).Path = Slash then
5040                         Remove_Forbidden_File_Name
5041                           (The_Unit_Data.File_Names (Unit_Kind).Name);
5042                      end if;
5043
5044                      --  Record the file name in the hash table Files_Htable
5045
5046                      Unit_Prj := (Unit => The_Unit, Project => Project);
5047                      Files_Htable.Set
5048                        (In_Tree.Files_HT,
5049                         Canonical_File_Name,
5050                         Unit_Prj);
5051
5052                      The_Unit_Data.File_Names (Unit_Kind) :=
5053                        (Name         => Canonical_File_Name,
5054                         Index        => Unit_Index,
5055                         Display_Name => File_Name,
5056                         Path         => Canonical_Path_Name,
5057                         Display_Path => Path_Name,
5058                         Project      => Project,
5059                         Needs_Pragma => Needs_Pragma);
5060                      In_Tree.Units.Table (The_Unit) :=
5061                        The_Unit_Data;
5062                      Source_Recorded := True;
5063
5064                   elsif The_Unit_Data.File_Names (Unit_Kind).Project = Project
5065                     and then (Data.Known_Order_Of_Source_Dirs or else
5066                               The_Unit_Data.File_Names (Unit_Kind).Path =
5067                                 Canonical_Path_Name)
5068                   then
5069                      if Previous_Source = Nil_String then
5070                         Data.Sources := Nil_String;
5071                      else
5072                         In_Tree.String_Elements.Table
5073                           (Previous_Source).Next := Nil_String;
5074                         String_Element_Table.Decrement_Last
5075                           (In_Tree.String_Elements);
5076                      end if;
5077
5078                      Current_Source := Previous_Source;
5079
5080                   else
5081                      --  It is an error to have two units with the same name
5082                      --  and the same kind (spec or body).
5083
5084                      if The_Location = No_Location then
5085                         The_Location :=
5086                           In_Tree.Projects.Table
5087                             (Project).Location;
5088                      end if;
5089
5090                      Err_Vars.Error_Msg_Name_1 := Unit_Name;
5091                      Error_Msg
5092                        (Project, In_Tree, "duplicate source {", The_Location);
5093
5094                      Err_Vars.Error_Msg_Name_1 :=
5095                        In_Tree.Projects.Table
5096                          (The_Unit_Data.File_Names (Unit_Kind).Project).Name;
5097                      Err_Vars.Error_Msg_Name_2 :=
5098                        The_Unit_Data.File_Names (Unit_Kind).Path;
5099                      Error_Msg
5100                        (Project, In_Tree,
5101                         "\   project file {, {", The_Location);
5102
5103                      Err_Vars.Error_Msg_Name_1 :=
5104                        In_Tree.Projects.Table (Project).Name;
5105                      Err_Vars.Error_Msg_Name_2 := Canonical_Path_Name;
5106                      Error_Msg
5107                        (Project, In_Tree,
5108                         "\   project file {, {", The_Location);
5109                   end if;
5110
5111                --  It is a new unit, create a new record
5112
5113                else
5114                   --  First, check if there is no other unit with this file
5115                   --  name in another project. If it is, report an error.
5116                   --  Of course, we do that only for the first unit in the
5117                   --  source file.
5118
5119                   Unit_Prj := Files_Htable.Get
5120                     (In_Tree.Files_HT, Canonical_File_Name);
5121
5122                   if not File_Name_Recorded and then
5123                     Unit_Prj /= No_Unit_Project
5124                   then
5125                      Error_Msg_Name_1 := File_Name;
5126                      Error_Msg_Name_2 :=
5127                        In_Tree.Projects.Table
5128                          (Unit_Prj.Project).Name;
5129                      Error_Msg
5130                        (Project, In_Tree,
5131                         "{ is already a source of project {",
5132                         Location);
5133
5134                   else
5135                      Unit_Table.Increment_Last (In_Tree.Units);
5136                      The_Unit := Unit_Table.Last (In_Tree.Units);
5137                      Units_Htable.Set
5138                        (In_Tree.Units_HT, Unit_Name, The_Unit);
5139                      Unit_Prj := (Unit => The_Unit, Project => Project);
5140                      Files_Htable.Set
5141                        (In_Tree.Files_HT,
5142                         Canonical_File_Name,
5143                         Unit_Prj);
5144                      The_Unit_Data.Name := Unit_Name;
5145                      The_Unit_Data.File_Names (Unit_Kind) :=
5146                        (Name         => Canonical_File_Name,
5147                         Index        => Unit_Index,
5148                         Display_Name => File_Name,
5149                         Path         => Canonical_Path_Name,
5150                         Display_Path => Path_Name,
5151                         Project      => Project,
5152                         Needs_Pragma => Needs_Pragma);
5153                      In_Tree.Units.Table (The_Unit) :=
5154                        The_Unit_Data;
5155                      Source_Recorded := True;
5156                   end if;
5157                end if;
5158             end;
5159
5160             exit when Exception_Id = No_Ada_Naming_Exception;
5161             File_Name_Recorded := True;
5162          end loop;
5163       end if;
5164    end Record_Ada_Source;
5165
5166    --------------------------
5167    -- Record_Other_Sources --
5168    --------------------------
5169
5170    procedure Record_Other_Sources
5171      (Project           : Project_Id;
5172       In_Tree           : Project_Tree_Ref;
5173       Data              : in out Project_Data;
5174       Language          : Language_Index;
5175       Naming_Exceptions : Boolean)
5176    is
5177       Source_Dir : String_List_Id := Data.Source_Dirs;
5178       Element    : String_Element;
5179       Path       : Name_Id;
5180
5181       Dir            : Dir_Type;
5182       Canonical_Name : Name_Id;
5183
5184       Name_Str : String (1 .. 1_024);
5185       Last     : Natural := 0;
5186       NL       : Name_Location;
5187
5188       First_Error : Boolean := True;
5189
5190       Suffix : constant String := Body_Suffix_Of (Language, Data, In_Tree);
5191
5192    begin
5193       while Source_Dir /= Nil_String loop
5194          Element := In_Tree.String_Elements.Table (Source_Dir);
5195
5196          declare
5197             Dir_Path : constant String := Get_Name_String (Element.Value);
5198
5199          begin
5200             if Current_Verbosity = High then
5201                Write_Str ("checking directory """);
5202                Write_Str (Dir_Path);
5203                Write_Str (""" for ");
5204
5205                if Naming_Exceptions then
5206                   Write_Str ("naming exceptions");
5207
5208                else
5209                   Write_Str ("sources");
5210                end if;
5211
5212                Write_Str (" of Language ");
5213                Display_Language_Name (Language);
5214             end if;
5215
5216             Open (Dir, Dir_Path);
5217
5218             loop
5219                Read (Dir, Name_Str, Last);
5220                exit when Last = 0;
5221
5222                if Is_Regular_File
5223                  (Dir_Path & Directory_Separator & Name_Str (1 .. Last))
5224                then
5225                   Name_Len := Last;
5226                   Name_Buffer (1 .. Name_Len) := Name_Str (1 .. Last);
5227                   Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
5228                   Canonical_Name := Name_Find;
5229                   NL := Source_Names.Get (Canonical_Name);
5230
5231                   if NL /= No_Name_Location then
5232                      if NL.Found then
5233                         if not Data.Known_Order_Of_Source_Dirs then
5234                            Error_Msg_Name_1 := Canonical_Name;
5235                            Error_Msg
5236                              (Project, In_Tree,
5237                               "{ is found in several source directories",
5238                               NL.Location);
5239                         end if;
5240
5241                      else
5242                         NL.Found := True;
5243                         Source_Names.Set (Canonical_Name, NL);
5244                         Name_Len := Dir_Path'Length;
5245                         Name_Buffer (1 .. Name_Len) := Dir_Path;
5246                         Add_Char_To_Name_Buffer (Directory_Separator);
5247                         Add_Str_To_Name_Buffer (Name_Str (1 .. Last));
5248                         Path := Name_Find;
5249
5250                         Check_For_Source
5251                           (File_Name        => Canonical_Name,
5252                            Path_Name        => Path,
5253                            Project          => Project,
5254                            In_Tree          => In_Tree,
5255                            Data             => Data,
5256                            Location         => NL.Location,
5257                            Language         => Language,
5258                            Suffix           => Suffix,
5259                            Naming_Exception => Naming_Exceptions);
5260                      end if;
5261                   end if;
5262                end if;
5263             end loop;
5264
5265             Close (Dir);
5266          end;
5267
5268          Source_Dir := Element.Next;
5269       end loop;
5270
5271       if not Naming_Exceptions then
5272          NL := Source_Names.Get_First;
5273
5274          --  It is an error if a source file name in a source list or
5275          --  in a source list file is not found.
5276
5277          while NL /= No_Name_Location loop
5278             if not NL.Found then
5279                Err_Vars.Error_Msg_Name_1 := NL.Name;
5280
5281                if First_Error then
5282                   Error_Msg
5283                     (Project, In_Tree,
5284                      "source file { cannot be found",
5285                      NL.Location);
5286                   First_Error := False;
5287
5288                else
5289                   Error_Msg
5290                     (Project, In_Tree,
5291                      "\source file { cannot be found",
5292                      NL.Location);
5293                end if;
5294             end if;
5295
5296             NL := Source_Names.Get_Next;
5297          end loop;
5298
5299          --  Any naming exception of this language that is not in a list
5300          --  of sources must be removed.
5301
5302          declare
5303             Source_Id : Other_Source_Id := Data.First_Other_Source;
5304             Prev_Id   : Other_Source_Id := No_Other_Source;
5305             Source    : Other_Source;
5306
5307          begin
5308             while Source_Id /= No_Other_Source loop
5309                Source := In_Tree.Other_Sources.Table (Source_Id);
5310
5311                if Source.Language = Language
5312                  and then Source.Naming_Exception
5313                then
5314                   if Current_Verbosity = High then
5315                      Write_Str ("Naming exception """);
5316                      Write_Str (Get_Name_String (Source.File_Name));
5317                      Write_Str (""" is not in the list of sources,");
5318                      Write_Line (" so it is removed.");
5319                   end if;
5320
5321                   if Prev_Id = No_Other_Source then
5322                      Data.First_Other_Source := Source.Next;
5323
5324                   else
5325                      In_Tree.Other_Sources.Table
5326                        (Prev_Id).Next := Source.Next;
5327                   end if;
5328
5329                   Source_Id := Source.Next;
5330
5331                   if Source_Id = No_Other_Source then
5332                      Data.Last_Other_Source := Prev_Id;
5333                   end if;
5334
5335                else
5336                   Prev_Id := Source_Id;
5337                   Source_Id := Source.Next;
5338                end if;
5339             end loop;
5340          end;
5341       end if;
5342    end Record_Other_Sources;
5343
5344    ---------------------------
5345    -- Report_No_Ada_Sources --
5346    ---------------------------
5347
5348    procedure Report_No_Ada_Sources
5349      (Project  : Project_Id;
5350       In_Tree  : Project_Tree_Ref;
5351       Location : Source_Ptr)
5352    is
5353    begin
5354       case When_No_Sources is
5355          when Silent =>
5356             null;
5357
5358          when Warning | Error =>
5359             Error_Msg_Warn := When_No_Sources = Warning;
5360
5361             Error_Msg
5362               (Project, In_Tree,
5363                "<there are no Ada sources in this project",
5364                Location);
5365       end case;
5366    end Report_No_Ada_Sources;
5367
5368    ----------------------
5369    -- Show_Source_Dirs --
5370    ----------------------
5371
5372    procedure Show_Source_Dirs
5373      (Project : Project_Id;
5374       In_Tree : Project_Tree_Ref)
5375    is
5376       Current : String_List_Id;
5377       Element : String_Element;
5378
5379    begin
5380       Write_Line ("Source_Dirs:");
5381
5382       Current := In_Tree.Projects.Table (Project).Source_Dirs;
5383       while Current /= Nil_String loop
5384          Element := In_Tree.String_Elements.Table (Current);
5385          Write_Str  ("   ");
5386          Write_Line (Get_Name_String (Element.Value));
5387          Current := Element.Next;
5388       end loop;
5389
5390       Write_Line ("end Source_Dirs.");
5391    end Show_Source_Dirs;
5392
5393    ----------------
5394    -- Suffix_For --
5395    ----------------
5396
5397    function Suffix_For
5398      (Language : Language_Index;
5399       Naming   : Naming_Data;
5400       In_Tree  : Project_Tree_Ref) return Name_Id
5401    is
5402       Suffix : constant Variable_Value :=
5403         Value_Of
5404           (Index     => Language_Names.Table (Language),
5405            Src_Index => 0,
5406            In_Array  => Naming.Body_Suffix,
5407            In_Tree   => In_Tree);
5408    begin
5409       --  If no suffix for this language in package Naming, use the default
5410
5411       if Suffix = Nil_Variable_Value then
5412          Name_Len := 0;
5413
5414          case Language is
5415             when Ada_Language_Index =>
5416                Add_Str_To_Name_Buffer (".adb");
5417
5418             when C_Language_Index =>
5419                Add_Str_To_Name_Buffer (".c");
5420
5421             when C_Plus_Plus_Language_Index =>
5422                Add_Str_To_Name_Buffer (".cpp");
5423
5424             when others =>
5425                return No_Name;
5426          end case;
5427
5428       --  Otherwise use the one specified
5429
5430       else
5431          Get_Name_String (Suffix.Value);
5432       end if;
5433
5434       Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
5435       return Name_Find;
5436    end Suffix_For;
5437
5438    -------------------------
5439    -- Warn_If_Not_Sources --
5440    -------------------------
5441
5442    --  comments needed in this body ???
5443
5444    procedure Warn_If_Not_Sources
5445      (Project     : Project_Id;
5446       In_Tree     : Project_Tree_Ref;
5447       Conventions : Array_Element_Id;
5448       Specs       : Boolean;
5449       Extending   : Boolean)
5450    is
5451       Conv          : Array_Element_Id := Conventions;
5452       Unit          : Name_Id;
5453       The_Unit_Id   : Unit_Id;
5454       The_Unit_Data : Unit_Data;
5455       Location      : Source_Ptr;
5456
5457    begin
5458       while Conv /= No_Array_Element loop
5459          Unit := In_Tree.Array_Elements.Table (Conv).Index;
5460          Error_Msg_Name_1 := Unit;
5461          Get_Name_String (Unit);
5462          To_Lower (Name_Buffer (1 .. Name_Len));
5463          Unit := Name_Find;
5464          The_Unit_Id := Units_Htable.Get
5465            (In_Tree.Units_HT, Unit);
5466          Location := In_Tree.Array_Elements.Table
5467                                             (Conv).Value.Location;
5468
5469          if The_Unit_Id = No_Unit then
5470             Error_Msg
5471               (Project, In_Tree,
5472                "?unknown unit {",
5473                Location);
5474
5475          else
5476             The_Unit_Data := In_Tree.Units.Table (The_Unit_Id);
5477             Error_Msg_Name_2 :=
5478               In_Tree.Array_Elements.Table (Conv).Value.Value;
5479
5480             if Specs then
5481                if not Check_Project
5482                  (The_Unit_Data.File_Names (Specification).Project,
5483                   Project, In_Tree, Extending)
5484                then
5485                   Error_Msg
5486                     (Project, In_Tree,
5487                      "?source of spec of unit { ({)" &
5488                      " cannot be found in this project",
5489                      Location);
5490                end if;
5491
5492             else
5493                if not Check_Project
5494                  (The_Unit_Data.File_Names (Body_Part).Project,
5495                   Project, In_Tree, Extending)
5496                then
5497                   Error_Msg
5498                     (Project, In_Tree,
5499                      "?source of body of unit { ({)" &
5500                      " cannot be found in this project",
5501                      Location);
5502                end if;
5503             end if;
5504          end if;
5505
5506          Conv := In_Tree.Array_Elements.Table (Conv).Next;
5507       end loop;
5508    end Warn_If_Not_Sources;
5509
5510 end Prj.Nmsc;