File : 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-2014, 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 3,  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 COPYING3.  If not, go to --
  19 -- http://www.gnu.org/licenses for a complete copy of the license.          --
  20 --                                                                          --
  21 -- GNAT was originally developed  by the GNAT team at  New York University. --
  22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
  23 --                                                                          --
  24 ------------------------------------------------------------------------------
  25 
  26 with Fmap;
  27 with Makeutl;  use Makeutl;
  28 with Opt;
  29 with Osint;    use Osint;
  30 with Output;   use Output;
  31 with Prj.Com;  use Prj.Com;
  32 with Sdefault;
  33 with Tempdir;
  34 
  35 with Ada.Text_IO; use Ada.Text_IO;
  36 
  37 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
  38 
  39 package body Prj.Env is
  40 
  41    Buffer_Initial : constant := 1_000;
  42    --  Initial arbitrary size of buffers
  43 
  44    Uninitialized_Prefix : constant String := '#' & Path_Separator;
  45    --  Prefix to indicate that the project path has not been initialized yet.
  46    --  Must be two characters long
  47 
  48    No_Project_Default_Dir : constant String := "-";
  49    --  Indicator in the project path to indicate that the default search
  50    --  directories should not be added to the path
  51 
  52    -----------------------
  53    -- Local Subprograms --
  54    -----------------------
  55 
  56    package Source_Path_Table is new GNAT.Dynamic_Tables
  57      (Table_Component_Type => Name_Id,
  58       Table_Index_Type     => Natural,
  59       Table_Low_Bound      => 1,
  60       Table_Initial        => 50,
  61       Table_Increment      => 100);
  62    --  A table to store the source dirs before creating the source path file
  63 
  64    package Object_Path_Table is new GNAT.Dynamic_Tables
  65      (Table_Component_Type => Path_Name_Type,
  66       Table_Index_Type     => Natural,
  67       Table_Low_Bound      => 1,
  68       Table_Initial        => 50,
  69       Table_Increment      => 100);
  70    --  A table to store the object dirs, before creating the object path file
  71 
  72    procedure Add_To_Buffer
  73      (S           : String;
  74       Buffer      : in out String_Access;
  75       Buffer_Last : in out Natural);
  76    --  Add a string to Buffer, extending Buffer if needed
  77 
  78    procedure Add_To_Path
  79      (Source_Dirs : String_List_Id;
  80       Shared      : Shared_Project_Tree_Data_Access;
  81       Buffer      : in out String_Access;
  82       Buffer_Last : in out Natural);
  83    --  Add to Ada_Path_Buffer all the source directories in string list
  84    --  Source_Dirs, if any.
  85 
  86    procedure Add_To_Path
  87      (Dir         : String;
  88       Buffer      : in out String_Access;
  89       Buffer_Last : in out Natural);
  90    --  If Dir is not already in the global variable Ada_Path_Buffer, add it.
  91    --  If Buffer_Last /= 0, prepend a Path_Separator character to Path.
  92 
  93    procedure Add_To_Source_Path
  94      (Source_Dirs  : String_List_Id;
  95       Shared       : Shared_Project_Tree_Data_Access;
  96       Source_Paths : in out Source_Path_Table.Instance);
  97    --  Add to Ada_Path_B all the source directories in string list
  98    --  Source_Dirs, if any. Increment Ada_Path_Length.
  99 
 100    procedure Add_To_Object_Path
 101      (Object_Dir   : Path_Name_Type;
 102       Object_Paths : in out Object_Path_Table.Instance);
 103    --  Add Object_Dir to object path table. Make sure it is not duplicate
 104    --  and it is the last one in the current table.
 105 
 106    ----------------------
 107    -- Ada_Include_Path --
 108    ----------------------
 109 
 110    function Ada_Include_Path
 111      (Project   : Project_Id;
 112       In_Tree   : Project_Tree_Ref;
 113       Recursive : Boolean := False) return String
 114    is
 115       Buffer      : String_Access;
 116       Buffer_Last : Natural := 0;
 117 
 118       procedure Add
 119         (Project : Project_Id;
 120          In_Tree : Project_Tree_Ref;
 121          Dummy   : in out Boolean);
 122       --  Add source dirs of Project to the path
 123 
 124       ---------
 125       -- Add --
 126       ---------
 127 
 128       procedure Add
 129         (Project : Project_Id;
 130          In_Tree : Project_Tree_Ref;
 131          Dummy   : in out Boolean)
 132       is
 133       begin
 134          Add_To_Path
 135            (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
 136       end Add;
 137 
 138       procedure For_All_Projects is
 139         new For_Every_Project_Imported (Boolean, Add);
 140 
 141       Dummy : Boolean := False;
 142 
 143    --  Start of processing for Ada_Include_Path
 144 
 145    begin
 146       if Recursive then
 147 
 148          --  If it is the first time we call this function for this project,
 149          --  compute the source path.
 150 
 151          if Project.Ada_Include_Path = null then
 152             Buffer := new String (1 .. Buffer_Initial);
 153             For_All_Projects
 154               (Project, In_Tree, Dummy, Include_Aggregated => True);
 155             Project.Ada_Include_Path := new String'(Buffer (1 .. Buffer_Last));
 156             Free (Buffer);
 157          end if;
 158 
 159          return Project.Ada_Include_Path.all;
 160 
 161       else
 162          Buffer := new String (1 .. Buffer_Initial);
 163          Add_To_Path
 164            (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
 165 
 166          declare
 167             Result : constant String := Buffer (1 .. Buffer_Last);
 168          begin
 169             Free (Buffer);
 170             return Result;
 171          end;
 172       end if;
 173    end Ada_Include_Path;
 174 
 175    ----------------------
 176    -- Ada_Objects_Path --
 177    ----------------------
 178 
 179    function Ada_Objects_Path
 180      (Project             : Project_Id;
 181       In_Tree             : Project_Tree_Ref;
 182       Including_Libraries : Boolean := True) return String_Access
 183    is
 184       Buffer      : String_Access;
 185       Buffer_Last : Natural := 0;
 186 
 187       procedure Add
 188         (Project : Project_Id;
 189          In_Tree : Project_Tree_Ref;
 190          Dummy   : in out Boolean);
 191       --  Add all the object directories of a project to the path
 192 
 193       ---------
 194       -- Add --
 195       ---------
 196 
 197       procedure Add
 198         (Project : Project_Id;
 199          In_Tree : Project_Tree_Ref;
 200          Dummy   : in out Boolean)
 201       is
 202          pragma Unreferenced (In_Tree);
 203 
 204          Path : constant Path_Name_Type :=
 205                   Get_Object_Directory
 206                     (Project,
 207                      Including_Libraries => Including_Libraries,
 208                      Only_If_Ada         => False);
 209       begin
 210          if Path /= No_Path then
 211             Add_To_Path (Get_Name_String (Path), Buffer, Buffer_Last);
 212          end if;
 213       end Add;
 214 
 215       procedure For_All_Projects is
 216         new For_Every_Project_Imported (Boolean, Add);
 217 
 218       Dummy : Boolean := False;
 219 
 220       Result : String_Access;
 221 
 222    --  Start of processing for Ada_Objects_Path
 223 
 224    begin
 225       --  If it is the first time we call this function for
 226       --  this project, compute the objects path
 227 
 228       if Including_Libraries and then Project.Ada_Objects_Path /= null then
 229          return Project.Ada_Objects_Path;
 230 
 231       elsif not Including_Libraries
 232         and then Project.Ada_Objects_Path_No_Libs /= null
 233       then
 234          return Project.Ada_Objects_Path_No_Libs;
 235 
 236       else
 237          Buffer := new String (1 .. Buffer_Initial);
 238          For_All_Projects (Project, In_Tree, Dummy);
 239          Result := new String'(Buffer (1 .. Buffer_Last));
 240          Free (Buffer);
 241 
 242          if Including_Libraries then
 243             Project.Ada_Objects_Path := Result;
 244          else
 245             Project.Ada_Objects_Path_No_Libs := Result;
 246          end if;
 247 
 248          return Result;
 249       end if;
 250    end Ada_Objects_Path;
 251 
 252    -------------------
 253    -- Add_To_Buffer --
 254    -------------------
 255 
 256    procedure Add_To_Buffer
 257      (S           : String;
 258       Buffer      : in out String_Access;
 259       Buffer_Last : in out Natural)
 260    is
 261       Last : constant Natural := Buffer_Last + S'Length;
 262 
 263    begin
 264       while Last > Buffer'Last loop
 265          declare
 266             New_Buffer : constant String_Access :=
 267                            new String (1 .. 2 * Buffer'Last);
 268          begin
 269             New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
 270             Free (Buffer);
 271             Buffer := New_Buffer;
 272          end;
 273       end loop;
 274 
 275       Buffer (Buffer_Last + 1 .. Last) := S;
 276       Buffer_Last := Last;
 277    end Add_To_Buffer;
 278 
 279    ------------------------
 280    -- Add_To_Object_Path --
 281    ------------------------
 282 
 283    procedure Add_To_Object_Path
 284      (Object_Dir   : Path_Name_Type;
 285       Object_Paths : in out Object_Path_Table.Instance)
 286    is
 287    begin
 288       --  Check if the directory is already in the table
 289 
 290       for Index in
 291         Object_Path_Table.First .. Object_Path_Table.Last (Object_Paths)
 292       loop
 293          --  If it is, remove it, and add it as the last one
 294 
 295          if Object_Paths.Table (Index) = Object_Dir then
 296             for Index2 in
 297               Index + 1 .. Object_Path_Table.Last (Object_Paths)
 298             loop
 299                Object_Paths.Table (Index2 - 1) := Object_Paths.Table (Index2);
 300             end loop;
 301 
 302             Object_Paths.Table
 303               (Object_Path_Table.Last (Object_Paths)) := Object_Dir;
 304             return;
 305          end if;
 306       end loop;
 307 
 308       --  The directory is not already in the table, add it
 309 
 310       Object_Path_Table.Append (Object_Paths, Object_Dir);
 311    end Add_To_Object_Path;
 312 
 313    -----------------
 314    -- Add_To_Path --
 315    -----------------
 316 
 317    procedure Add_To_Path
 318      (Source_Dirs : String_List_Id;
 319       Shared      : Shared_Project_Tree_Data_Access;
 320       Buffer      : in out String_Access;
 321       Buffer_Last : in out Natural)
 322    is
 323       Current    : String_List_Id;
 324       Source_Dir : String_Element;
 325    begin
 326       Current := Source_Dirs;
 327       while Current /= Nil_String loop
 328          Source_Dir := Shared.String_Elements.Table (Current);
 329          Add_To_Path (Get_Name_String (Source_Dir.Display_Value),
 330                       Buffer, Buffer_Last);
 331          Current := Source_Dir.Next;
 332       end loop;
 333    end Add_To_Path;
 334 
 335    procedure Add_To_Path
 336      (Dir         : String;
 337       Buffer      : in out String_Access;
 338       Buffer_Last : in out Natural)
 339    is
 340       Len        : Natural;
 341       New_Buffer : String_Access;
 342       Min_Len    : Natural;
 343 
 344       function Is_Present (Path : String; Dir : String) return Boolean;
 345       --  Return True if Dir is part of Path
 346 
 347       ----------------
 348       -- Is_Present --
 349       ----------------
 350 
 351       function Is_Present (Path : String; Dir : String) return Boolean is
 352          Last : constant Integer := Path'Last - Dir'Length + 1;
 353 
 354       begin
 355          for J in Path'First .. Last loop
 356 
 357             --  Note: the order of the conditions below is important, since
 358             --  it ensures a minimal number of string comparisons.
 359 
 360             if (J = Path'First or else Path (J - 1) = Path_Separator)
 361               and then
 362                 (J + Dir'Length > Path'Last
 363                   or else Path (J + Dir'Length) = Path_Separator)
 364               and then Dir = Path (J .. J + Dir'Length - 1)
 365             then
 366                return True;
 367             end if;
 368          end loop;
 369 
 370          return False;
 371       end Is_Present;
 372 
 373    --  Start of processing for Add_To_Path
 374 
 375    begin
 376       if Is_Present (Buffer (1 .. Buffer_Last), Dir) then
 377 
 378          --  Dir is already in the path, nothing to do
 379 
 380          return;
 381       end if;
 382 
 383       Min_Len := Buffer_Last + Dir'Length;
 384 
 385       if Buffer_Last > 0 then
 386 
 387          --  Add 1 for the Path_Separator character
 388 
 389          Min_Len := Min_Len + 1;
 390       end if;
 391 
 392       --  If Ada_Path_Buffer is too small, increase it
 393 
 394       Len := Buffer'Last;
 395 
 396       if Len < Min_Len then
 397          loop
 398             Len := Len * 2;
 399             exit when Len >= Min_Len;
 400          end loop;
 401 
 402          New_Buffer := new String (1 .. Len);
 403          New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
 404          Free (Buffer);
 405          Buffer := New_Buffer;
 406       end if;
 407 
 408       if Buffer_Last > 0 then
 409          Buffer_Last := Buffer_Last + 1;
 410          Buffer (Buffer_Last) := Path_Separator;
 411       end if;
 412 
 413       Buffer (Buffer_Last + 1 .. Buffer_Last + Dir'Length) := Dir;
 414       Buffer_Last := Buffer_Last + Dir'Length;
 415    end Add_To_Path;
 416 
 417    ------------------------
 418    -- Add_To_Source_Path --
 419    ------------------------
 420 
 421    procedure Add_To_Source_Path
 422      (Source_Dirs  : String_List_Id;
 423       Shared       : Shared_Project_Tree_Data_Access;
 424       Source_Paths : in out Source_Path_Table.Instance)
 425    is
 426       Current    : String_List_Id;
 427       Source_Dir : String_Element;
 428       Add_It     : Boolean;
 429 
 430    begin
 431       --  Add each source directory
 432 
 433       Current := Source_Dirs;
 434       while Current /= Nil_String loop
 435          Source_Dir := Shared.String_Elements.Table (Current);
 436          Add_It := True;
 437 
 438          --  Check if the source directory is already in the table
 439 
 440          for Index in
 441            Source_Path_Table.First .. Source_Path_Table.Last (Source_Paths)
 442          loop
 443             --  If it is already, no need to add it
 444 
 445             if Source_Paths.Table (Index) = Source_Dir.Value then
 446                Add_It := False;
 447                exit;
 448             end if;
 449          end loop;
 450 
 451          if Add_It then
 452             Source_Path_Table.Append (Source_Paths, Source_Dir.Display_Value);
 453          end if;
 454 
 455          --  Next source directory
 456 
 457          Current := Source_Dir.Next;
 458       end loop;
 459    end Add_To_Source_Path;
 460 
 461    --------------------------------
 462    -- Create_Config_Pragmas_File --
 463    --------------------------------
 464 
 465    procedure Create_Config_Pragmas_File
 466      (For_Project : Project_Id;
 467       In_Tree     : Project_Tree_Ref)
 468    is
 469       type Naming_Id is new Nat;
 470       package Naming_Table is new GNAT.Dynamic_Tables
 471         (Table_Component_Type => Lang_Naming_Data,
 472          Table_Index_Type     => Naming_Id,
 473          Table_Low_Bound      => 1,
 474          Table_Initial        => 5,
 475          Table_Increment      => 100);
 476 
 477       Default_Naming : constant Naming_Id := Naming_Table.First;
 478       Namings        : Naming_Table.Instance;
 479       --  Table storing the naming data for gnatmake/gprmake
 480 
 481       Buffer      : String_Access := new String (1 .. Buffer_Initial);
 482       Buffer_Last : Natural := 0;
 483 
 484       File_Name : Path_Name_Type  := No_Path;
 485       File      : File_Descriptor := Invalid_FD;
 486 
 487       Current_Naming : Naming_Id;
 488 
 489       procedure Check
 490         (Project : Project_Id;
 491          In_Tree : Project_Tree_Ref;
 492          State   : in out Integer);
 493       --  Recursive procedure that put in the config pragmas file any non
 494       --  standard naming schemes, if it is not already in the file, then call
 495       --  itself for any imported project.
 496 
 497       procedure Put (Source : Source_Id);
 498       --  Put an SFN pragma in the temporary file
 499 
 500       procedure Put (S : String);
 501       procedure Put_Line (S : String);
 502       --  Output procedures, analogous to normal Text_IO procs of same name.
 503       --  The text is put in Buffer, then it will be written into a temporary
 504       --  file with procedure Write_Temp_File below.
 505 
 506       procedure Write_Temp_File;
 507       --  Create a temporary file and put the content of the buffer in it
 508 
 509       -----------
 510       -- Check --
 511       -----------
 512 
 513       procedure Check
 514         (Project : Project_Id;
 515          In_Tree : Project_Tree_Ref;
 516          State   : in out Integer)
 517       is
 518          pragma Unreferenced (State);
 519 
 520          Lang   : constant Language_Ptr :=
 521                     Get_Language_From_Name (Project, "ada");
 522          Naming : Lang_Naming_Data;
 523          Iter   : Source_Iterator;
 524          Source : Source_Id;
 525 
 526       begin
 527          if Current_Verbosity = High then
 528             Debug_Output ("Checking project file:", Project.Name);
 529          end if;
 530 
 531          if Lang = null then
 532             if Current_Verbosity = High then
 533                Debug_Output ("Languages does not contain Ada, nothing to do");
 534             end if;
 535 
 536             return;
 537          end if;
 538 
 539          --  Visit all the files and process those that need an SFN pragma
 540 
 541          Iter := For_Each_Source (In_Tree, Project);
 542          while Element (Iter) /= No_Source loop
 543             Source := Element (Iter);
 544 
 545             if not Source.Locally_Removed
 546               and then Source.Unit /= null
 547               and then
 548                 (Source.Index >= 1 or else Source.Naming_Exception /= No)
 549             then
 550                Put (Source);
 551             end if;
 552 
 553             Next (Iter);
 554          end loop;
 555 
 556          Naming := Lang.Config.Naming_Data;
 557 
 558          --  Is the naming scheme of this project one that we know?
 559 
 560          Current_Naming := Default_Naming;
 561          while Current_Naming <= Naming_Table.Last (Namings)
 562            and then Namings.Table (Current_Naming).Dot_Replacement =
 563                                                     Naming.Dot_Replacement
 564            and then Namings.Table (Current_Naming).Casing =
 565                                                     Naming.Casing
 566            and then Namings.Table (Current_Naming).Separate_Suffix =
 567                                                     Naming.Separate_Suffix
 568          loop
 569             Current_Naming := Current_Naming + 1;
 570          end loop;
 571 
 572          --  If we don't know it, add it
 573 
 574          if Current_Naming > Naming_Table.Last (Namings) then
 575             Naming_Table.Increment_Last (Namings);
 576             Namings.Table (Naming_Table.Last (Namings)) := Naming;
 577 
 578             --  Put the SFN pragmas for the naming scheme
 579 
 580             --  Spec
 581 
 582             Put_Line
 583               ("pragma Source_File_Name_Project");
 584             Put_Line
 585               ("  (Spec_File_Name  => ""*" &
 586                Get_Name_String (Naming.Spec_Suffix) & """,");
 587             Put_Line
 588               ("   Casing          => " &
 589                Image (Naming.Casing) & ",");
 590             Put_Line
 591               ("   Dot_Replacement => """ &
 592                Get_Name_String (Naming.Dot_Replacement) & """);");
 593 
 594             --  and body
 595 
 596             Put_Line
 597               ("pragma Source_File_Name_Project");
 598             Put_Line
 599               ("  (Body_File_Name  => ""*" &
 600                Get_Name_String (Naming.Body_Suffix) & """,");
 601             Put_Line
 602               ("   Casing          => " &
 603                Image (Naming.Casing) & ",");
 604             Put_Line
 605               ("   Dot_Replacement => """ &
 606                Get_Name_String (Naming.Dot_Replacement) &
 607                """);");
 608 
 609             --  and maybe separate
 610 
 611             if Naming.Body_Suffix /= Naming.Separate_Suffix then
 612                Put_Line ("pragma Source_File_Name_Project");
 613                Put_Line
 614                  ("  (Subunit_File_Name  => ""*" &
 615                   Get_Name_String (Naming.Separate_Suffix) & """,");
 616                Put_Line
 617                  ("   Casing          => " &
 618                   Image (Naming.Casing) & ",");
 619                Put_Line
 620                  ("   Dot_Replacement => """ &
 621                   Get_Name_String (Naming.Dot_Replacement) &
 622                   """);");
 623             end if;
 624          end if;
 625       end Check;
 626 
 627       ---------
 628       -- Put --
 629       ---------
 630 
 631       procedure Put (Source : Source_Id) is
 632       begin
 633          --  Put the pragma SFN for the unit kind (spec or body)
 634 
 635          Put ("pragma Source_File_Name_Project (");
 636          Put (Namet.Get_Name_String (Source.Unit.Name));
 637 
 638          if Source.Kind = Spec then
 639             Put (", Spec_File_Name => """);
 640          else
 641             Put (", Body_File_Name => """);
 642          end if;
 643 
 644          Put (Namet.Get_Name_String (Source.File));
 645          Put ("""");
 646 
 647          if Source.Index /= 0 then
 648             Put (", Index =>");
 649             Put (Source.Index'Img);
 650          end if;
 651 
 652          Put_Line (");");
 653       end Put;
 654 
 655       procedure Put (S : String) is
 656       begin
 657          Add_To_Buffer (S, Buffer, Buffer_Last);
 658 
 659          if Current_Verbosity = High then
 660             Write_Str (S);
 661          end if;
 662       end Put;
 663 
 664       --------------
 665       -- Put_Line --
 666       --------------
 667 
 668       procedure Put_Line (S : String) is
 669       begin
 670          --  Add an ASCII.LF to the string. As this config file is supposed to
 671          --  be used only by the compiler, we don't care about the characters
 672          --  for the end of line. In fact we could have put a space, but
 673          --  it is more convenient to be able to read gnat.adc during
 674          --  development, for which the ASCII.LF is fine.
 675 
 676          Put (S);
 677          Put (S => (1 => ASCII.LF));
 678       end Put_Line;
 679 
 680       ---------------------
 681       -- Write_Temp_File --
 682       ---------------------
 683 
 684       procedure Write_Temp_File is
 685          Status : Boolean := False;
 686          Last   : Natural;
 687 
 688       begin
 689          Tempdir.Create_Temp_File (File, File_Name);
 690 
 691          if File /= Invalid_FD then
 692             Last := Write (File, Buffer (1)'Address, Buffer_Last);
 693 
 694             if Last = Buffer_Last then
 695                Close (File, Status);
 696             end if;
 697          end if;
 698 
 699          if not Status then
 700             Prj.Com.Fail ("unable to create temporary file");
 701          end if;
 702       end Write_Temp_File;
 703 
 704       procedure Check_Imported_Projects is
 705         new For_Every_Project_Imported (Integer, Check);
 706 
 707       Dummy : Integer := 0;
 708 
 709    --  Start of processing for Create_Config_Pragmas_File
 710 
 711    begin
 712       if not For_Project.Config_Checked then
 713          Naming_Table.Init (Namings);
 714 
 715          --  Check the naming schemes
 716 
 717          Check_Imported_Projects
 718            (For_Project, In_Tree, Dummy, Imported_First => False);
 719 
 720          --  If there are no non standard naming scheme, issue the GNAT
 721          --  standard naming scheme. This will tell the compiler that
 722          --  a project file is used and will forbid any pragma SFN.
 723 
 724          if Buffer_Last = 0 then
 725 
 726             Put_Line ("pragma Source_File_Name_Project");
 727             Put_Line ("   (Spec_File_Name  => ""*.ads"",");
 728             Put_Line ("    Dot_Replacement => ""-"",");
 729             Put_Line ("    Casing          => lowercase);");
 730 
 731             Put_Line ("pragma Source_File_Name_Project");
 732             Put_Line ("   (Body_File_Name  => ""*.adb"",");
 733             Put_Line ("    Dot_Replacement => ""-"",");
 734             Put_Line ("    Casing          => lowercase);");
 735          end if;
 736 
 737          --  Close the temporary file
 738 
 739          Write_Temp_File;
 740 
 741          if Opt.Verbose_Mode then
 742             Write_Str ("Created configuration file """);
 743             Write_Str (Get_Name_String (File_Name));
 744             Write_Line ("""");
 745          end if;
 746 
 747          For_Project.Config_File_Name := File_Name;
 748          For_Project.Config_File_Temp := True;
 749          For_Project.Config_Checked   := True;
 750       end if;
 751 
 752       Free (Buffer);
 753    end Create_Config_Pragmas_File;
 754 
 755    --------------------
 756    -- Create_Mapping --
 757    --------------------
 758 
 759    procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
 760       Data : Source_Id;
 761       Iter : Source_Iterator;
 762 
 763    begin
 764       Fmap.Reset_Tables;
 765 
 766       Iter := For_Each_Source (In_Tree);
 767       loop
 768          Data := Element (Iter);
 769          exit when Data = No_Source;
 770 
 771          if Data.Unit /= No_Unit_Index then
 772             if Data.Locally_Removed and then not Data.Suppressed then
 773                Fmap.Add_Forbidden_File_Name (Data.File);
 774             else
 775                Fmap.Add_To_File_Map
 776                  (Unit_Name => Unit_Name_Type (Data.Unit.Name),
 777                   File_Name => Data.File,
 778                   Path_Name => File_Name_Type (Data.Path.Display_Name));
 779             end if;
 780          end if;
 781 
 782          Next (Iter);
 783       end loop;
 784    end Create_Mapping;
 785 
 786    -------------------------
 787    -- Create_Mapping_File --
 788    -------------------------
 789 
 790    procedure Create_Mapping_File
 791      (Project  : Project_Id;
 792       Language : Name_Id;
 793       In_Tree  : Project_Tree_Ref;
 794       Name     : out Path_Name_Type)
 795    is
 796       File        : File_Descriptor := Invalid_FD;
 797       Buffer      : String_Access   := new String (1 .. Buffer_Initial);
 798       Buffer_Last : Natural         := 0;
 799 
 800       procedure Put_Name_Buffer;
 801       --  Put the line contained in the Name_Buffer in the global buffer
 802 
 803       procedure Process
 804         (Project : Project_Id;
 805          In_Tree : Project_Tree_Ref;
 806          State   : in out Integer);
 807       --  Generate the mapping file for Project (not recursively)
 808 
 809       ---------------------
 810       -- Put_Name_Buffer --
 811       ---------------------
 812 
 813       procedure Put_Name_Buffer is
 814       begin
 815          if Current_Verbosity = High then
 816             Debug_Output (Name_Buffer (1 .. Name_Len));
 817          end if;
 818 
 819          Name_Len := Name_Len + 1;
 820          Name_Buffer (Name_Len) := ASCII.LF;
 821          Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
 822       end Put_Name_Buffer;
 823 
 824       -------------
 825       -- Process --
 826       -------------
 827 
 828       procedure Process
 829         (Project : Project_Id;
 830          In_Tree : Project_Tree_Ref;
 831          State   : in out Integer)
 832       is
 833          pragma Unreferenced (State);
 834 
 835          Source : Source_Id;
 836          Suffix : File_Name_Type;
 837          Iter   : Source_Iterator;
 838 
 839       begin
 840          Debug_Output ("Add mapping for project", Project.Name);
 841          Iter := For_Each_Source (In_Tree, Project, Language => Language);
 842 
 843          loop
 844             Source := Prj.Element (Iter);
 845             exit when Source = No_Source;
 846 
 847             if not Source.Suppressed
 848               and then Source.Replaced_By = No_Source
 849               and then Source.Path.Name /= No_Path
 850               and then (Source.Language.Config.Kind = File_Based
 851                          or else Source.Unit /= No_Unit_Index)
 852             then
 853                if Source.Unit /= No_Unit_Index then
 854 
 855                   --  Put the encoded unit name in the name buffer
 856 
 857                   declare
 858                      Uname : constant String :=
 859                                Get_Name_String (Source.Unit.Name);
 860 
 861                   begin
 862                      Name_Len := 0;
 863                      for J in Uname'Range loop
 864                         if Uname (J) in Upper_Half_Character then
 865                            Store_Encoded_Character (Get_Char_Code (Uname (J)));
 866                         else
 867                            Add_Char_To_Name_Buffer (Uname (J));
 868                         end if;
 869                      end loop;
 870                   end;
 871 
 872                   if Source.Language.Config.Kind = Unit_Based then
 873 
 874                      --  ??? Mapping_Spec_Suffix could be set in the case of
 875                      --  gnatmake as well
 876 
 877                      Add_Char_To_Name_Buffer ('%');
 878 
 879                      if Source.Kind = Spec then
 880                         Add_Char_To_Name_Buffer ('s');
 881                      else
 882                         Add_Char_To_Name_Buffer ('b');
 883                      end if;
 884 
 885                   else
 886                      case Source.Kind is
 887                         when Spec =>
 888                            Suffix :=
 889                              Source.Language.Config.Mapping_Spec_Suffix;
 890                         when Impl | Sep =>
 891                            Suffix :=
 892                              Source.Language.Config.Mapping_Body_Suffix;
 893                      end case;
 894 
 895                      if Suffix /= No_File then
 896                         Add_Str_To_Name_Buffer (Get_Name_String (Suffix));
 897                      end if;
 898                   end if;
 899 
 900                   Put_Name_Buffer;
 901                end if;
 902 
 903                Get_Name_String (Source.Display_File);
 904                Put_Name_Buffer;
 905 
 906                if Source.Locally_Removed then
 907                   Name_Len := 1;
 908                   Name_Buffer (1) := '/';
 909                else
 910                   Get_Name_String (Source.Path.Display_Name);
 911                end if;
 912 
 913                Put_Name_Buffer;
 914             end if;
 915 
 916             Next (Iter);
 917          end loop;
 918       end Process;
 919 
 920       procedure For_Every_Imported_Project is new
 921         For_Every_Project_Imported (State => Integer, Action => Process);
 922 
 923       --  Local variables
 924 
 925       Dummy : Integer := 0;
 926 
 927    --  Start of processing for Create_Mapping_File
 928 
 929    begin
 930       if Current_Verbosity = High then
 931          Debug_Output ("Create mapping file for", Debug_Name (In_Tree));
 932       end if;
 933 
 934       Create_Temp_File (In_Tree.Shared, File, Name, "mapping");
 935 
 936       if Current_Verbosity = High then
 937          Debug_Increase_Indent ("Create mapping file ", Name_Id (Name));
 938       end if;
 939 
 940       For_Every_Imported_Project
 941         (Project, In_Tree, Dummy, Include_Aggregated => False);
 942 
 943       declare
 944          Last   : Natural;
 945          Status : Boolean := False;
 946 
 947       begin
 948          if File /= Invalid_FD then
 949             Last := Write (File, Buffer (1)'Address, Buffer_Last);
 950 
 951             if Last = Buffer_Last then
 952                GNAT.OS_Lib.Close (File, Status);
 953             end if;
 954          end if;
 955 
 956          if not Status then
 957             Prj.Com.Fail ("could not write mapping file");
 958          end if;
 959       end;
 960 
 961       Free (Buffer);
 962 
 963       Debug_Decrease_Indent ("Done create mapping file");
 964    end Create_Mapping_File;
 965 
 966    ----------------------
 967    -- Create_Temp_File --
 968    ----------------------
 969 
 970    procedure Create_Temp_File
 971      (Shared    : Shared_Project_Tree_Data_Access;
 972       Path_FD   : out File_Descriptor;
 973       Path_Name : out Path_Name_Type;
 974       File_Use  : String)
 975    is
 976    begin
 977       Tempdir.Create_Temp_File (Path_FD, Path_Name);
 978 
 979       if Path_Name /= No_Path then
 980          if Current_Verbosity = High then
 981             Write_Line ("Create temp file (" & File_Use & ") "
 982                         & Get_Name_String (Path_Name));
 983          end if;
 984 
 985          Record_Temp_File (Shared, Path_Name);
 986 
 987       else
 988          Prj.Com.Fail
 989            ("unable to create temporary " & File_Use & " file");
 990       end if;
 991    end Create_Temp_File;
 992 
 993    --------------------------
 994    -- Create_New_Path_File --
 995    --------------------------
 996 
 997    procedure Create_New_Path_File
 998      (Shared    : Shared_Project_Tree_Data_Access;
 999       Path_FD   : out File_Descriptor;
1000       Path_Name : out Path_Name_Type)
1001    is
1002    begin
1003       Create_Temp_File (Shared, Path_FD, Path_Name, "path file");
1004    end Create_New_Path_File;
1005 
1006    ------------------------------------
1007    -- File_Name_Of_Library_Unit_Body --
1008    ------------------------------------
1009 
1010    function File_Name_Of_Library_Unit_Body
1011      (Name              : String;
1012       Project           : Project_Id;
1013       In_Tree           : Project_Tree_Ref;
1014       Main_Project_Only : Boolean := True;
1015       Full_Path         : Boolean := False) return String
1016    is
1017 
1018       Lang          : constant Language_Ptr :=
1019                         Get_Language_From_Name (Project, "ada");
1020       The_Project   : Project_Id := Project;
1021       Original_Name : String := Name;
1022 
1023       Unit              : Unit_Index;
1024       The_Original_Name : Name_Id;
1025       The_Spec_Name     : Name_Id;
1026       The_Body_Name     : Name_Id;
1027 
1028    begin
1029       --  ??? Same block in Project_Of
1030       Canonical_Case_File_Name (Original_Name);
1031       Name_Len := Original_Name'Length;
1032       Name_Buffer (1 .. Name_Len) := Original_Name;
1033       The_Original_Name := Name_Find;
1034 
1035       if Lang /= null then
1036          declare
1037             Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
1038             Extended_Spec_Name : String :=
1039                                    Name & Namet.Get_Name_String
1040                                             (Naming.Spec_Suffix);
1041             Extended_Body_Name : String :=
1042                                    Name & Namet.Get_Name_String
1043                                             (Naming.Body_Suffix);
1044 
1045          begin
1046             Canonical_Case_File_Name (Extended_Spec_Name);
1047             Name_Len := Extended_Spec_Name'Length;
1048             Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1049             The_Spec_Name := Name_Find;
1050 
1051             Canonical_Case_File_Name (Extended_Body_Name);
1052             Name_Len := Extended_Body_Name'Length;
1053             Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1054             The_Body_Name := Name_Find;
1055          end;
1056 
1057       else
1058          Name_Len := Name'Length;
1059          Name_Buffer (1 .. Name_Len) := Name;
1060          Canonical_Case_File_Name (Name_Buffer);
1061          The_Spec_Name := Name_Find;
1062          The_Body_Name := The_Spec_Name;
1063       end if;
1064 
1065       if Current_Verbosity = High then
1066          Write_Str  ("Looking for file name of """);
1067          Write_Str  (Name);
1068          Write_Char ('"');
1069          Write_Eol;
1070          Write_Str  ("   Extended Spec Name = """);
1071          Write_Str  (Get_Name_String (The_Spec_Name));
1072          Write_Char ('"');
1073          Write_Eol;
1074          Write_Str  ("   Extended Body Name = """);
1075          Write_Str  (Get_Name_String (The_Body_Name));
1076          Write_Char ('"');
1077          Write_Eol;
1078       end if;
1079 
1080       --  For extending project, search in the extended project if the source
1081       --  is not found. For non extending projects, this loop will be run only
1082       --  once.
1083 
1084       loop
1085          --  Loop through units
1086 
1087          Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1088          while Unit /= null loop
1089 
1090             --  Check for body
1091 
1092             if not Main_Project_Only
1093               or else
1094                 (Unit.File_Names (Impl) /= null
1095                   and then Unit.File_Names (Impl).Project = The_Project)
1096             then
1097                declare
1098                   Current_Name : File_Name_Type;
1099 
1100                begin
1101                   --  Case of a body present
1102 
1103                   if Unit.File_Names (Impl) /= null then
1104                      Current_Name := Unit.File_Names (Impl).File;
1105 
1106                      if Current_Verbosity = High then
1107                         Write_Str  ("   Comparing with """);
1108                         Write_Str  (Get_Name_String (Current_Name));
1109                         Write_Char ('"');
1110                         Write_Eol;
1111                      end if;
1112 
1113                      --  If it has the name of the original name, return the
1114                      --  original name.
1115 
1116                      if Unit.Name = The_Original_Name
1117                        or else
1118                          Current_Name = File_Name_Type (The_Original_Name)
1119                      then
1120                         if Current_Verbosity = High then
1121                            Write_Line ("   OK");
1122                         end if;
1123 
1124                         if Full_Path then
1125                            return Get_Name_String
1126                              (Unit.File_Names (Impl).Path.Name);
1127 
1128                         else
1129                            return Get_Name_String (Current_Name);
1130                         end if;
1131 
1132                         --  If it has the name of the extended body name,
1133                         --  return the extended body name
1134 
1135                      elsif Current_Name = File_Name_Type (The_Body_Name) then
1136                         if Current_Verbosity = High then
1137                            Write_Line ("   OK");
1138                         end if;
1139 
1140                         if Full_Path then
1141                            return Get_Name_String
1142                              (Unit.File_Names (Impl).Path.Name);
1143 
1144                         else
1145                            return Get_Name_String (The_Body_Name);
1146                         end if;
1147 
1148                      else
1149                         if Current_Verbosity = High then
1150                            Write_Line ("   not good");
1151                         end if;
1152                      end if;
1153                   end if;
1154                end;
1155             end if;
1156 
1157             --  Check for spec
1158 
1159             if not Main_Project_Only
1160               or else (Unit.File_Names (Spec) /= null
1161                         and then Unit.File_Names (Spec).Project = The_Project)
1162             then
1163                declare
1164                   Current_Name : File_Name_Type;
1165 
1166                begin
1167                   --  Case of spec present
1168 
1169                   if Unit.File_Names (Spec) /= null then
1170                      Current_Name := Unit.File_Names (Spec).File;
1171                      if Current_Verbosity = High then
1172                         Write_Str  ("   Comparing with """);
1173                         Write_Str  (Get_Name_String (Current_Name));
1174                         Write_Char ('"');
1175                         Write_Eol;
1176                      end if;
1177 
1178                      --  If name same as original name, return original name
1179 
1180                      if Unit.Name = The_Original_Name
1181                        or else
1182                          Current_Name = File_Name_Type (The_Original_Name)
1183                      then
1184                         if Current_Verbosity = High then
1185                            Write_Line ("   OK");
1186                         end if;
1187 
1188                         if Full_Path then
1189                            return Get_Name_String
1190                              (Unit.File_Names (Spec).Path.Name);
1191                         else
1192                            return Get_Name_String (Current_Name);
1193                         end if;
1194 
1195                         --  If it has the same name as the extended spec name,
1196                         --  return the extended spec name.
1197 
1198                      elsif Current_Name = File_Name_Type (The_Spec_Name) then
1199                         if Current_Verbosity = High then
1200                            Write_Line ("   OK");
1201                         end if;
1202 
1203                         if Full_Path then
1204                            return Get_Name_String
1205                              (Unit.File_Names (Spec).Path.Name);
1206                         else
1207                            return Get_Name_String (The_Spec_Name);
1208                         end if;
1209 
1210                      else
1211                         if Current_Verbosity = High then
1212                            Write_Line ("   not good");
1213                         end if;
1214                      end if;
1215                   end if;
1216                end;
1217             end if;
1218 
1219             Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1220          end loop;
1221 
1222          --  If we are not in an extending project, give up
1223 
1224          exit when not Main_Project_Only
1225            or else The_Project.Extends = No_Project;
1226 
1227          --  Otherwise, look in the project we are extending
1228 
1229          The_Project := The_Project.Extends;
1230       end loop;
1231 
1232       --  We don't know this file name, return an empty string
1233 
1234       return "";
1235    end File_Name_Of_Library_Unit_Body;
1236 
1237    -------------------------
1238    -- For_All_Object_Dirs --
1239    -------------------------
1240 
1241    procedure For_All_Object_Dirs
1242      (Project : Project_Id;
1243       Tree    : Project_Tree_Ref)
1244    is
1245       procedure For_Project
1246         (Prj   : Project_Id;
1247          Tree  : Project_Tree_Ref;
1248          Dummy : in out Integer);
1249       --  Get all object directories of Prj
1250 
1251       -----------------
1252       -- For_Project --
1253       -----------------
1254 
1255       procedure For_Project
1256         (Prj   : Project_Id;
1257          Tree  : Project_Tree_Ref;
1258          Dummy : in out Integer)
1259       is
1260          pragma Unreferenced (Tree);
1261 
1262       begin
1263          --  ??? Set_Ada_Paths has a different behavior for library project
1264          --  files, should we have the same ?
1265 
1266          if Prj.Object_Directory /= No_Path_Information then
1267             Get_Name_String (Prj.Object_Directory.Display_Name);
1268             Action (Name_Buffer (1 .. Name_Len));
1269          end if;
1270       end For_Project;
1271 
1272       procedure Get_Object_Dirs is
1273         new For_Every_Project_Imported (Integer, For_Project);
1274       Dummy : Integer := 1;
1275 
1276    --  Start of processing for For_All_Object_Dirs
1277 
1278    begin
1279       Get_Object_Dirs (Project, Tree, Dummy);
1280    end For_All_Object_Dirs;
1281 
1282    -------------------------
1283    -- For_All_Source_Dirs --
1284    -------------------------
1285 
1286    procedure For_All_Source_Dirs
1287      (Project : Project_Id;
1288       In_Tree : Project_Tree_Ref)
1289    is
1290       procedure For_Project
1291         (Prj     : Project_Id;
1292          In_Tree : Project_Tree_Ref;
1293          Dummy   : in out Integer);
1294       --  Get all object directories of Prj
1295 
1296       -----------------
1297       -- For_Project --
1298       -----------------
1299 
1300       procedure For_Project
1301         (Prj     : Project_Id;
1302          In_Tree : Project_Tree_Ref;
1303          Dummy   : in out Integer)
1304       is
1305          Current    : String_List_Id := Prj.Source_Dirs;
1306          The_String : String_Element;
1307 
1308       begin
1309          --  If there are Ada sources, call action with the name of every
1310          --  source directory.
1311 
1312          if Has_Ada_Sources (Prj) then
1313             while Current /= Nil_String loop
1314                The_String := In_Tree.Shared.String_Elements.Table (Current);
1315                Action (Get_Name_String (The_String.Display_Value));
1316                Current := The_String.Next;
1317             end loop;
1318          end if;
1319       end For_Project;
1320 
1321       procedure Get_Source_Dirs is
1322         new For_Every_Project_Imported (Integer, For_Project);
1323       Dummy : Integer := 1;
1324 
1325    --  Start of processing for For_All_Source_Dirs
1326 
1327    begin
1328       Get_Source_Dirs (Project, In_Tree, Dummy);
1329    end For_All_Source_Dirs;
1330 
1331    -------------------
1332    -- Get_Reference --
1333    -------------------
1334 
1335    procedure Get_Reference
1336      (Source_File_Name : String;
1337       In_Tree          : Project_Tree_Ref;
1338       Project          : out Project_Id;
1339       Path             : out Path_Name_Type)
1340    is
1341    begin
1342       --  Body below could use some comments ???
1343 
1344       if Current_Verbosity > Default then
1345          Write_Str ("Getting Reference_Of (""");
1346          Write_Str (Source_File_Name);
1347          Write_Str (""") ... ");
1348       end if;
1349 
1350       declare
1351          Original_Name : String := Source_File_Name;
1352          Unit          : Unit_Index;
1353 
1354       begin
1355          Canonical_Case_File_Name (Original_Name);
1356          Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1357 
1358          while Unit /= null loop
1359             if Unit.File_Names (Spec) /= null
1360               and then not Unit.File_Names (Spec).Locally_Removed
1361               and then Unit.File_Names (Spec).File /= No_File
1362               and then
1363                 (Namet.Get_Name_String
1364                    (Unit.File_Names (Spec).File) = Original_Name
1365                  or else (Unit.File_Names (Spec).Path /= No_Path_Information
1366                            and then
1367                              Namet.Get_Name_String
1368                                (Unit.File_Names (Spec).Path.Name) =
1369                                                            Original_Name))
1370             then
1371                Project :=
1372                  Ultimate_Extending_Project_Of
1373                    (Unit.File_Names (Spec).Project);
1374                Path := Unit.File_Names (Spec).Path.Display_Name;
1375 
1376                if Current_Verbosity > Default then
1377                   Write_Str ("Done: Spec.");
1378                   Write_Eol;
1379                end if;
1380 
1381                return;
1382 
1383             elsif Unit.File_Names (Impl) /= null
1384               and then Unit.File_Names (Impl).File /= No_File
1385               and then not Unit.File_Names (Impl).Locally_Removed
1386               and then
1387                 (Namet.Get_Name_String
1388                    (Unit.File_Names (Impl).File) = Original_Name
1389                   or else (Unit.File_Names (Impl).Path /= No_Path_Information
1390                             and then Namet.Get_Name_String
1391                                        (Unit.File_Names (Impl).Path.Name) =
1392                                                               Original_Name))
1393             then
1394                Project :=
1395                  Ultimate_Extending_Project_Of
1396                    (Unit.File_Names (Impl).Project);
1397                Path := Unit.File_Names (Impl).Path.Display_Name;
1398 
1399                if Current_Verbosity > Default then
1400                   Write_Str ("Done: Body.");
1401                   Write_Eol;
1402                end if;
1403 
1404                return;
1405             end if;
1406 
1407             Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1408          end loop;
1409       end;
1410 
1411       Project := No_Project;
1412       Path    := No_Path;
1413 
1414       if Current_Verbosity > Default then
1415          Write_Str ("Cannot be found.");
1416          Write_Eol;
1417       end if;
1418    end Get_Reference;
1419 
1420    ----------------------
1421    -- Get_Runtime_Path --
1422    ----------------------
1423 
1424    function Get_Runtime_Path
1425      (Self : Project_Search_Path;
1426       Name : String) return String_Access
1427    is
1428       function Find_Rts_In_Path is
1429         new Prj.Env.Find_Name_In_Path (Check_Filename => Is_Directory);
1430    begin
1431       return Find_Rts_In_Path (Self, Name);
1432    end Get_Runtime_Path;
1433 
1434    ----------------
1435    -- Initialize --
1436    ----------------
1437 
1438    procedure Initialize (In_Tree : Project_Tree_Ref) is
1439    begin
1440       In_Tree.Shared.Private_Part.Current_Source_Path_File := No_Path;
1441       In_Tree.Shared.Private_Part.Current_Object_Path_File := No_Path;
1442    end Initialize;
1443 
1444    -------------------
1445    -- Print_Sources --
1446    -------------------
1447 
1448    --  Could use some comments in this body ???
1449 
1450    procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1451       Unit : Unit_Index;
1452 
1453    begin
1454       Write_Line ("List of Sources:");
1455 
1456       Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1457       while Unit /= No_Unit_Index loop
1458          Write_Str  ("   ");
1459          Write_Line (Namet.Get_Name_String (Unit.Name));
1460 
1461          if Unit.File_Names (Spec).File /= No_File then
1462             if Unit.File_Names (Spec).Project = No_Project then
1463                Write_Line ("   No project");
1464 
1465             else
1466                Write_Str  ("   Project: ");
1467                Get_Name_String
1468                  (Unit.File_Names (Spec).Project.Path.Name);
1469                Write_Line (Name_Buffer (1 .. Name_Len));
1470             end if;
1471 
1472             Write_Str  ("      spec: ");
1473             Write_Line
1474               (Namet.Get_Name_String
1475                (Unit.File_Names (Spec).File));
1476          end if;
1477 
1478          if Unit.File_Names (Impl).File /= No_File then
1479             if Unit.File_Names (Impl).Project = No_Project then
1480                Write_Line ("   No project");
1481 
1482             else
1483                Write_Str  ("   Project: ");
1484                Get_Name_String
1485                  (Unit.File_Names (Impl).Project.Path.Name);
1486                Write_Line (Name_Buffer (1 .. Name_Len));
1487             end if;
1488 
1489             Write_Str  ("      body: ");
1490             Write_Line
1491               (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1492          end if;
1493 
1494          Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1495       end loop;
1496 
1497       Write_Line ("end of List of Sources.");
1498    end Print_Sources;
1499 
1500    ----------------
1501    -- Project_Of --
1502    ----------------
1503 
1504    function Project_Of
1505      (Name         : String;
1506       Main_Project : Project_Id;
1507       In_Tree      : Project_Tree_Ref) return Project_Id
1508    is
1509       Result : Project_Id := No_Project;
1510 
1511       Original_Name : String := Name;
1512 
1513       Lang : constant Language_Ptr :=
1514                Get_Language_From_Name (Main_Project, "ada");
1515 
1516       Unit : Unit_Index;
1517 
1518       Current_Name      : File_Name_Type;
1519       The_Original_Name : File_Name_Type;
1520       The_Spec_Name     : File_Name_Type;
1521       The_Body_Name     : File_Name_Type;
1522 
1523    begin
1524       --  ??? Same block in File_Name_Of_Library_Unit_Body
1525       Canonical_Case_File_Name (Original_Name);
1526       Name_Len := Original_Name'Length;
1527       Name_Buffer (1 .. Name_Len) := Original_Name;
1528       The_Original_Name := Name_Find;
1529 
1530       if Lang /= null then
1531          declare
1532             Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1533             Extended_Spec_Name : String :=
1534                                    Name & Namet.Get_Name_String
1535                                             (Naming.Spec_Suffix);
1536             Extended_Body_Name : String :=
1537                                    Name & Namet.Get_Name_String
1538                                             (Naming.Body_Suffix);
1539 
1540          begin
1541             Canonical_Case_File_Name (Extended_Spec_Name);
1542             Name_Len := Extended_Spec_Name'Length;
1543             Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1544             The_Spec_Name := Name_Find;
1545 
1546             Canonical_Case_File_Name (Extended_Body_Name);
1547             Name_Len := Extended_Body_Name'Length;
1548             Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1549             The_Body_Name := Name_Find;
1550          end;
1551 
1552       else
1553          The_Spec_Name := The_Original_Name;
1554          The_Body_Name := The_Original_Name;
1555       end if;
1556 
1557       Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1558       while Unit /= null loop
1559 
1560          --  Case of a body present
1561 
1562          if Unit.File_Names (Impl) /= null then
1563             Current_Name := Unit.File_Names (Impl).File;
1564 
1565             --  If it has the name of the original name or the body name,
1566             --  we have found the project.
1567 
1568             if Unit.Name = Name_Id (The_Original_Name)
1569               or else Current_Name = The_Original_Name
1570               or else Current_Name = The_Body_Name
1571             then
1572                Result := Unit.File_Names (Impl).Project;
1573                exit;
1574             end if;
1575          end if;
1576 
1577          --  Check for spec
1578 
1579          if Unit.File_Names (Spec) /= null then
1580             Current_Name := Unit.File_Names (Spec).File;
1581 
1582             --  If name same as the original name, or the spec name, we have
1583             --  found the project.
1584 
1585             if Unit.Name = Name_Id (The_Original_Name)
1586               or else Current_Name = The_Original_Name
1587               or else Current_Name = The_Spec_Name
1588             then
1589                Result := Unit.File_Names (Spec).Project;
1590                exit;
1591             end if;
1592          end if;
1593 
1594          Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1595       end loop;
1596 
1597       return Ultimate_Extending_Project_Of (Result);
1598    end Project_Of;
1599 
1600    -------------------
1601    -- Set_Ada_Paths --
1602    -------------------
1603 
1604    procedure Set_Ada_Paths
1605      (Project             : Project_Id;
1606       In_Tree             : Project_Tree_Ref;
1607       Including_Libraries : Boolean;
1608       Include_Path        : Boolean := True;
1609       Objects_Path        : Boolean := True)
1610 
1611    is
1612       Shared : constant Shared_Project_Tree_Data_Access := In_Tree.Shared;
1613 
1614       Source_Paths : Source_Path_Table.Instance;
1615       Object_Paths : Object_Path_Table.Instance;
1616       --  List of source or object dirs. Only computed the first time this
1617       --  procedure is called (since Source_FD is then reused)
1618 
1619       Source_FD : File_Descriptor := Invalid_FD;
1620       Object_FD : File_Descriptor := Invalid_FD;
1621       --  The temporary files to store the paths. These are only created the
1622       --  first time this procedure is called, and reused from then on.
1623 
1624       Process_Source_Dirs : Boolean := False;
1625       Process_Object_Dirs : Boolean := False;
1626 
1627       Status : Boolean;
1628       --  For calls to Close
1629 
1630       Last        : Natural;
1631       Buffer      : String_Access := new String (1 .. Buffer_Initial);
1632       Buffer_Last : Natural := 0;
1633 
1634       procedure Recursive_Add
1635         (Project : Project_Id;
1636          In_Tree : Project_Tree_Ref;
1637          Dummy   : in out Boolean);
1638       --  Recursive procedure to add the source/object paths of extended/
1639       --  imported projects.
1640 
1641       -------------------
1642       -- Recursive_Add --
1643       -------------------
1644 
1645       procedure Recursive_Add
1646         (Project : Project_Id;
1647          In_Tree : Project_Tree_Ref;
1648          Dummy   : in out Boolean)
1649       is
1650          pragma Unreferenced (In_Tree);
1651 
1652          Path : Path_Name_Type;
1653 
1654       begin
1655          if Process_Source_Dirs then
1656 
1657             --  Add to path all source directories of this project if there are
1658             --  Ada sources.
1659 
1660             if Has_Ada_Sources (Project) then
1661                Add_To_Source_Path (Project.Source_Dirs, Shared, Source_Paths);
1662             end if;
1663          end if;
1664 
1665          if Process_Object_Dirs then
1666             Path := Get_Object_Directory
1667               (Project,
1668                Including_Libraries => Including_Libraries,
1669                Only_If_Ada         => True);
1670 
1671             if Path /= No_Path then
1672                Add_To_Object_Path (Path, Object_Paths);
1673             end if;
1674          end if;
1675       end Recursive_Add;
1676 
1677       procedure For_All_Projects is
1678         new For_Every_Project_Imported (Boolean, Recursive_Add);
1679 
1680       Dummy : Boolean := False;
1681 
1682    --  Start of processing for Set_Ada_Paths
1683 
1684    begin
1685       --  If it is the first time we call this procedure for this project,
1686       --  compute the source path and/or the object path.
1687 
1688       if Include_Path and then Project.Include_Path_File = No_Path then
1689          Source_Path_Table.Init (Source_Paths);
1690          Process_Source_Dirs := True;
1691          Create_New_Path_File (Shared, Source_FD, Project.Include_Path_File);
1692       end if;
1693 
1694       --  For the object path, we make a distinction depending on
1695       --  Including_Libraries.
1696 
1697       if Objects_Path and Including_Libraries then
1698          if Project.Objects_Path_File_With_Libs = No_Path then
1699             Object_Path_Table.Init (Object_Paths);
1700             Process_Object_Dirs := True;
1701             Create_New_Path_File
1702               (Shared, Object_FD, Project.Objects_Path_File_With_Libs);
1703          end if;
1704 
1705       elsif Objects_Path then
1706          if Project.Objects_Path_File_Without_Libs = No_Path then
1707             Object_Path_Table.Init (Object_Paths);
1708             Process_Object_Dirs := True;
1709             Create_New_Path_File
1710               (Shared, Object_FD, Project.Objects_Path_File_Without_Libs);
1711          end if;
1712       end if;
1713 
1714       --  If there is something to do, set Seen to False for all projects,
1715       --  then call the recursive procedure Add for Project.
1716 
1717       if Process_Source_Dirs or Process_Object_Dirs then
1718          For_All_Projects (Project, In_Tree, Dummy);
1719       end if;
1720 
1721       --  Write and close any file that has been created. Source_FD is not set
1722       --  when this subprogram is called a second time or more, since we reuse
1723       --  the previous version of the file.
1724 
1725       if Source_FD /= Invalid_FD then
1726          Buffer_Last := 0;
1727 
1728          for Index in
1729            Source_Path_Table.First .. Source_Path_Table.Last (Source_Paths)
1730          loop
1731             Get_Name_String (Source_Paths.Table (Index));
1732             Name_Len := Name_Len + 1;
1733             Name_Buffer (Name_Len) := ASCII.LF;
1734             Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1735          end loop;
1736 
1737          Last := Write (Source_FD, Buffer (1)'Address, Buffer_Last);
1738 
1739          if Last = Buffer_Last then
1740             Close (Source_FD, Status);
1741 
1742          else
1743             Status := False;
1744          end if;
1745 
1746          if not Status then
1747             Prj.Com.Fail ("could not write temporary file");
1748          end if;
1749       end if;
1750 
1751       if Object_FD /= Invalid_FD then
1752          Buffer_Last := 0;
1753 
1754          for Index in
1755            Object_Path_Table.First .. Object_Path_Table.Last (Object_Paths)
1756          loop
1757             Get_Name_String (Object_Paths.Table (Index));
1758             Name_Len := Name_Len + 1;
1759             Name_Buffer (Name_Len) := ASCII.LF;
1760             Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1761          end loop;
1762 
1763          Last := Write (Object_FD, Buffer (1)'Address, Buffer_Last);
1764 
1765          if Last = Buffer_Last then
1766             Close (Object_FD, Status);
1767          else
1768             Status := False;
1769          end if;
1770 
1771          if not Status then
1772             Prj.Com.Fail ("could not write temporary file");
1773          end if;
1774       end if;
1775 
1776       --  Set the env vars, if they need to be changed, and set the
1777       --  corresponding flags.
1778 
1779       if Include_Path
1780         and then
1781           Shared.Private_Part.Current_Source_Path_File /=
1782             Project.Include_Path_File
1783       then
1784          Shared.Private_Part.Current_Source_Path_File :=
1785            Project.Include_Path_File;
1786          Set_Path_File_Var
1787            (Project_Include_Path_File,
1788             Get_Name_String (Shared.Private_Part.Current_Source_Path_File));
1789       end if;
1790 
1791       if Objects_Path then
1792          if Including_Libraries then
1793             if Shared.Private_Part.Current_Object_Path_File /=
1794               Project.Objects_Path_File_With_Libs
1795             then
1796                Shared.Private_Part.Current_Object_Path_File :=
1797                  Project.Objects_Path_File_With_Libs;
1798                Set_Path_File_Var
1799                  (Project_Objects_Path_File,
1800                   Get_Name_String
1801                     (Shared.Private_Part.Current_Object_Path_File));
1802             end if;
1803 
1804          else
1805             if Shared.Private_Part.Current_Object_Path_File /=
1806               Project.Objects_Path_File_Without_Libs
1807             then
1808                Shared.Private_Part.Current_Object_Path_File :=
1809                  Project.Objects_Path_File_Without_Libs;
1810                Set_Path_File_Var
1811                  (Project_Objects_Path_File,
1812                   Get_Name_String
1813                     (Shared.Private_Part.Current_Object_Path_File));
1814             end if;
1815          end if;
1816       end if;
1817 
1818       Free (Buffer);
1819    end Set_Ada_Paths;
1820 
1821    ---------------------
1822    -- Add_Directories --
1823    ---------------------
1824 
1825    procedure Add_Directories
1826      (Self    : in out Project_Search_Path;
1827       Path    : String;
1828       Prepend : Boolean := False)
1829    is
1830       Tmp : String_Access;
1831    begin
1832       if Self.Path = null then
1833          Self.Path := new String'(Uninitialized_Prefix & Path);
1834       else
1835          Tmp := Self.Path;
1836          if Prepend then
1837             Self.Path := new String'(Path & Path_Separator & Tmp.all);
1838          else
1839             Self.Path := new String'(Tmp.all & Path_Separator & Path);
1840          end if;
1841          Free (Tmp);
1842       end if;
1843 
1844       if Current_Verbosity = High then
1845          Debug_Output ("Adding directories to Project_Path: """
1846                        & Path & '"');
1847       end if;
1848    end Add_Directories;
1849 
1850    --------------------
1851    -- Is_Initialized --
1852    --------------------
1853 
1854    function Is_Initialized (Self : Project_Search_Path) return Boolean is
1855    begin
1856       return Self.Path /= null
1857         and then (Self.Path'Length = 0
1858                    or else Self.Path (Self.Path'First) /= '#');
1859    end Is_Initialized;
1860 
1861    ----------------------
1862    -- Initialize_Empty --
1863    ----------------------
1864 
1865    procedure Initialize_Empty (Self : in out Project_Search_Path) is
1866    begin
1867       Free (Self.Path);
1868       Self.Path := new String'("");
1869    end Initialize_Empty;
1870 
1871    -------------------------------------
1872    -- Initialize_Default_Project_Path --
1873    -------------------------------------
1874 
1875    procedure Initialize_Default_Project_Path
1876      (Self         : in out Project_Search_Path;
1877       Target_Name  : String;
1878       Runtime_Name : String := "")
1879    is
1880       Add_Default_Dir : Boolean := Target_Name /= "-";
1881       First           : Positive;
1882       Last            : Positive;
1883 
1884       Ada_Project_Path      : constant String := "ADA_PROJECT_PATH";
1885       Gpr_Project_Path      : constant String := "GPR_PROJECT_PATH";
1886       Gpr_Project_Path_File : constant String := "GPR_PROJECT_PATH_FILE";
1887       --  Names of alternate env. variable that contain path name(s) of
1888       --  directories where project files may reside. They are taken into
1889       --  account in this order: GPR_PROJECT_PATH_FILE, GPR_PROJECT_PATH,
1890       --  ADA_PROJECT_PATH.
1891 
1892       Gpr_Prj_Path_File : String_Access;
1893       Gpr_Prj_Path      : String_Access;
1894       Ada_Prj_Path      : String_Access;
1895       --  The path name(s) of directories where project files may reside.
1896       --  May be empty.
1897 
1898       Prefix  : String_Ptr;
1899       Runtime : String_Ptr;
1900 
1901       procedure Add_Target;
1902       --  Add :<prefix>/<target> to the project path
1903 
1904       ----------------
1905       -- Add_Target --
1906       ----------------
1907 
1908       procedure Add_Target is
1909       begin
1910          Add_Str_To_Name_Buffer
1911            (Path_Separator & Prefix.all & Target_Name);
1912 
1913          --  Note: Target_Name has a trailing / when it comes from Sdefault
1914 
1915          if Name_Buffer (Name_Len) /= '/' then
1916             Add_Char_To_Name_Buffer (Directory_Separator);
1917          end if;
1918       end Add_Target;
1919 
1920    --  Start of processing for Initialize_Default_Project_Path
1921 
1922    begin
1923       if Is_Initialized (Self) then
1924          return;
1925       end if;
1926 
1927       --  The current directory is always first in the search path. Since the
1928       --  Project_Path currently starts with '#:' as a sign that it isn't
1929       --  initialized, we simply replace '#' with '.'
1930 
1931       if Self.Path = null then
1932          Self.Path := new String'('.' & Path_Separator);
1933       else
1934          Self.Path (Self.Path'First) := '.';
1935       end if;
1936 
1937       --  Then the reset of the project path (if any) currently contains the
1938       --  directories added through Add_Search_Project_Directory
1939 
1940       --  If environment variables are defined and not empty, add their content
1941 
1942       Gpr_Prj_Path_File := Getenv (Gpr_Project_Path_File);
1943       Gpr_Prj_Path      := Getenv (Gpr_Project_Path);
1944       Ada_Prj_Path      := Getenv (Ada_Project_Path);
1945 
1946       if Gpr_Prj_Path_File.all /= "" then
1947          declare
1948             File : Ada.Text_IO.File_Type;
1949             Line : String (1 .. 10_000);
1950             Last : Natural;
1951 
1952             Tmp : String_Access;
1953 
1954          begin
1955             Open (File, In_File, Gpr_Prj_Path_File.all);
1956 
1957             while not End_Of_File (File) loop
1958                Get_Line (File, Line, Last);
1959 
1960                if Last /= 0
1961                  and then (Last = 1 or else Line (1 .. 2) /= "--")
1962                then
1963                   Tmp := Self.Path;
1964                   Self.Path :=
1965                     new String'
1966                       (Tmp.all & Path_Separator & Line (1 .. Last));
1967                   Free (Tmp);
1968                end if;
1969 
1970                if Current_Verbosity = High then
1971                   Debug_Output ("Adding directory to Project_Path: """
1972                                 & Line (1 .. Last) & '"');
1973                end if;
1974             end loop;
1975 
1976             Close (File);
1977 
1978          exception
1979             when others =>
1980                Write_Str ("warning: could not read project path file """);
1981                Write_Str (Gpr_Prj_Path_File.all);
1982                Write_Line ("""");
1983          end;
1984 
1985       end if;
1986 
1987       if Gpr_Prj_Path.all /= "" then
1988          Add_Directories (Self, Gpr_Prj_Path.all);
1989       end if;
1990 
1991       Free (Gpr_Prj_Path);
1992 
1993       if Ada_Prj_Path.all /= "" then
1994          Add_Directories (Self, Ada_Prj_Path.all);
1995       end if;
1996 
1997       Free (Ada_Prj_Path);
1998 
1999       --  Copy to Name_Buffer, since we will need to manipulate the path
2000 
2001       Name_Len := Self.Path'Length;
2002       Name_Buffer (1 .. Name_Len) := Self.Path.all;
2003 
2004       --  Scan the directory path to see if "-" is one of the directories.
2005       --  Remove each occurrence of "-" and set Add_Default_Dir to False.
2006       --  Also resolve relative paths and symbolic links.
2007 
2008       First := 3;
2009       loop
2010          while First <= Name_Len
2011            and then (Name_Buffer (First) = Path_Separator)
2012          loop
2013             First := First + 1;
2014          end loop;
2015 
2016          exit when First > Name_Len;
2017 
2018          Last := First;
2019 
2020          while Last < Name_Len
2021            and then Name_Buffer (Last + 1) /= Path_Separator
2022          loop
2023             Last := Last + 1;
2024          end loop;
2025 
2026          --  If the directory is "-", set Add_Default_Dir to False and
2027          --  remove from path.
2028 
2029          if Name_Buffer (First .. Last) = No_Project_Default_Dir then
2030             Add_Default_Dir := False;
2031 
2032             for J in Last + 1 .. Name_Len loop
2033                Name_Buffer (J - No_Project_Default_Dir'Length - 1) :=
2034                  Name_Buffer (J);
2035             end loop;
2036 
2037             Name_Len := Name_Len - No_Project_Default_Dir'Length - 1;
2038 
2039             --  After removing the '-', go back one character to get the next
2040             --  directory correctly.
2041 
2042             Last := Last - 1;
2043 
2044          else
2045             declare
2046                New_Dir : constant String :=
2047                            Normalize_Pathname
2048                              (Name_Buffer (First .. Last),
2049                               Resolve_Links => Opt.Follow_Links_For_Dirs);
2050                New_Len  : Positive;
2051                New_Last : Positive;
2052 
2053             begin
2054                --  If the absolute path was resolved and is different from
2055                --  the original, replace original with the resolved path.
2056 
2057                if New_Dir /= Name_Buffer (First .. Last)
2058                  and then New_Dir'Length /= 0
2059                then
2060                   New_Len := Name_Len + New_Dir'Length - (Last - First + 1);
2061                   New_Last := First + New_Dir'Length - 1;
2062                   Name_Buffer (New_Last + 1 .. New_Len) :=
2063                     Name_Buffer (Last + 1 .. Name_Len);
2064                   Name_Buffer (First .. New_Last) := New_Dir;
2065                   Name_Len := New_Len;
2066                   Last := New_Last;
2067                end if;
2068             end;
2069          end if;
2070 
2071          First := Last + 1;
2072       end loop;
2073 
2074       Free (Self.Path);
2075 
2076       --  Set the initial value of Current_Project_Path
2077 
2078       if Add_Default_Dir then
2079          if Sdefault.Search_Dir_Prefix = null then
2080 
2081             --  gprbuild case
2082 
2083             Prefix := new String'(Executable_Prefix_Path);
2084 
2085          else
2086             Prefix := new String'(Sdefault.Search_Dir_Prefix.all
2087                                   & ".." & Dir_Separator
2088                                   & ".." & Dir_Separator
2089                                   & ".." & Dir_Separator
2090                                   & ".." & Dir_Separator);
2091          end if;
2092 
2093          if Prefix.all /= "" then
2094             if Target_Name /= "" then
2095 
2096                if Runtime_Name /= "" then
2097                   if Base_Name (Runtime_Name) = Runtime_Name then
2098 
2099                      --  $prefix/$target/$runtime/lib/gnat
2100                      Add_Target;
2101                      Add_Str_To_Name_Buffer
2102                        (Runtime_Name & Directory_Separator &
2103                           "lib" & Directory_Separator & "gnat");
2104 
2105                      --  $prefix/$target/$runtime/share/gpr
2106                      Add_Target;
2107                      Add_Str_To_Name_Buffer
2108                        (Runtime_Name & Directory_Separator &
2109                           "share" & Directory_Separator & "gpr");
2110 
2111                   else
2112                      Runtime :=
2113                        new String'(Normalize_Pathname (Runtime_Name));
2114 
2115                      --  $runtime_dir/lib/gnat
2116                      Add_Str_To_Name_Buffer
2117                        (Path_Separator & Runtime.all & Directory_Separator &
2118                         "lib" & Directory_Separator & "gnat");
2119 
2120                      --  $runtime_dir/share/gpr
2121                      Add_Str_To_Name_Buffer
2122                        (Path_Separator & Runtime.all & Directory_Separator &
2123                         "share" & Directory_Separator & "gpr");
2124                   end if;
2125                end if;
2126 
2127                --  $prefix/$target/lib/gnat
2128 
2129                Add_Target;
2130                Add_Str_To_Name_Buffer
2131                  ("lib" & Directory_Separator & "gnat");
2132 
2133                --  $prefix/$target/share/gpr
2134 
2135                Add_Target;
2136                Add_Str_To_Name_Buffer
2137                  ("share" & Directory_Separator & "gpr");
2138             end if;
2139 
2140             --  $prefix/share/gpr
2141 
2142             Add_Str_To_Name_Buffer
2143               (Path_Separator & Prefix.all & "share"
2144                & Directory_Separator & "gpr");
2145 
2146             --  $prefix/lib/gnat
2147 
2148             Add_Str_To_Name_Buffer
2149               (Path_Separator & Prefix.all & "lib"
2150                & Directory_Separator & "gnat");
2151          end if;
2152 
2153          Free (Prefix);
2154       end if;
2155 
2156       Self.Path := new String'(Name_Buffer (1 .. Name_Len));
2157    end Initialize_Default_Project_Path;
2158 
2159    --------------
2160    -- Get_Path --
2161    --------------
2162 
2163    procedure Get_Path (Self : Project_Search_Path; Path : out String_Access) is
2164    begin
2165       pragma Assert (Is_Initialized (Self));
2166       Path := Self.Path;
2167    end Get_Path;
2168 
2169    --------------
2170    -- Set_Path --
2171    --------------
2172 
2173    procedure Set_Path (Self : in out Project_Search_Path; Path : String) is
2174    begin
2175       Free (Self.Path);
2176       Self.Path := new String'(Path);
2177       Projects_Paths.Reset (Self.Cache);
2178    end Set_Path;
2179 
2180    -----------------------
2181    -- Find_Name_In_Path --
2182    -----------------------
2183 
2184    function Find_Name_In_Path
2185      (Self : Project_Search_Path;
2186       Path : String) return String_Access
2187    is
2188       First : Natural;
2189       Last  : Natural;
2190 
2191    begin
2192       if Current_Verbosity = High then
2193          Debug_Output ("Trying " & Path);
2194       end if;
2195 
2196       if Is_Absolute_Path (Path) then
2197          if Check_Filename (Path) then
2198             return new String'(Path);
2199          else
2200             return null;
2201          end if;
2202 
2203       else
2204          --  Because we don't want to resolve symbolic links, we cannot use
2205          --  Locate_Regular_File. So, we try each possible path successively.
2206 
2207          First := Self.Path'First;
2208          while First <= Self.Path'Last loop
2209             while First <= Self.Path'Last
2210               and then Self.Path (First) = Path_Separator
2211             loop
2212                First := First + 1;
2213             end loop;
2214 
2215             exit when First > Self.Path'Last;
2216 
2217             Last := First;
2218             while Last < Self.Path'Last
2219               and then Self.Path (Last + 1) /= Path_Separator
2220             loop
2221                Last := Last + 1;
2222             end loop;
2223 
2224             Name_Len := 0;
2225 
2226             if not Is_Absolute_Path (Self.Path (First .. Last)) then
2227                Add_Str_To_Name_Buffer (Get_Current_Dir);  -- ??? System call
2228                Add_Char_To_Name_Buffer (Directory_Separator);
2229             end if;
2230 
2231             Add_Str_To_Name_Buffer (Self.Path (First .. Last));
2232             Add_Char_To_Name_Buffer (Directory_Separator);
2233             Add_Str_To_Name_Buffer (Path);
2234 
2235             if Current_Verbosity = High then
2236                Debug_Output ("Testing file " & Name_Buffer (1 .. Name_Len));
2237             end if;
2238 
2239             if Check_Filename (Name_Buffer (1 .. Name_Len)) then
2240                return new String'(Name_Buffer (1 .. Name_Len));
2241             end if;
2242 
2243             First := Last + 1;
2244          end loop;
2245       end if;
2246 
2247       return null;
2248    end Find_Name_In_Path;
2249 
2250    ------------------
2251    -- Find_Project --
2252    ------------------
2253 
2254    procedure Find_Project
2255      (Self               : in out Project_Search_Path;
2256       Project_File_Name  : String;
2257       Directory          : String;
2258       Path               : out Namet.Path_Name_Type)
2259    is
2260       Result  : String_Access;
2261       Has_Dot : Boolean := False;
2262       Key     : Name_Id;
2263 
2264       File : constant String := Project_File_Name;
2265       --  Have to do a copy, in case the parameter is Name_Buffer, which we
2266       --  modify below.
2267 
2268       Cached_Path : Namet.Path_Name_Type;
2269       --  This should be commented rather than making us guess from the name???
2270 
2271       function Try_Path_Name is new
2272         Find_Name_In_Path (Check_Filename => Is_Regular_File);
2273       --  Find a file in the project search path
2274 
2275    --  Start of processing for Find_Project
2276 
2277    begin
2278       pragma Assert (Is_Initialized (Self));
2279 
2280       if Current_Verbosity = High then
2281          Debug_Increase_Indent
2282            ("Searching for project """ & File & """ in """
2283             & Directory & '"');
2284       end if;
2285 
2286       --  Check the project cache
2287 
2288       Name_Len := File'Length;
2289       Name_Buffer (1 .. Name_Len) := File;
2290       Key := Name_Find;
2291       Cached_Path := Projects_Paths.Get (Self.Cache, Key);
2292 
2293       --  Check if File contains an extension (a dot before a
2294       --  directory separator). If it is the case we do not try project file
2295       --  with an added extension as it is not possible to have multiple dots
2296       --  on a project file name.
2297 
2298       Check_Dot : for K in reverse File'Range loop
2299          if File (K) = '.' then
2300             Has_Dot := True;
2301             exit Check_Dot;
2302          end if;
2303 
2304          exit Check_Dot when Is_Directory_Separator (File (K));
2305       end loop Check_Dot;
2306 
2307       if not Is_Absolute_Path (File) then
2308 
2309          --  If we have found project in the cache, check if in the directory
2310 
2311          if Cached_Path /= No_Path then
2312             declare
2313                Cached : constant String := Get_Name_String (Cached_Path);
2314             begin
2315                if (not Has_Dot
2316                     and then Cached =
2317                       GNAT.OS_Lib.Normalize_Pathname
2318                         (File & Project_File_Extension,
2319                          Directory      => Directory,
2320                          Resolve_Links  => Opt.Follow_Links_For_Files,
2321                          Case_Sensitive => True))
2322                  or else
2323                    Cached =
2324                      GNAT.OS_Lib.Normalize_Pathname
2325                        (File,
2326                         Directory      => Directory,
2327                         Resolve_Links  => Opt.Follow_Links_For_Files,
2328                         Case_Sensitive => True)
2329                then
2330                   Path := Cached_Path;
2331                   Debug_Decrease_Indent;
2332                   return;
2333                end if;
2334             end;
2335          end if;
2336 
2337          --  First we try <directory>/<file_name>.<extension>
2338 
2339          if not Has_Dot then
2340             Result :=
2341               Try_Path_Name
2342                 (Self,
2343                  Directory & Directory_Separator
2344                  & File & Project_File_Extension);
2345          end if;
2346 
2347          --  Then we try <directory>/<file_name>
2348 
2349          if Result = null then
2350             Result :=
2351               Try_Path_Name (Self, Directory & Directory_Separator & File);
2352          end if;
2353       end if;
2354 
2355       --  If we found the path in the cache, this is the one
2356 
2357       if Result = null and then Cached_Path /= No_Path then
2358          Path := Cached_Path;
2359          Debug_Decrease_Indent;
2360          return;
2361       end if;
2362 
2363       --  Then we try <file_name>.<extension>
2364 
2365       if Result = null and then not Has_Dot then
2366          Result := Try_Path_Name (Self, File & Project_File_Extension);
2367       end if;
2368 
2369       --  Then we try <file_name>
2370 
2371       if Result = null then
2372          Result := Try_Path_Name (Self, File);
2373       end if;
2374 
2375       --  If we cannot find the project file, we return an empty string
2376 
2377       if Result = null then
2378          Path := Namet.No_Path;
2379          return;
2380 
2381       else
2382          declare
2383             Final_Result : constant String :=
2384                              GNAT.OS_Lib.Normalize_Pathname
2385                                (Result.all,
2386                                 Directory      => Directory,
2387                                 Resolve_Links  => Opt.Follow_Links_For_Files,
2388                                 Case_Sensitive => True);
2389          begin
2390             Free (Result);
2391             Name_Len := Final_Result'Length;
2392             Name_Buffer (1 .. Name_Len) := Final_Result;
2393             Path := Name_Find;
2394             Projects_Paths.Set (Self.Cache, Key, Path);
2395          end;
2396       end if;
2397 
2398       Debug_Decrease_Indent;
2399    end Find_Project;
2400 
2401    ----------
2402    -- Free --
2403    ----------
2404 
2405    procedure Free (Self : in out Project_Search_Path) is
2406    begin
2407       Free (Self.Path);
2408       Projects_Paths.Reset (Self.Cache);
2409    end Free;
2410 
2411    ----------
2412    -- Copy --
2413    ----------
2414 
2415    procedure Copy (From : Project_Search_Path; To : out Project_Search_Path) is
2416    begin
2417       Free (To);
2418 
2419       if From.Path /= null then
2420          To.Path := new String'(From.Path.all);
2421       end if;
2422 
2423       --  No need to copy the Cache, it will be recomputed as needed
2424    end Copy;
2425 
2426 end Prj.Env;