OSDN Git Service

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