OSDN Git Service

2004-06-25 Pascal Obry <obry@gnat.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / prj-env.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                              P R J . E N V                               --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2001-2004 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,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, 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 Namet;    use Namet;
28 with Opt;
29 with Osint;    use Osint;
30 with Output;   use Output;
31 with Prj.Com;  use Prj.Com;
32 with Table;
33 with Tempdir;
34
35 with GNAT.OS_Lib; use GNAT.OS_Lib;
36
37 package body Prj.Env is
38
39    type Naming_Id is new Nat;
40
41    Current_Source_Path_File : Name_Id := No_Name;
42    --  Current value of project source path file env var.
43    --  Used to avoid setting the env var to the same value.
44
45    Current_Object_Path_File : Name_Id := No_Name;
46    --  Current value of project object path file env var.
47    --  Used to avoid setting the env var to the same value.
48
49    Ada_Path_Buffer : String_Access := new String (1 .. 1024);
50    --  A buffer where values for ADA_INCLUDE_PATH
51    --  and ADA_OBJECTS_PATH are stored.
52
53    Ada_Path_Length : Natural := 0;
54    --  Index of the last valid character in Ada_Path_Buffer.
55
56    Ada_Prj_Include_File_Set : Boolean := False;
57    Ada_Prj_Objects_File_Set : Boolean := False;
58    --  These flags are set to True when the corresponding environment variables
59    --  are set and are used to give these environment variables an empty string
60    --  value at the end of the program. This has no practical effect on most
61    --  platforms, except on VMS where the logical names are deassigned, thus
62    --  avoiding the pollution of the environment of the caller.
63
64    package Namings is new Table.Table
65      (Table_Component_Type => Naming_Data,
66       Table_Index_Type     => Naming_Id,
67       Table_Low_Bound      => 1,
68       Table_Initial        => 5,
69       Table_Increment      => 100,
70       Table_Name           => "Prj.Env.Namings");
71
72    Default_Naming : constant Naming_Id := Namings.First;
73
74    Fill_Mapping_File : Boolean := True;
75
76    package Path_Files is new Table.Table
77      (Table_Component_Type => Name_Id,
78       Table_Index_Type     => Natural,
79       Table_Low_Bound      => 1,
80       Table_Initial        => 50,
81       Table_Increment      => 50,
82       Table_Name           => "Prj.Env.Path_Files");
83    --  Table storing all the temp path file names.
84    --  Used by Delete_All_Path_Files.
85
86    type Project_Flags is array (Project_Id range <>) of Boolean;
87    --  A Boolean array type used in Create_Mapping_File to select the projects
88    --  in the closure of a specific project.
89
90    package Source_Paths is new Table.Table
91      (Table_Component_Type => Name_Id,
92       Table_Index_Type     => Natural,
93       Table_Low_Bound      => 1,
94       Table_Initial        => 50,
95       Table_Increment      => 50,
96       Table_Name           => "Prj.Env.Source_Paths");
97    --  A table to store the source dirs before creating the source path file
98
99    package Object_Paths is new Table.Table
100      (Table_Component_Type => Name_Id,
101       Table_Index_Type     => Natural,
102       Table_Low_Bound      => 1,
103       Table_Initial        => 50,
104       Table_Increment      => 50,
105       Table_Name           => "Prj.Env.Source_Paths");
106    --  A table to store the object dirs, before creating the object path file
107
108    -----------------------
109    -- Local Subprograms --
110    -----------------------
111
112    function Body_Path_Name_Of (Unit : Unit_Id) return String;
113    --  Returns the path name of the body of a unit.
114    --  Compute it first, if necessary.
115
116    function Spec_Path_Name_Of (Unit : Unit_Id) return String;
117    --  Returns the path name of the spec of a unit.
118    --  Compute it first, if necessary.
119
120    procedure Add_To_Path (Source_Dirs : String_List_Id);
121    --  Add to Ada_Path_Buffer all the source directories in string list
122    --  Source_Dirs, if any. Increment Ada_Path_Length.
123
124    procedure Add_To_Path (Dir : String);
125    --  If Dir is not already in the global variable Ada_Path_Buffer, add it.
126    --  Increment Ada_Path_Length.
127    --  If Ada_Path_Length /= 0, prepend a Path_Separator character to
128    --  Path.
129
130    procedure Add_To_Source_Path (Source_Dirs : String_List_Id);
131    --  Add to Ada_Path_B all the source directories in string list
132    --  Source_Dirs, if any. Increment Ada_Path_Length.
133
134    procedure Add_To_Object_Path (Object_Dir : Name_Id);
135    --  Add Object_Dir to object path table. Make sure it is not duplicate
136    --  and it is the last one in the current table.
137
138    procedure Create_New_Path_File
139      (Path_FD   : out File_Descriptor;
140       Path_Name : out Name_Id);
141    --  Create a new temporary path file. Get the file name in Path_Name.
142    --  The name is normally obtained by increasing the number in
143    --  Temp_Path_File_Name by 1.
144
145    procedure Set_Path_File_Var (Name : String; Value : String);
146    --  Call Setenv, after calling To_Host_File_Spec
147
148    function Ultimate_Extension_Of (Project : in Project_Id) return Project_Id;
149    --  Return a project that is either Project or an extended ancestor of
150    --  Project that itself is not extended.
151
152    ----------------------
153    -- Ada_Include_Path --
154    ----------------------
155
156    function Ada_Include_Path (Project : Project_Id) return String_Access is
157
158       procedure Add (Project : Project_Id);
159       --  Add all the source directories of a project to the path only if
160       --  this project has not been visited. Calls itself recursively for
161       --  projects being extended, and imported projects. Adds the project
162       --  to the list Seen if this is the call to Add for this project.
163
164       ---------
165       -- Add --
166       ---------
167
168       procedure Add (Project : Project_Id) is
169       begin
170          --  If Seen is empty, then the project cannot have been visited
171
172          if not Projects.Table (Project).Seen then
173             Projects.Table (Project).Seen := True;
174
175             declare
176                Data : constant Project_Data := Projects.Table (Project);
177                List : Project_List := Data.Imported_Projects;
178
179             begin
180                --  Add to path all source directories of this project
181
182                Add_To_Path (Data.Source_Dirs);
183
184                --  Call Add to the project being extended, if any
185
186                if Data.Extends /= No_Project then
187                   Add (Data.Extends);
188                end if;
189
190                --  Call Add for each imported project, if any
191
192                while List /= Empty_Project_List loop
193                   Add (Project_Lists.Table (List).Project);
194                   List := Project_Lists.Table (List).Next;
195                end loop;
196             end;
197          end if;
198       end Add;
199
200    --  Start of processing for Ada_Include_Path
201
202    begin
203       --  If it is the first time we call this function for
204       --  this project, compute the source path
205
206       if Projects.Table (Project).Ada_Include_Path = null then
207          Ada_Path_Length := 0;
208
209          for Index in 1 .. Projects.Last loop
210             Projects.Table (Index).Seen := False;
211          end loop;
212
213          Add (Project);
214          Projects.Table (Project).Ada_Include_Path :=
215            new String'(Ada_Path_Buffer (1 .. Ada_Path_Length));
216       end if;
217
218       return Projects.Table (Project).Ada_Include_Path;
219    end Ada_Include_Path;
220
221    ----------------------
222    -- Ada_Include_Path --
223    ----------------------
224
225    function Ada_Include_Path
226      (Project   : Project_Id;
227       Recursive : Boolean) return String
228    is
229    begin
230       if Recursive then
231          return Ada_Include_Path (Project).all;
232       else
233          Ada_Path_Length := 0;
234          Add_To_Path (Projects.Table (Project).Source_Dirs);
235          return Ada_Path_Buffer (1 .. Ada_Path_Length);
236       end if;
237    end Ada_Include_Path;
238
239    ----------------------
240    -- Ada_Objects_Path --
241    ----------------------
242
243    function Ada_Objects_Path
244      (Project             : Project_Id;
245       Including_Libraries : Boolean := True) return String_Access
246    is
247       procedure Add (Project : Project_Id);
248       --  Add all the object directories of a project to the path only if
249       --  this project has not been visited. Calls itself recursively for
250       --  projects being extended, and imported projects. Adds the project
251       --  to the list Seen if this is the first call to Add for this project.
252
253       ---------
254       -- Add --
255       ---------
256
257       procedure Add (Project : Project_Id) is
258       begin
259          --  If this project has not been seen yet
260
261          if not Projects.Table (Project).Seen then
262             Projects.Table (Project).Seen := True;
263
264             declare
265                Data : constant Project_Data := Projects.Table (Project);
266                List : Project_List := Data.Imported_Projects;
267
268             begin
269                --  Add to path the object directory of this project
270                --  except if we don't include library project and
271                --  this is a library project.
272
273                if (Data.Library and then Including_Libraries)
274                  or else
275                  (Data.Object_Directory /= No_Name
276                    and then
277                    (not Including_Libraries or else not Data.Library))
278                then
279                   --  For a library project, add the library directory
280
281                   if Data.Library then
282                      Add_To_Path (Get_Name_String (Data.Library_Dir));
283
284                   else
285                      --  For a non library project, add the object directory
286
287                      Add_To_Path (Get_Name_String (Data.Object_Directory));
288                   end if;
289                end if;
290
291                --  Call Add to the project being extended, if any
292
293                if Data.Extends /= No_Project then
294                   Add (Data.Extends);
295                end if;
296
297                --  Call Add for each imported project, if any
298
299                while List /= Empty_Project_List loop
300                   Add (Project_Lists.Table (List).Project);
301                   List := Project_Lists.Table (List).Next;
302                end loop;
303             end;
304
305          end if;
306       end Add;
307
308    --  Start of processing for Ada_Objects_Path
309
310    begin
311       --  If it is the first time we call this function for
312       --  this project, compute the objects path
313
314       if Projects.Table (Project).Ada_Objects_Path = null then
315          Ada_Path_Length := 0;
316
317          for Index in 1 .. Projects.Last loop
318             Projects.Table (Index).Seen := False;
319          end loop;
320
321          Add (Project);
322          Projects.Table (Project).Ada_Objects_Path :=
323            new String'(Ada_Path_Buffer (1 .. Ada_Path_Length));
324       end if;
325
326       return Projects.Table (Project).Ada_Objects_Path;
327    end Ada_Objects_Path;
328
329    ------------------------
330    -- Add_To_Object_Path --
331    ------------------------
332
333    procedure Add_To_Object_Path (Object_Dir : Name_Id) is
334    begin
335       --  Check if the directory is already in the table
336
337       for Index in 1 .. Object_Paths.Last loop
338
339          --  If it is, remove it, and add it as the last one
340
341          if Object_Paths.Table (Index) = Object_Dir then
342             for Index2 in Index + 1 .. Object_Paths.Last loop
343                Object_Paths.Table (Index2 - 1) :=
344                  Object_Paths.Table (Index2);
345             end loop;
346
347             Object_Paths.Table (Object_Paths.Last) := Object_Dir;
348             return;
349          end if;
350       end loop;
351
352       --  The directory is not already in the table, add it
353
354       Object_Paths.Increment_Last;
355       Object_Paths.Table (Object_Paths.Last) := Object_Dir;
356    end Add_To_Object_Path;
357
358    -----------------
359    -- Add_To_Path --
360    -----------------
361
362    procedure Add_To_Path (Source_Dirs : String_List_Id) is
363       Current    : String_List_Id := Source_Dirs;
364       Source_Dir : String_Element;
365    begin
366       while Current /= Nil_String loop
367          Source_Dir := String_Elements.Table (Current);
368          Add_To_Path (Get_Name_String (Source_Dir.Display_Value));
369          Current := Source_Dir.Next;
370       end loop;
371    end Add_To_Path;
372
373    procedure Add_To_Path (Dir : String) is
374       Len        : Natural;
375       New_Buffer : String_Access;
376       Min_Len    : Natural;
377
378       function Is_Present (Path : String; Dir : String) return Boolean;
379       --  Return True if Dir is part of Path
380
381       ----------------
382       -- Is_Present --
383       ----------------
384
385       function Is_Present (Path : String; Dir : String) return Boolean is
386          Last : constant Integer := Path'Last - Dir'Length + 1;
387
388       begin
389          for J in Path'First .. Last loop
390
391             --  Note: the order of the conditions below is important, since
392             --  it ensures a minimal number of string comparisons.
393
394             if (J = Path'First
395                 or else Path (J - 1) = Path_Separator)
396               and then
397                 (J + Dir'Length > Path'Last
398                  or else Path (J + Dir'Length) = Path_Separator)
399               and then Dir = Path (J .. J + Dir'Length - 1)
400             then
401                return True;
402             end if;
403          end loop;
404
405          return False;
406       end Is_Present;
407
408    --  Start of processing for Add_To_Path
409
410    begin
411       if Is_Present (Ada_Path_Buffer (1 .. Ada_Path_Length), Dir) then
412
413          --  Dir is already in the path, nothing to do
414
415          return;
416       end if;
417
418       Min_Len := Ada_Path_Length + Dir'Length;
419
420       if Ada_Path_Length > 0 then
421
422          --  Add 1 for the Path_Separator character
423
424          Min_Len := Min_Len + 1;
425       end if;
426
427       --  If Ada_Path_Buffer is too small, increase it
428
429       Len := Ada_Path_Buffer'Last;
430
431       if Len < Min_Len then
432          loop
433             Len := Len * 2;
434             exit when Len >= Min_Len;
435          end loop;
436
437          New_Buffer := new String (1 .. Len);
438          New_Buffer (1 .. Ada_Path_Length) :=
439            Ada_Path_Buffer (1 .. Ada_Path_Length);
440          Free (Ada_Path_Buffer);
441          Ada_Path_Buffer := New_Buffer;
442       end if;
443
444       if Ada_Path_Length > 0 then
445          Ada_Path_Length := Ada_Path_Length + 1;
446          Ada_Path_Buffer (Ada_Path_Length) := Path_Separator;
447       end if;
448
449       Ada_Path_Buffer
450         (Ada_Path_Length + 1 .. Ada_Path_Length + Dir'Length) := Dir;
451       Ada_Path_Length := Ada_Path_Length + Dir'Length;
452    end Add_To_Path;
453
454    ------------------------
455    -- Add_To_Source_Path --
456    ------------------------
457
458    procedure Add_To_Source_Path (Source_Dirs : String_List_Id) is
459       Current    : String_List_Id := Source_Dirs;
460       Source_Dir : String_Element;
461       Add_It     : Boolean;
462
463    begin
464       --  Add each source directory
465
466       while Current /= Nil_String loop
467          Source_Dir := String_Elements.Table (Current);
468          Add_It := True;
469
470          --  Check if the source directory is already in the table
471
472          for Index in 1 .. Source_Paths.Last loop
473             --  If it is already, no need to add it
474
475             if Source_Paths.Table (Index) = Source_Dir.Value then
476                Add_It := False;
477                exit;
478             end if;
479          end loop;
480
481          if Add_It then
482             Source_Paths.Increment_Last;
483             Source_Paths.Table (Source_Paths.Last) := Source_Dir.Value;
484          end if;
485
486          --  Next source directory
487
488          Current := Source_Dir.Next;
489       end loop;
490    end Add_To_Source_Path;
491
492    -----------------------
493    -- Body_Path_Name_Of --
494    -----------------------
495
496    function Body_Path_Name_Of (Unit : Unit_Id) return String is
497       Data : Unit_Data := Units.Table (Unit);
498
499    begin
500       --  If we don't know the path name of the body of this unit,
501       --  we compute it, and we store it.
502
503       if Data.File_Names (Body_Part).Path = No_Name then
504          declare
505             Current_Source : String_List_Id :=
506               Projects.Table (Data.File_Names (Body_Part).Project).Sources;
507             Path : GNAT.OS_Lib.String_Access;
508
509          begin
510             --  By default, put the file name
511
512             Data.File_Names (Body_Part).Path :=
513               Data.File_Names (Body_Part).Name;
514
515             --  For each source directory
516
517             while Current_Source /= Nil_String loop
518                Path :=
519                  Locate_Regular_File
520                    (Namet.Get_Name_String
521                       (Data.File_Names (Body_Part).Name),
522                     Namet.Get_Name_String
523                        (String_Elements.Table (Current_Source).Value));
524
525                --  If the file is in this directory,
526                --  then we store the path, and we are done.
527
528                if Path /= null then
529                   Name_Len := Path'Length;
530                   Name_Buffer (1 .. Name_Len) := Path.all;
531                   Data.File_Names (Body_Part).Path := Name_Enter;
532                   exit;
533
534                else
535                   Current_Source :=
536                     String_Elements.Table (Current_Source).Next;
537                end if;
538             end loop;
539
540             Units.Table (Unit) := Data;
541          end;
542       end if;
543
544       --  Returned the stored value
545
546       return Namet.Get_Name_String (Data.File_Names (Body_Part).Path);
547    end Body_Path_Name_Of;
548
549    --------------------------------
550    -- Create_Config_Pragmas_File --
551    --------------------------------
552
553    procedure Create_Config_Pragmas_File
554      (For_Project          : Project_Id;
555       Main_Project         : Project_Id;
556       Include_Config_Files : Boolean := True)
557    is
558       pragma Unreferenced (Main_Project);
559       pragma Unreferenced (Include_Config_Files);
560
561       File_Name : Name_Id         := No_Name;
562       File      : File_Descriptor := Invalid_FD;
563
564       Current_Unit : Unit_Id := Units.First;
565
566       First_Project : Project_List := Empty_Project_List;
567
568       Current_Project : Project_List;
569       Current_Naming  : Naming_Id;
570
571       Status : Boolean;
572       --  For call to Close
573
574       procedure Check (Project : Project_Id);
575       --  Recursive procedure that put in the config pragmas file any non
576       --  standard naming schemes, if it is not already in the file, then call
577       --  itself for any imported project.
578
579       procedure Check_Temp_File;
580       --  Check that a temporary file has been opened.
581       --  If not, create one, and put its name in the project data,
582       --  with the indication that it is a temporary file.
583
584       procedure Put
585         (Unit_Name : Name_Id;
586          File_Name : Name_Id;
587          Unit_Kind : Spec_Or_Body;
588          Index     : Int);
589       --  Put an SFN pragma in the temporary file
590
591       procedure Put (File : File_Descriptor; S : String);
592       procedure Put_Line (File : File_Descriptor; S : String);
593       --  Output procedures, analogous to normal Text_IO procs of same name
594
595       -----------
596       -- Check --
597       -----------
598
599       procedure Check (Project : Project_Id) is
600          Data : constant Project_Data := Projects.Table (Project);
601
602       begin
603          if Current_Verbosity = High then
604             Write_Str ("Checking project file """);
605             Write_Str (Namet.Get_Name_String (Data.Name));
606             Write_Str (""".");
607             Write_Eol;
608          end if;
609
610          --  Is this project in the list of the visited project?
611
612          Current_Project := First_Project;
613          while Current_Project /= Empty_Project_List
614            and then Project_Lists.Table (Current_Project).Project /= Project
615          loop
616             Current_Project := Project_Lists.Table (Current_Project).Next;
617          end loop;
618
619          --  If it is not, put it in the list, and visit it
620
621          if Current_Project = Empty_Project_List then
622             Project_Lists.Increment_Last;
623             Project_Lists.Table (Project_Lists.Last) :=
624               (Project => Project, Next => First_Project);
625             First_Project := Project_Lists.Last;
626
627             --  Is the naming scheme of this project one that we know?
628
629             Current_Naming := Default_Naming;
630             while Current_Naming <= Namings.Last and then
631               not Same_Naming_Scheme
632               (Left => Namings.Table (Current_Naming),
633                Right => Data.Naming) loop
634                Current_Naming := Current_Naming + 1;
635             end loop;
636
637             --  If we don't know it, add it
638
639             if Current_Naming > Namings.Last then
640                Namings.Increment_Last;
641                Namings.Table (Namings.Last) := Data.Naming;
642
643                --  We need a temporary file to be created
644
645                Check_Temp_File;
646
647                --  Put the SFN pragmas for the naming scheme
648
649                --  Spec
650
651                Put_Line
652                  (File, "pragma Source_File_Name_Project");
653                Put_Line
654                  (File, "  (Spec_File_Name  => ""*" &
655                   Namet.Get_Name_String (Data.Naming.Current_Spec_Suffix) &
656                   """,");
657                Put_Line
658                  (File, "   Casing          => " &
659                   Image (Data.Naming.Casing) & ",");
660                Put_Line
661                  (File, "   Dot_Replacement => """ &
662                  Namet.Get_Name_String (Data.Naming.Dot_Replacement) &
663                   """);");
664
665                --  and body
666
667                Put_Line
668                  (File, "pragma Source_File_Name_Project");
669                Put_Line
670                  (File, "  (Body_File_Name  => ""*" &
671                   Namet.Get_Name_String (Data.Naming.Current_Body_Suffix) &
672                   """,");
673                Put_Line
674                  (File, "   Casing          => " &
675                   Image (Data.Naming.Casing) & ",");
676                Put_Line
677                  (File, "   Dot_Replacement => """ &
678                   Namet.Get_Name_String (Data.Naming.Dot_Replacement) &
679                   """);");
680
681                --  and maybe separate
682
683                if
684                  Data.Naming.Current_Body_Suffix /= Data.Naming.Separate_Suffix
685                then
686                   Put_Line
687                     (File, "pragma Source_File_Name_Project");
688                   Put_Line
689                     (File, "  (Subunit_File_Name  => ""*" &
690                      Namet.Get_Name_String (Data.Naming.Separate_Suffix) &
691                      """,");
692                   Put_Line
693                     (File, "   Casing          => " &
694                      Image (Data.Naming.Casing) &
695                      ",");
696                   Put_Line
697                     (File, "   Dot_Replacement => """ &
698                      Namet.Get_Name_String (Data.Naming.Dot_Replacement) &
699                      """);");
700                end if;
701             end if;
702
703             if Data.Extends /= No_Project then
704                Check (Data.Extends);
705             end if;
706
707             declare
708                Current : Project_List := Data.Imported_Projects;
709
710             begin
711                while Current /= Empty_Project_List loop
712                   Check (Project_Lists.Table (Current).Project);
713                   Current := Project_Lists.Table (Current).Next;
714                end loop;
715             end;
716          end if;
717       end Check;
718
719       ---------------------
720       -- Check_Temp_File --
721       ---------------------
722
723       procedure Check_Temp_File is
724       begin
725          if File = Invalid_FD then
726             Tempdir.Create_Temp_File (File, Name => File_Name);
727
728             if File = Invalid_FD then
729                Prj.Com.Fail
730                  ("unable to create temporary configuration pragmas file");
731             elsif Opt.Verbose_Mode then
732                Write_Str ("Creating temp file """);
733                Write_Str (Get_Name_String (File_Name));
734                Write_Line ("""");
735             end if;
736          end if;
737       end Check_Temp_File;
738
739       ---------
740       -- Put --
741       ---------
742
743       procedure Put
744         (Unit_Name : Name_Id;
745          File_Name : Name_Id;
746          Unit_Kind : Spec_Or_Body;
747          Index     : Int)
748       is
749       begin
750          --  A temporary file needs to be open
751
752          Check_Temp_File;
753
754          --  Put the pragma SFN for the unit kind (spec or body)
755
756          Put (File, "pragma Source_File_Name_Project (");
757          Put (File, Namet.Get_Name_String (Unit_Name));
758
759          if Unit_Kind = Specification then
760             Put (File, ", Spec_File_Name => """);
761          else
762             Put (File, ", Body_File_Name => """);
763          end if;
764
765          Put (File, Namet.Get_Name_String (File_Name));
766          Put (File, """");
767
768          if Index /= 0 then
769             Put (File, ", Index =>");
770             Put (File, Index'Img);
771          end if;
772
773          Put_Line (File, ");");
774       end Put;
775
776       procedure Put (File : File_Descriptor; S : String) is
777          Last : Natural;
778
779       begin
780          Last := Write (File, S (S'First)'Address, S'Length);
781
782          if Last /= S'Length then
783             Prj.Com.Fail ("Disk full");
784          end if;
785
786          if Current_Verbosity = High then
787             Write_Str (S);
788          end if;
789       end Put;
790
791       --------------
792       -- Put_Line --
793       --------------
794
795       procedure Put_Line (File : File_Descriptor; S : String) is
796          S0   : String (1 .. S'Length + 1);
797          Last : Natural;
798
799       begin
800          --  Add an ASCII.LF to the string. As this config file is supposed to
801          --  be used only by the compiler, we don't care about the characters
802          --  for the end of line. In fact we could have put a space, but
803          --  it is more convenient to be able to read gnat.adc during
804          --  development, for which the ASCII.LF is fine.
805
806          S0 (1 .. S'Length) := S;
807          S0 (S0'Last) := ASCII.LF;
808          Last := Write (File, S0'Address, S0'Length);
809
810          if Last /= S'Length + 1 then
811             Prj.Com.Fail ("Disk full");
812          end if;
813
814          if Current_Verbosity = High then
815             Write_Line (S);
816          end if;
817       end Put_Line;
818
819    --  Start of processing for Create_Config_Pragmas_File
820
821    begin
822       if not Projects.Table (For_Project).Config_Checked then
823
824          --  Remove any memory of processed naming schemes, if any
825
826          Namings.Set_Last (Default_Naming);
827
828          --  Check the naming schemes
829
830          Check (For_Project);
831
832          --  Visit all the units and process those that need an SFN pragma
833
834          while Current_Unit <= Units.Last loop
835             declare
836                Unit : constant Unit_Data :=
837                  Units.Table (Current_Unit);
838
839             begin
840                if Unit.File_Names (Specification).Needs_Pragma then
841                   Put (Unit.Name,
842                        Unit.File_Names (Specification).Name,
843                        Specification,
844                        Unit.File_Names (Specification).Index);
845                end if;
846
847                if Unit.File_Names (Body_Part).Needs_Pragma then
848                   Put (Unit.Name,
849                        Unit.File_Names (Body_Part).Name,
850                        Body_Part,
851                        Unit.File_Names (Body_Part).Index);
852                end if;
853
854                Current_Unit := Current_Unit + 1;
855             end;
856          end loop;
857
858          --  If there are no non standard naming scheme, issue the GNAT
859          --  standard naming scheme. This will tell the compiler that
860          --  a project file is used and will forbid any pragma SFN.
861
862          if File = Invalid_FD then
863             Check_Temp_File;
864
865             Put_Line (File, "pragma Source_File_Name_Project");
866             Put_Line (File, "   (Spec_File_Name  => ""*.ads"",");
867             Put_Line (File, "    Dot_Replacement => ""-"",");
868             Put_Line (File, "    Casing          => lowercase);");
869
870             Put_Line (File, "pragma Source_File_Name_Project");
871             Put_Line (File, "   (Body_File_Name  => ""*.adb"",");
872             Put_Line (File, "    Dot_Replacement => ""-"",");
873             Put_Line (File, "    Casing          => lowercase);");
874          end if;
875
876          --  Close the temporary file
877
878          GNAT.OS_Lib.Close (File, Status);
879
880          if not Status then
881             Prj.Com.Fail ("disk full");
882          end if;
883
884          if Opt.Verbose_Mode then
885             Write_Str ("Closing configuration file """);
886             Write_Str (Get_Name_String (File_Name));
887             Write_Line ("""");
888          end if;
889
890          Projects.Table (For_Project).Config_File_Name := File_Name;
891          Projects.Table (For_Project).Config_File_Temp := True;
892
893          Projects.Table (For_Project).Config_Checked := True;
894       end if;
895    end Create_Config_Pragmas_File;
896
897    -------------------------
898    -- Create_Mapping_File --
899    -------------------------
900
901    procedure Create_Mapping_File
902      (Project : Project_Id;
903       Name    : out Name_Id)
904    is
905       File          : File_Descriptor := Invalid_FD;
906       The_Unit_Data : Unit_Data;
907       Data          : File_Name_Data;
908
909       Status : Boolean;
910       --  For call to Close
911
912       Present : Project_Flags (No_Project .. Projects.Last) :=
913         (others => False);
914       --  For each project in the closure of Project, the corresponding flag
915       --  will be set to True;
916
917       procedure Put_Name_Buffer;
918       --  Put the line contained in the Name_Buffer in the mapping file
919
920       procedure Put_Data (Spec : Boolean);
921       --  Put the mapping of the spec or body contained in Data in the file
922       --  (3 lines).
923
924       procedure Recursive_Flag (Prj : Project_Id);
925       --  Set the flags corresponding to Prj, the projects it imports
926       --  (directly or indirectly) or extends to True. Call itself recursively.
927
928       ---------
929       -- Put --
930       ---------
931
932       procedure Put_Name_Buffer is
933          Last : Natural;
934
935       begin
936          Name_Len := Name_Len + 1;
937          Name_Buffer (Name_Len) := ASCII.LF;
938          Last := Write (File, Name_Buffer (1)'Address, Name_Len);
939
940          if Last /= Name_Len then
941             Prj.Com.Fail ("Disk full");
942          end if;
943       end Put_Name_Buffer;
944
945       --------------
946       -- Put_Data --
947       --------------
948
949       procedure Put_Data (Spec : Boolean) is
950       begin
951          --  Line with the unit name
952
953          Get_Name_String (The_Unit_Data.Name);
954          Name_Len := Name_Len + 1;
955          Name_Buffer (Name_Len) := '%';
956          Name_Len := Name_Len + 1;
957
958          if Spec then
959             Name_Buffer (Name_Len) := 's';
960          else
961             Name_Buffer (Name_Len) := 'b';
962          end if;
963
964          Put_Name_Buffer;
965
966          --  Line with the file name
967
968          Get_Name_String (Data.Name);
969          Put_Name_Buffer;
970
971          --  Line with the path name
972
973          Get_Name_String (Data.Path);
974          Put_Name_Buffer;
975
976       end Put_Data;
977
978       --------------------
979       -- Recursive_Flag --
980       --------------------
981
982       procedure Recursive_Flag (Prj : Project_Id) is
983          Imported : Project_List;
984          Proj     : Project_Id;
985
986       begin
987          --  Nothing to do for non existent project or project that has
988          --  already been flagged.
989
990          if Prj = No_Project or else Present (Prj) then
991             return;
992          end if;
993
994          --  Flag the current project
995
996          Present (Prj) := True;
997          Imported := Projects.Table (Prj).Imported_Projects;
998
999          --  Call itself for each project directly imported
1000
1001          while Imported /= Empty_Project_List loop
1002             Proj := Project_Lists.Table (Imported).Project;
1003             Imported := Project_Lists.Table (Imported).Next;
1004             Recursive_Flag (Proj);
1005          end loop;
1006
1007          --  Call itself for an eventual project being extended
1008
1009          Recursive_Flag (Projects.Table (Prj).Extends);
1010       end Recursive_Flag;
1011
1012    --  Start of processing for Create_Mapping_File
1013
1014    begin
1015       --  Flag the necessary projects
1016
1017       Recursive_Flag (Project);
1018
1019       --  Create the temporary file
1020
1021       Tempdir.Create_Temp_File (File, Name => Name);
1022
1023       if File = Invalid_FD then
1024          Prj.Com.Fail ("unable to create temporary mapping file");
1025
1026       elsif Opt.Verbose_Mode then
1027          Write_Str ("Creating temp mapping file """);
1028          Write_Str (Get_Name_String (Name));
1029          Write_Line ("""");
1030       end if;
1031
1032       if Fill_Mapping_File then
1033          --  For all units in table Units
1034
1035          for Unit in 1 .. Units.Last loop
1036             The_Unit_Data := Units.Table (Unit);
1037
1038             --  If the unit has a valid name
1039
1040             if The_Unit_Data.Name /= No_Name then
1041                Data := The_Unit_Data.File_Names (Specification);
1042
1043                --  If there is a spec, put it mapping in the file if it is
1044                --  from a project in the closure of Project.
1045
1046                if Data.Name /= No_Name and then Present (Data.Project) then
1047                   Put_Data (Spec => True);
1048                end if;
1049
1050                Data := The_Unit_Data.File_Names (Body_Part);
1051
1052                --  If there is a body (or subunit) put its mapping in the file
1053                --  if it is from a project in the closure of Project.
1054
1055                if Data.Name /= No_Name and then Present (Data.Project) then
1056                   Put_Data (Spec => False);
1057                end if;
1058
1059             end if;
1060          end loop;
1061       end if;
1062
1063       GNAT.OS_Lib.Close (File, Status);
1064
1065       if not Status then
1066          Prj.Com.Fail ("disk full");
1067       end if;
1068    end Create_Mapping_File;
1069
1070    --------------------------
1071    -- Create_New_Path_File --
1072    --------------------------
1073
1074    procedure Create_New_Path_File
1075      (Path_FD   : out File_Descriptor;
1076       Path_Name : out Name_Id)
1077    is
1078    begin
1079       Tempdir.Create_Temp_File (Path_FD, Path_Name);
1080
1081       if Path_Name /= No_Name then
1082
1083          --  Record the name, so that the temp path file will be deleted
1084          --  at the end of the program.
1085
1086          Path_Files.Increment_Last;
1087          Path_Files.Table (Path_Files.Last) := Path_Name;
1088       end if;
1089    end Create_New_Path_File;
1090
1091    ---------------------------
1092    -- Delete_All_Path_Files --
1093    ---------------------------
1094
1095    procedure Delete_All_Path_Files is
1096       Disregard : Boolean := True;
1097
1098    begin
1099       for Index in 1 .. Path_Files.Last loop
1100          if Path_Files.Table (Index) /= No_Name then
1101             Delete_File
1102               (Get_Name_String (Path_Files.Table (Index)), Disregard);
1103          end if;
1104       end loop;
1105
1106       --  If any of the environment variables ADA_PRJ_INCLUDE_FILE or
1107       --  ADA_PRJ_OBJECTS_FILE has been set, then reset their value to
1108       --  the empty string. On VMS, this has the effect of deassigning
1109       --  the logical names.
1110
1111       if Ada_Prj_Include_File_Set then
1112          Setenv (Project_Include_Path_File, "");
1113          Ada_Prj_Include_File_Set := False;
1114       end if;
1115
1116       if Ada_Prj_Objects_File_Set then
1117          Setenv (Project_Objects_Path_File, "");
1118          Ada_Prj_Objects_File_Set := False;
1119       end if;
1120    end Delete_All_Path_Files;
1121
1122    ------------------------------------
1123    -- File_Name_Of_Library_Unit_Body --
1124    ------------------------------------
1125
1126    function File_Name_Of_Library_Unit_Body
1127      (Name              : String;
1128       Project           : Project_Id;
1129       Main_Project_Only : Boolean := True;
1130       Full_Path         : Boolean := False) return String
1131    is
1132       The_Project   : Project_Id := Project;
1133       Data          : Project_Data := Projects.Table (Project);
1134       Original_Name : String := Name;
1135
1136       Extended_Spec_Name : String :=
1137                              Name & Namet.Get_Name_String
1138                                       (Data.Naming.Current_Spec_Suffix);
1139       Extended_Body_Name : String :=
1140                              Name & Namet.Get_Name_String
1141                                       (Data.Naming.Current_Body_Suffix);
1142
1143       Unit : Unit_Data;
1144
1145       The_Original_Name : Name_Id;
1146       The_Spec_Name     : Name_Id;
1147       The_Body_Name     : Name_Id;
1148
1149    begin
1150       Canonical_Case_File_Name (Original_Name);
1151       Name_Len := Original_Name'Length;
1152       Name_Buffer (1 .. Name_Len) := Original_Name;
1153       The_Original_Name := Name_Find;
1154
1155       Canonical_Case_File_Name (Extended_Spec_Name);
1156       Name_Len := Extended_Spec_Name'Length;
1157       Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1158       The_Spec_Name := Name_Find;
1159
1160       Canonical_Case_File_Name (Extended_Body_Name);
1161       Name_Len := Extended_Body_Name'Length;
1162       Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1163       The_Body_Name := Name_Find;
1164
1165       if Current_Verbosity = High then
1166          Write_Str  ("Looking for file name of """);
1167          Write_Str  (Name);
1168          Write_Char ('"');
1169          Write_Eol;
1170          Write_Str  ("   Extended Spec Name = """);
1171          Write_Str  (Extended_Spec_Name);
1172          Write_Char ('"');
1173          Write_Eol;
1174          Write_Str  ("   Extended Body Name = """);
1175          Write_Str  (Extended_Body_Name);
1176          Write_Char ('"');
1177          Write_Eol;
1178       end if;
1179
1180       --  For extending project, search in the extended project
1181       --  if the source is not found. For non extending projects,
1182       --  this loop will be run only once.
1183
1184       loop
1185          --  Loop through units
1186          --  Should have comment explaining reverse ???
1187
1188          for Current in reverse Units.First .. Units.Last loop
1189             Unit := Units.Table (Current);
1190
1191             --  Check for body
1192
1193             if not Main_Project_Only
1194               or else Unit.File_Names (Body_Part).Project = The_Project
1195             then
1196                declare
1197                   Current_Name : constant Name_Id :=
1198                                    Unit.File_Names (Body_Part).Name;
1199
1200                begin
1201                   --  Case of a body present
1202
1203                   if Current_Name /= No_Name then
1204                      if Current_Verbosity = High then
1205                         Write_Str  ("   Comparing with """);
1206                         Write_Str  (Get_Name_String (Current_Name));
1207                         Write_Char ('"');
1208                         Write_Eol;
1209                      end if;
1210
1211                      --  If it has the name of the original name,
1212                      --  return the original name
1213
1214                      if Unit.Name = The_Original_Name
1215                        or else Current_Name = The_Original_Name
1216                      then
1217                         if Current_Verbosity = High then
1218                            Write_Line ("   OK");
1219                         end if;
1220
1221                         if Full_Path then
1222                            return Get_Name_String
1223                              (Unit.File_Names (Body_Part).Path);
1224
1225                         else
1226                            return Get_Name_String (Current_Name);
1227                         end if;
1228
1229                         --  If it has the name of the extended body name,
1230                         --  return the extended body name
1231
1232                      elsif Current_Name = The_Body_Name then
1233                         if Current_Verbosity = High then
1234                            Write_Line ("   OK");
1235                         end if;
1236
1237                         if Full_Path then
1238                            return Get_Name_String
1239                              (Unit.File_Names (Body_Part).Path);
1240
1241                         else
1242                            return Extended_Body_Name;
1243                         end if;
1244
1245                      else
1246                         if Current_Verbosity = High then
1247                            Write_Line ("   not good");
1248                         end if;
1249                      end if;
1250                   end if;
1251                end;
1252             end if;
1253
1254             --  Check for spec
1255
1256             if not Main_Project_Only
1257               or else Unit.File_Names (Specification).Project = The_Project
1258             then
1259                declare
1260                   Current_Name : constant Name_Id :=
1261                                    Unit.File_Names (Specification).Name;
1262
1263                begin
1264                   --  Case of spec present
1265
1266                   if Current_Name /= No_Name then
1267                      if Current_Verbosity = High then
1268                         Write_Str  ("   Comparing with """);
1269                         Write_Str  (Get_Name_String (Current_Name));
1270                         Write_Char ('"');
1271                         Write_Eol;
1272                      end if;
1273
1274                      --  If name same as original name, return original name
1275
1276                      if Unit.Name = The_Original_Name
1277                        or else Current_Name = The_Original_Name
1278                      then
1279                         if Current_Verbosity = High then
1280                            Write_Line ("   OK");
1281                         end if;
1282
1283                         if Full_Path then
1284                            return Get_Name_String
1285                              (Unit.File_Names (Specification).Path);
1286                         else
1287                            return Get_Name_String (Current_Name);
1288                         end if;
1289
1290                         --  If it has the same name as the extended spec name,
1291                         --  return the extended spec name.
1292
1293                      elsif Current_Name = The_Spec_Name then
1294                         if Current_Verbosity = High then
1295                            Write_Line ("   OK");
1296                         end if;
1297
1298                         if Full_Path then
1299                            return Get_Name_String
1300                              (Unit.File_Names (Specification).Path);
1301                         else
1302                            return Extended_Spec_Name;
1303                         end if;
1304
1305                      else
1306                         if Current_Verbosity = High then
1307                            Write_Line ("   not good");
1308                         end if;
1309                      end if;
1310                   end if;
1311                end;
1312             end if;
1313          end loop;
1314
1315          --  If we are not in an extending project, give up
1316
1317          exit when (not Main_Project_Only) or else Data.Extends = No_Project;
1318
1319          --  Otherwise, look in the project we are extending
1320
1321          The_Project := Data.Extends;
1322          Data := Projects.Table (The_Project);
1323       end loop;
1324
1325       --  We don't know this file name, return an empty string
1326
1327       return "";
1328    end File_Name_Of_Library_Unit_Body;
1329
1330    -------------------------
1331    -- For_All_Object_Dirs --
1332    -------------------------
1333
1334    procedure For_All_Object_Dirs (Project : Project_Id) is
1335       Seen : Project_List := Empty_Project_List;
1336
1337       procedure Add (Project : Project_Id);
1338       --  Process a project. Remember the processes visited to avoid
1339       --  processing a project twice. Recursively process an eventual
1340       --  extended project, and all imported projects.
1341
1342       ---------
1343       -- Add --
1344       ---------
1345
1346       procedure Add (Project : Project_Id) is
1347          Data : constant Project_Data := Projects.Table (Project);
1348          List : Project_List := Data.Imported_Projects;
1349
1350       begin
1351          --  If the list of visited project is empty, then
1352          --  for sure we never visited this project.
1353
1354          if Seen = Empty_Project_List then
1355             Project_Lists.Increment_Last;
1356             Seen := Project_Lists.Last;
1357             Project_Lists.Table (Seen) :=
1358               (Project => Project, Next => Empty_Project_List);
1359
1360          else
1361             --  Check if the project is in the list
1362
1363             declare
1364                Current : Project_List := Seen;
1365
1366             begin
1367                loop
1368                   --  If it is, then there is nothing else to do
1369
1370                   if Project_Lists.Table (Current).Project = Project then
1371                      return;
1372                   end if;
1373
1374                   exit when Project_Lists.Table (Current).Next =
1375                     Empty_Project_List;
1376                   Current := Project_Lists.Table (Current).Next;
1377                end loop;
1378
1379                --  This project has never been visited, add it
1380                --  to the list.
1381
1382                Project_Lists.Increment_Last;
1383                Project_Lists.Table (Current).Next := Project_Lists.Last;
1384                Project_Lists.Table (Project_Lists.Last) :=
1385                  (Project => Project, Next => Empty_Project_List);
1386             end;
1387          end if;
1388
1389          --  If there is an object directory, call Action
1390          --  with its name
1391
1392          if Data.Object_Directory /= No_Name then
1393             Get_Name_String (Data.Object_Directory);
1394             Action (Name_Buffer (1 .. Name_Len));
1395          end if;
1396
1397          --  If we are extending a project, visit it
1398
1399          if Data.Extends /= No_Project then
1400             Add (Data.Extends);
1401          end if;
1402
1403          --  And visit all imported projects
1404
1405          while List /= Empty_Project_List loop
1406             Add (Project_Lists.Table (List).Project);
1407             List := Project_Lists.Table (List).Next;
1408          end loop;
1409       end Add;
1410
1411    --  Start of processing for For_All_Object_Dirs
1412
1413    begin
1414       --  Visit this project, and its imported projects,
1415       --  recursively
1416
1417       Add (Project);
1418    end For_All_Object_Dirs;
1419
1420    -------------------------
1421    -- For_All_Source_Dirs --
1422    -------------------------
1423
1424    procedure For_All_Source_Dirs (Project : Project_Id) is
1425       Seen : Project_List := Empty_Project_List;
1426
1427       procedure Add (Project : Project_Id);
1428       --  Process a project. Remember the processes visited to avoid
1429       --  processing a project twice. Recursively process an eventual
1430       --  extended project, and all imported projects.
1431
1432       ---------
1433       -- Add --
1434       ---------
1435
1436       procedure Add (Project : Project_Id) is
1437          Data : constant Project_Data := Projects.Table (Project);
1438          List : Project_List := Data.Imported_Projects;
1439
1440       begin
1441          --  If the list of visited project is empty, then
1442          --  for sure we never visited this project.
1443
1444          if Seen = Empty_Project_List then
1445             Project_Lists.Increment_Last;
1446             Seen := Project_Lists.Last;
1447             Project_Lists.Table (Seen) :=
1448               (Project => Project, Next => Empty_Project_List);
1449
1450          else
1451             --  Check if the project is in the list
1452
1453             declare
1454                Current : Project_List := Seen;
1455
1456             begin
1457                loop
1458                   --  If it is, then there is nothing else to do
1459
1460                   if Project_Lists.Table (Current).Project = Project then
1461                      return;
1462                   end if;
1463
1464                   exit when Project_Lists.Table (Current).Next =
1465                     Empty_Project_List;
1466                   Current := Project_Lists.Table (Current).Next;
1467                end loop;
1468
1469                --  This project has never been visited, add it
1470                --  to the list.
1471
1472                Project_Lists.Increment_Last;
1473                Project_Lists.Table (Current).Next := Project_Lists.Last;
1474                Project_Lists.Table (Project_Lists.Last) :=
1475                  (Project => Project, Next => Empty_Project_List);
1476             end;
1477          end if;
1478
1479          declare
1480             Current    : String_List_Id := Data.Source_Dirs;
1481             The_String : String_Element;
1482
1483          begin
1484             --  If there are Ada sources, call action with the name of every
1485             --  source directory.
1486
1487             if Projects.Table (Project).Ada_Sources_Present then
1488                while Current /= Nil_String loop
1489                   The_String := String_Elements.Table (Current);
1490                   Action (Get_Name_String (The_String.Value));
1491                   Current := The_String.Next;
1492                end loop;
1493             end if;
1494          end;
1495
1496          --  If we are extending a project, visit it
1497
1498          if Data.Extends /= No_Project then
1499             Add (Data.Extends);
1500          end if;
1501
1502          --  And visit all imported projects
1503
1504          while List /= Empty_Project_List loop
1505             Add (Project_Lists.Table (List).Project);
1506             List := Project_Lists.Table (List).Next;
1507          end loop;
1508       end Add;
1509
1510    --  Start of processing for For_All_Source_Dirs
1511
1512    begin
1513       --  Visit this project, and its imported projects recursively
1514
1515       Add (Project);
1516    end For_All_Source_Dirs;
1517
1518    -------------------
1519    -- Get_Reference --
1520    -------------------
1521
1522    procedure Get_Reference
1523      (Source_File_Name : String;
1524       Project          : out Project_Id;
1525       Path             : out Name_Id)
1526    is
1527    begin
1528       --  Body below could use some comments ???
1529
1530       if Current_Verbosity > Default then
1531          Write_Str ("Getting Reference_Of (""");
1532          Write_Str (Source_File_Name);
1533          Write_Str (""") ... ");
1534       end if;
1535
1536       declare
1537          Original_Name : String := Source_File_Name;
1538          Unit          : Unit_Data;
1539
1540       begin
1541          Canonical_Case_File_Name (Original_Name);
1542
1543          for Id in Units.First .. Units.Last loop
1544             Unit := Units.Table (Id);
1545
1546             if (Unit.File_Names (Specification).Name /= No_Name
1547                  and then
1548                    Namet.Get_Name_String
1549                      (Unit.File_Names (Specification).Name) = Original_Name)
1550               or else (Unit.File_Names (Specification).Path /= No_Name
1551                          and then
1552                            Namet.Get_Name_String
1553                            (Unit.File_Names (Specification).Path) =
1554                                                               Original_Name)
1555             then
1556                Project := Ultimate_Extension_Of
1557                             (Unit.File_Names (Specification).Project);
1558                Path := Unit.File_Names (Specification).Display_Path;
1559
1560                if Current_Verbosity > Default then
1561                   Write_Str ("Done: Specification.");
1562                   Write_Eol;
1563                end if;
1564
1565                return;
1566
1567             elsif (Unit.File_Names (Body_Part).Name /= No_Name
1568                     and then
1569                       Namet.Get_Name_String
1570                         (Unit.File_Names (Body_Part).Name) = Original_Name)
1571               or else (Unit.File_Names (Body_Part).Path /= No_Name
1572                          and then Namet.Get_Name_String
1573                                     (Unit.File_Names (Body_Part).Path) =
1574                                                              Original_Name)
1575             then
1576                Project := Ultimate_Extension_Of
1577                             (Unit.File_Names (Body_Part).Project);
1578                Path := Unit.File_Names (Body_Part).Display_Path;
1579
1580                if Current_Verbosity > Default then
1581                   Write_Str ("Done: Body.");
1582                   Write_Eol;
1583                end if;
1584
1585                return;
1586             end if;
1587          end loop;
1588       end;
1589
1590       Project := No_Project;
1591       Path    := No_Name;
1592
1593       if Current_Verbosity > Default then
1594          Write_Str ("Cannot be found.");
1595          Write_Eol;
1596       end if;
1597    end Get_Reference;
1598
1599    ----------------
1600    -- Initialize --
1601    ----------------
1602
1603    --  This is a place holder for possible required initialization in
1604    --  the future. In the current version no initialization is required.
1605
1606    procedure Initialize is
1607    begin
1608       null;
1609    end Initialize;
1610
1611    ------------------------------------
1612    -- Path_Name_Of_Library_Unit_Body --
1613    ------------------------------------
1614
1615    --  Could use some comments in the body here ???
1616
1617    function Path_Name_Of_Library_Unit_Body
1618      (Name    : String;
1619       Project : Project_Id) return String
1620    is
1621       Data          : constant Project_Data := Projects.Table (Project);
1622       Original_Name : String := Name;
1623
1624       Extended_Spec_Name : String :=
1625                              Name & Namet.Get_Name_String
1626                                      (Data.Naming.Current_Spec_Suffix);
1627       Extended_Body_Name : String :=
1628                              Name & Namet.Get_Name_String
1629                                      (Data.Naming.Current_Body_Suffix);
1630
1631       First   : Unit_Id := Units.First;
1632       Current : Unit_Id;
1633       Unit    : Unit_Data;
1634
1635    begin
1636       Canonical_Case_File_Name (Original_Name);
1637       Canonical_Case_File_Name (Extended_Spec_Name);
1638       Canonical_Case_File_Name (Extended_Body_Name);
1639
1640       if Current_Verbosity = High then
1641          Write_Str  ("Looking for path name of """);
1642          Write_Str  (Name);
1643          Write_Char ('"');
1644          Write_Eol;
1645          Write_Str  ("   Extended Spec Name = """);
1646          Write_Str  (Extended_Spec_Name);
1647          Write_Char ('"');
1648          Write_Eol;
1649          Write_Str  ("   Extended Body Name = """);
1650          Write_Str  (Extended_Body_Name);
1651          Write_Char ('"');
1652          Write_Eol;
1653       end if;
1654
1655       while First <= Units.Last
1656         and then Units.Table (First).File_Names (Body_Part).Project /= Project
1657       loop
1658          First := First + 1;
1659       end loop;
1660
1661       Current := First;
1662       while Current <= Units.Last loop
1663          Unit := Units.Table (Current);
1664
1665          if Unit.File_Names (Body_Part).Project = Project
1666            and then Unit.File_Names (Body_Part).Name /= No_Name
1667          then
1668             declare
1669                Current_Name : constant String :=
1670                  Namet.Get_Name_String (Unit.File_Names (Body_Part).Name);
1671             begin
1672                if Current_Verbosity = High then
1673                   Write_Str  ("   Comparing with """);
1674                   Write_Str  (Current_Name);
1675                   Write_Char ('"');
1676                   Write_Eol;
1677                end if;
1678
1679                if Current_Name = Original_Name then
1680                   if Current_Verbosity = High then
1681                      Write_Line ("   OK");
1682                   end if;
1683
1684                   return Body_Path_Name_Of (Current);
1685
1686                elsif Current_Name = Extended_Body_Name then
1687                   if Current_Verbosity = High then
1688                      Write_Line ("   OK");
1689                   end if;
1690
1691                   return Body_Path_Name_Of (Current);
1692
1693                else
1694                   if Current_Verbosity = High then
1695                      Write_Line ("   not good");
1696                   end if;
1697                end if;
1698             end;
1699
1700          elsif Unit.File_Names (Specification).Name /= No_Name then
1701             declare
1702                Current_Name : constant String :=
1703                                 Namet.Get_Name_String
1704                                   (Unit.File_Names (Specification).Name);
1705
1706             begin
1707                if Current_Verbosity = High then
1708                   Write_Str  ("   Comparing with """);
1709                   Write_Str  (Current_Name);
1710                   Write_Char ('"');
1711                   Write_Eol;
1712                end if;
1713
1714                if Current_Name = Original_Name then
1715                   if Current_Verbosity = High then
1716                      Write_Line ("   OK");
1717                   end if;
1718
1719                   return Spec_Path_Name_Of (Current);
1720
1721                elsif Current_Name = Extended_Spec_Name then
1722                   if Current_Verbosity = High then
1723                      Write_Line ("   OK");
1724                   end if;
1725
1726                   return Spec_Path_Name_Of (Current);
1727
1728                else
1729                   if Current_Verbosity = High then
1730                      Write_Line ("   not good");
1731                   end if;
1732                end if;
1733             end;
1734          end if;
1735          Current := Current + 1;
1736       end loop;
1737
1738       return "";
1739    end Path_Name_Of_Library_Unit_Body;
1740
1741    -------------------
1742    -- Print_Sources --
1743    -------------------
1744
1745    --  Could use some comments in this body ???
1746
1747    procedure Print_Sources is
1748       Unit : Unit_Data;
1749
1750    begin
1751       Write_Line ("List of Sources:");
1752
1753       for Id in Units.First .. Units.Last loop
1754          Unit := Units.Table (Id);
1755          Write_Str  ("   ");
1756          Write_Line (Namet.Get_Name_String (Unit.Name));
1757
1758          if Unit.File_Names (Specification).Name /= No_Name then
1759             if Unit.File_Names (Specification).Project = No_Project then
1760                Write_Line ("   No project");
1761
1762             else
1763                Write_Str  ("   Project: ");
1764                Get_Name_String
1765                  (Projects.Table
1766                    (Unit.File_Names (Specification).Project).Path_Name);
1767                Write_Line (Name_Buffer (1 .. Name_Len));
1768             end if;
1769
1770             Write_Str  ("      spec: ");
1771             Write_Line
1772               (Namet.Get_Name_String
1773                (Unit.File_Names (Specification).Name));
1774          end if;
1775
1776          if Unit.File_Names (Body_Part).Name /= No_Name then
1777             if Unit.File_Names (Body_Part).Project = No_Project then
1778                Write_Line ("   No project");
1779
1780             else
1781                Write_Str  ("   Project: ");
1782                Get_Name_String
1783                  (Projects.Table
1784                    (Unit.File_Names (Body_Part).Project).Path_Name);
1785                Write_Line (Name_Buffer (1 .. Name_Len));
1786             end if;
1787
1788             Write_Str  ("      body: ");
1789             Write_Line
1790               (Namet.Get_Name_String
1791                (Unit.File_Names (Body_Part).Name));
1792          end if;
1793       end loop;
1794
1795       Write_Line ("end of List of Sources.");
1796    end Print_Sources;
1797
1798    ----------------
1799    -- Project_Of --
1800    ----------------
1801
1802    function Project_Of
1803      (Name         : String;
1804       Main_Project : Project_Id) return Project_Id
1805    is
1806       Result : Project_Id := No_Project;
1807
1808       Original_Name : String := Name;
1809
1810       Data : constant Project_Data := Projects.Table (Main_Project);
1811
1812       Extended_Spec_Name : String :=
1813                              Name & Namet.Get_Name_String
1814                                       (Data.Naming.Current_Spec_Suffix);
1815       Extended_Body_Name : String :=
1816                              Name & Namet.Get_Name_String
1817                                       (Data.Naming.Current_Body_Suffix);
1818
1819       Unit : Unit_Data;
1820
1821       Current_Name : Name_Id;
1822
1823       The_Original_Name : Name_Id;
1824       The_Spec_Name     : Name_Id;
1825       The_Body_Name     : Name_Id;
1826
1827    begin
1828       Canonical_Case_File_Name (Original_Name);
1829       Name_Len := Original_Name'Length;
1830       Name_Buffer (1 .. Name_Len) := Original_Name;
1831       The_Original_Name := Name_Find;
1832
1833       Canonical_Case_File_Name (Extended_Spec_Name);
1834       Name_Len := Extended_Spec_Name'Length;
1835       Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1836       The_Spec_Name := Name_Find;
1837
1838       Canonical_Case_File_Name (Extended_Body_Name);
1839       Name_Len := Extended_Body_Name'Length;
1840       Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1841       The_Body_Name := Name_Find;
1842
1843       for Current in reverse Units.First .. Units.Last loop
1844          Unit := Units.Table (Current);
1845
1846          --  Check for body
1847
1848          Current_Name := Unit.File_Names (Body_Part).Name;
1849
1850          --  Case of a body present
1851
1852          if Current_Name /= No_Name then
1853
1854             --  If it has the name of the original name or the body name,
1855             --  we have found the project.
1856
1857             if Unit.Name = The_Original_Name
1858               or else Current_Name = The_Original_Name
1859               or else Current_Name = The_Body_Name
1860             then
1861                Result := Unit.File_Names (Body_Part).Project;
1862                exit;
1863             end if;
1864          end if;
1865
1866          --  Check for spec
1867
1868          Current_Name := Unit.File_Names (Specification).Name;
1869
1870          if Current_Name /= No_Name then
1871
1872             --  If name same as the original name, or the spec name, we have
1873             --  found the project.
1874
1875             if Unit.Name = The_Original_Name
1876               or else Current_Name = The_Original_Name
1877               or else Current_Name = The_Spec_Name
1878             then
1879                Result := Unit.File_Names (Specification).Project;
1880                exit;
1881             end if;
1882          end if;
1883       end loop;
1884
1885       --  Get the ultimate extending project
1886
1887       if Result /= No_Project then
1888          while Projects.Table (Result).Extended_By /= No_Project loop
1889             Result := Projects.Table (Result).Extended_By;
1890          end loop;
1891       end if;
1892
1893       return Result;
1894    end Project_Of;
1895
1896    -------------------
1897    -- Set_Ada_Paths --
1898    -------------------
1899
1900    procedure Set_Ada_Paths
1901      (Project             : Project_Id;
1902       Including_Libraries : Boolean)
1903    is
1904       Source_FD : File_Descriptor := Invalid_FD;
1905       Object_FD : File_Descriptor := Invalid_FD;
1906
1907       Process_Source_Dirs : Boolean := False;
1908       Process_Object_Dirs : Boolean := False;
1909
1910       Status : Boolean;
1911       --  For calls to Close
1912
1913       Len : Natural;
1914
1915       procedure Add (Proj : Project_Id);
1916       --  Add all the source/object directories of a project to the path only
1917       --  if this project has not been visited. Calls an internal procedure
1918       --  recursively for projects being extended, and imported projects.
1919
1920       ---------
1921       -- Add --
1922       ---------
1923
1924       procedure Add (Proj : Project_Id) is
1925
1926          procedure Recursive_Add (Project : Project_Id);
1927          --  Recursive procedure to add the source/object paths of extended/
1928          --  imported projects.
1929
1930          -------------------
1931          -- Recursive_Add --
1932          -------------------
1933
1934          procedure Recursive_Add (Project : Project_Id) is
1935          begin
1936             --  If Seen is False, then the project has not yet been visited
1937
1938             if not Projects.Table (Project).Seen then
1939                Projects.Table (Project).Seen := True;
1940
1941                declare
1942                   Data : constant Project_Data := Projects.Table (Project);
1943                   List : Project_List := Data.Imported_Projects;
1944
1945                begin
1946                   if Process_Source_Dirs then
1947
1948                      --  Add to path all source directories of this project
1949                      --  if there are Ada sources.
1950
1951                      if Projects.Table (Project).Ada_Sources_Present then
1952                         Add_To_Source_Path (Data.Source_Dirs);
1953                      end if;
1954                   end if;
1955
1956                   if Process_Object_Dirs then
1957
1958                      --  Add to path the object directory of this project
1959                      --  except if we don't include library project and
1960                      --  this is a library project.
1961
1962                      if (Data.Library and then Including_Libraries)
1963                        or else
1964                          (Data.Object_Directory /= No_Name
1965                           and then
1966                             (not Including_Libraries or else not Data.Library))
1967                      then
1968                         --  For a library project, add the library directory
1969
1970                         if Data.Library then
1971                            Add_To_Object_Path (Data.Library_Dir);
1972
1973                         else
1974                            --  For a non library project, add the object
1975                            --  directory.
1976
1977                            Add_To_Object_Path (Data.Object_Directory);
1978                         end if;
1979                      end if;
1980                   end if;
1981
1982                   --  Call Add to the project being extended, if any
1983
1984                   if Data.Extends /= No_Project then
1985                      Recursive_Add (Data.Extends);
1986                   end if;
1987
1988                   --  Call Add for each imported project, if any
1989
1990                   while List /= Empty_Project_List loop
1991                      Recursive_Add (Project_Lists.Table (List).Project);
1992                      List := Project_Lists.Table (List).Next;
1993                   end loop;
1994                end;
1995             end if;
1996          end Recursive_Add;
1997
1998       begin
1999          Source_Paths.Set_Last (0);
2000          Object_Paths.Set_Last (0);
2001
2002          for Index in 1 .. Projects.Last loop
2003             Projects.Table (Index).Seen := False;
2004          end loop;
2005
2006          Recursive_Add (Proj);
2007       end Add;
2008
2009    --  Start of processing for Set_Ada_Paths
2010
2011    begin
2012       --  If it is the first time we call this procedure for
2013       --  this project, compute the source path and/or the object path.
2014
2015       if Projects.Table (Project).Include_Path_File = No_Name then
2016          Process_Source_Dirs := True;
2017          Create_New_Path_File
2018            (Source_FD, Projects.Table (Project).Include_Path_File);
2019       end if;
2020
2021       --  For the object path, we make a distinction depending on
2022       --  Including_Libraries.
2023
2024       if Including_Libraries then
2025          if Projects.Table (Project).Objects_Path_File_With_Libs = No_Name then
2026             Process_Object_Dirs := True;
2027             Create_New_Path_File
2028               (Object_FD, Projects.Table (Project).
2029                                            Objects_Path_File_With_Libs);
2030          end if;
2031
2032       else
2033          if
2034            Projects.Table (Project).Objects_Path_File_Without_Libs = No_Name
2035          then
2036             Process_Object_Dirs := True;
2037             Create_New_Path_File
2038               (Object_FD, Projects.Table (Project).
2039                                            Objects_Path_File_Without_Libs);
2040          end if;
2041       end if;
2042
2043       --  If there is something to do, set Seen to False for all projects,
2044       --  then call the recursive procedure Add for Project.
2045
2046       if Process_Source_Dirs or Process_Object_Dirs then
2047          Add (Project);
2048       end if;
2049
2050       --  Write and close any file that has been created.
2051
2052       if Source_FD /= Invalid_FD then
2053          for Index in 1 .. Source_Paths.Last loop
2054             Get_Name_String (Source_Paths.Table (Index));
2055             Name_Len := Name_Len + 1;
2056             Name_Buffer (Name_Len) := ASCII.LF;
2057             Len := Write (Source_FD, Name_Buffer (1)'Address, Name_Len);
2058
2059             if Len /= Name_Len then
2060                Prj.Com.Fail ("disk full");
2061             end if;
2062          end loop;
2063
2064          Close (Source_FD, Status);
2065
2066          if not Status then
2067             Prj.Com.Fail ("disk full");
2068          end if;
2069       end if;
2070
2071       if Object_FD /= Invalid_FD then
2072          for Index in 1 .. Object_Paths.Last loop
2073             Get_Name_String (Object_Paths.Table (Index));
2074             Name_Len := Name_Len + 1;
2075             Name_Buffer (Name_Len) := ASCII.LF;
2076             Len := Write (Object_FD, Name_Buffer (1)'Address, Name_Len);
2077
2078             if Len /= Name_Len then
2079                Prj.Com.Fail ("disk full");
2080             end if;
2081          end loop;
2082
2083          Close (Object_FD, Status);
2084
2085          if not Status then
2086             Prj.Com.Fail ("disk full");
2087          end if;
2088       end if;
2089
2090       --  Set the env vars, if they need to be changed, and set the
2091       --  corresponding flags.
2092
2093       if Current_Source_Path_File /=
2094            Projects.Table (Project).Include_Path_File
2095       then
2096          Current_Source_Path_File :=
2097            Projects.Table (Project).Include_Path_File;
2098          Set_Path_File_Var
2099            (Project_Include_Path_File,
2100             Get_Name_String (Current_Source_Path_File));
2101          Ada_Prj_Include_File_Set := True;
2102       end if;
2103
2104       if Including_Libraries then
2105          if Current_Object_Path_File
2106               /= Projects.Table (Project).Objects_Path_File_With_Libs
2107          then
2108             Current_Object_Path_File :=
2109               Projects.Table (Project).Objects_Path_File_With_Libs;
2110             Set_Path_File_Var
2111               (Project_Objects_Path_File,
2112                Get_Name_String (Current_Object_Path_File));
2113             Ada_Prj_Objects_File_Set := True;
2114          end if;
2115
2116       else
2117          if Current_Object_Path_File
2118               /= Projects.Table (Project).Objects_Path_File_Without_Libs
2119          then
2120             Current_Object_Path_File :=
2121               Projects.Table (Project).Objects_Path_File_Without_Libs;
2122             Set_Path_File_Var
2123               (Project_Objects_Path_File,
2124                Get_Name_String (Current_Object_Path_File));
2125             Ada_Prj_Objects_File_Set := True;
2126          end if;
2127       end if;
2128    end Set_Ada_Paths;
2129
2130    ---------------------------------------------
2131    -- Set_Mapping_File_Initial_State_To_Empty --
2132    ---------------------------------------------
2133
2134    procedure Set_Mapping_File_Initial_State_To_Empty is
2135    begin
2136       Fill_Mapping_File := False;
2137    end Set_Mapping_File_Initial_State_To_Empty;
2138
2139    -----------------------
2140    -- Set_Path_File_Var --
2141    -----------------------
2142
2143    procedure Set_Path_File_Var (Name : String; Value : String) is
2144       Host_Spec : String_Access := To_Host_File_Spec (Value);
2145
2146    begin
2147       if Host_Spec = null then
2148          Prj.Com.Fail
2149            ("could not convert file name """, Value, """ to host spec");
2150       else
2151          Setenv (Name, Host_Spec.all);
2152          Free (Host_Spec);
2153       end if;
2154    end Set_Path_File_Var;
2155
2156    -----------------------
2157    -- Spec_Path_Name_Of --
2158    -----------------------
2159
2160    function Spec_Path_Name_Of (Unit : Unit_Id) return String is
2161       Data : Unit_Data := Units.Table (Unit);
2162
2163    begin
2164       if Data.File_Names (Specification).Path = No_Name then
2165          declare
2166             Current_Source : String_List_Id :=
2167               Projects.Table (Data.File_Names (Specification).Project).Sources;
2168             Path : GNAT.OS_Lib.String_Access;
2169
2170          begin
2171             Data.File_Names (Specification).Path :=
2172               Data.File_Names (Specification).Name;
2173
2174             while Current_Source /= Nil_String loop
2175                Path := Locate_Regular_File
2176                  (Namet.Get_Name_String
2177                   (Data.File_Names (Specification).Name),
2178                   Namet.Get_Name_String
2179                    (String_Elements.Table (Current_Source).Value));
2180
2181                if Path /= null then
2182                   Name_Len := Path'Length;
2183                   Name_Buffer (1 .. Name_Len) := Path.all;
2184                   Data.File_Names (Specification).Path := Name_Enter;
2185                   exit;
2186                else
2187                   Current_Source :=
2188                     String_Elements.Table (Current_Source).Next;
2189                end if;
2190             end loop;
2191
2192             Units.Table (Unit) := Data;
2193          end;
2194       end if;
2195
2196       return Namet.Get_Name_String (Data.File_Names (Specification).Path);
2197    end Spec_Path_Name_Of;
2198
2199    ---------------------------
2200    -- Ultimate_Extension_Of --
2201    ---------------------------
2202
2203    function Ultimate_Extension_Of (Project : in Project_Id) return Project_Id
2204    is
2205       Result : Project_Id := Project;
2206
2207    begin
2208       while Projects.Table (Result).Extended_By /= No_Project loop
2209          Result := Projects.Table (Result).Extended_By;
2210       end loop;
2211
2212       return Result;
2213    end Ultimate_Extension_Of;
2214
2215 --  Package initialization
2216 --  What is relationshiop to procedure Initialize
2217
2218 begin
2219    Path_Files.Set_Last (0);
2220 end Prj.Env;