OSDN Git Service

2001-12-11 David O'Brien <obrien@FreeBSD.org>
[pf3gnuchains/gcc-fork.git] / gcc / ada / prj-part.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                             P R J . P A R T                              --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --                            $Revision$
10 --                                                                          --
11 --             Copyright (C) 2001 Free Software Foundation, Inc.            --
12 --                                                                          --
13 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
14 -- terms of the  GNU General Public License as published  by the Free Soft- --
15 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
16 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
19 -- for  more details.  You should have  received  a copy of the GNU General --
20 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
21 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
22 -- MA 02111-1307, USA.                                                      --
23 --                                                                          --
24 -- GNAT was originally developed  by the GNAT team at  New York University. --
25 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
26 --                                                                          --
27 ------------------------------------------------------------------------------
28
29 with Ada.Characters.Handling;    use Ada.Characters.Handling;
30 with Ada.Exceptions;             use Ada.Exceptions;
31 with Errout;                     use Errout;
32 with GNAT.Directory_Operations;  use GNAT.Directory_Operations;
33 with GNAT.OS_Lib;                use GNAT.OS_Lib;
34 with Namet;                      use Namet;
35 with Osint;                      use Osint;
36 with Output;                     use Output;
37 with Prj.Com;                    use Prj.Com;
38 with Prj.Dect;
39 with Scans;                      use Scans;
40 with Scn;                        use Scn;
41 with Sinfo;                      use Sinfo;
42 with Sinput;                     use Sinput;
43 with Sinput.P;                   use Sinput.P;
44 with Stringt;                    use Stringt;
45 with Table;
46 with Types;                      use Types;
47
48 pragma Elaborate_All (GNAT.OS_Lib);
49
50 package body Prj.Part is
51
52    Dir_Sep  : Character renames GNAT.OS_Lib.Directory_Separator;
53
54    Project_File_Extension : String := ".gpr";
55
56    Project_Path : String_Access;
57    --  The project path; initialized during package elaboration.
58
59    Ada_Project_Path : constant String := "ADA_PROJECT_PATH";
60    Prj_Path : constant String_Access := Getenv (Ada_Project_Path);
61
62    ------------------------------------
63    -- Local Packages and Subprograms --
64    ------------------------------------
65
66    package Project_Stack is new Table.Table
67      (Table_Component_Type => Name_Id,
68       Table_Index_Type     => Nat,
69       Table_Low_Bound      => 1,
70       Table_Initial        => 10,
71       Table_Increment      => 10,
72       Table_Name           => "Prj.Part.Project_Stack");
73    --  This table is used to detect circular dependencies
74    --  for imported and modified projects.
75
76    procedure Parse_Context_Clause
77      (Context_Clause    : out Project_Node_Id;
78       Project_Directory : Name_Id);
79    --  Parse the context clause of a project
80    --  Does nothing if there is b\no context clause (if the current
81    --  token is not "with").
82
83    procedure Parse_Single_Project
84      (Project         : out Project_Node_Id;
85       Path_Name       : String;
86       Modified        : Boolean);
87    --  Parse a project file.
88    --  Recursive procedure: it calls itself for imported and
89    --  modified projects.
90
91    function Path_Name_Of
92      (File_Name : String;
93       Directory : String)
94       return      String;
95    --  Returns the path name of a (non project) file.
96    --  Returns an empty string if file cannot be found.
97
98    function Project_Path_Name_Of
99      (Project_File_Name : String;
100       Directory         : String)
101       return              String;
102    --  Returns the path name of a project file.
103    --  Returns an empty string if project file cannot be found.
104
105    function Immediate_Directory_Of (Path_Name : Name_Id) return Name_Id;
106    --  Get the directory of the file with the specified path name.
107    --  This includes the directory separator as the last character.
108    --  Returns "./" if Path_Name contains no directory separator.
109
110    function Simple_File_Name_Of (Path_Name : Name_Id) return Name_Id;
111    --  Returns the name of a file with the specified path name
112    --  with no directory information.
113
114    function Project_Name_From (Path_Name : String) return Name_Id;
115    --  Returns the name of the project that corresponds to its path name.
116    --  Returns No_Name if the path name is invalid, because the corresponding
117    --  project name does not have the syntax of an ada identifier.
118
119    ----------------------------
120    -- Immediate_Directory_Of --
121    ----------------------------
122
123    function Immediate_Directory_Of (Path_Name : Name_Id) return Name_Id is
124    begin
125       Get_Name_String (Path_Name);
126
127       for Index in reverse 1 .. Name_Len loop
128          if Name_Buffer (Index) = '/'
129            or else Name_Buffer (Index) = Dir_Sep
130          then
131             --  Remove from name all characters after the last
132             --  directory separator.
133
134             Name_Len := Index;
135             return Name_Find;
136          end if;
137       end loop;
138
139       --  There is no directory separator in name. Return "./" or ".\"
140
141       Name_Len := 2;
142       Name_Buffer (1) := '.';
143       Name_Buffer (2) := Dir_Sep;
144       return Name_Find;
145    end Immediate_Directory_Of;
146
147    -----------
148    -- Parse --
149    -----------
150
151    procedure Parse
152      (Project                : out Project_Node_Id;
153       Project_File_Name      : String;
154       Always_Errout_Finalize : Boolean)
155    is
156       Current_Directory : constant String := Get_Current_Dir;
157
158    begin
159       Project := Empty_Node;
160
161       if Current_Verbosity >= Medium then
162          Write_Str ("ADA_PROJECT_PATH=""");
163          Write_Str (Project_Path.all);
164          Write_Line ("""");
165       end if;
166
167       declare
168          Path_Name : constant String :=
169            Project_Path_Name_Of (Project_File_Name,
170                                  Directory   => Current_Directory);
171
172       begin
173          --  Initialize the tables
174
175          Tree_Private_Part.Project_Nodes.Set_Last (Empty_Node);
176          Tree_Private_Part.Projects_Htable.Reset;
177
178          Errout.Initialize;
179
180          --  And parse the main project file
181
182          if Path_Name = "" then
183             Fail ("project file """ & Project_File_Name & """ not found");
184          end if;
185
186          Parse_Single_Project
187            (Project         => Project,
188             Path_Name       => Path_Name,
189             Modified        => False);
190
191          if Errout.Errors_Detected > 0 then
192             Project := Empty_Node;
193          end if;
194
195          if Project = Empty_Node or else Always_Errout_Finalize then
196             Errout.Finalize;
197          end if;
198       end;
199
200    exception
201       when X : others =>
202
203          --  Internal error
204
205          Write_Line (Exception_Information (X));
206          Write_Str  ("Exception ");
207          Write_Str  (Exception_Name (X));
208          Write_Line (" raised, while processing project file");
209          Project := Empty_Node;
210    end Parse;
211
212    --------------------------
213    -- Parse_Context_Clause --
214    --------------------------
215
216    procedure Parse_Context_Clause
217      (Context_Clause    : out Project_Node_Id;
218       Project_Directory : Name_Id)
219    is
220       Project_Directory_Path : constant String :=
221                                  Get_Name_String (Project_Directory);
222       Current_With_Clause    : Project_Node_Id := Empty_Node;
223       Next_With_Clause       : Project_Node_Id := Empty_Node;
224
225    begin
226       --  Assume no context clause
227
228       Context_Clause := Empty_Node;
229       With_Loop :
230
231       --  If Token is not WITH, there is no context clause,
232       --  or we have exhausted the with clauses.
233
234       while Token = Tok_With loop
235          Comma_Loop :
236          loop
237             Scan; -- scan past WITH or ","
238
239             Expect (Tok_String_Literal, "literal string");
240
241             if Token /= Tok_String_Literal then
242                return;
243             end if;
244
245             --  New with clause
246
247             if Current_With_Clause = Empty_Node then
248
249                --  First with clause of the context clause
250
251                Current_With_Clause := Default_Project_Node
252                  (Of_Kind => N_With_Clause);
253                Context_Clause := Current_With_Clause;
254
255             else
256                Next_With_Clause := Default_Project_Node
257                  (Of_Kind => N_With_Clause);
258                Set_Next_With_Clause_Of (Current_With_Clause, Next_With_Clause);
259                Current_With_Clause := Next_With_Clause;
260             end if;
261
262             Set_String_Value_Of (Current_With_Clause, Strval (Token_Node));
263             Set_Location_Of     (Current_With_Clause, Token_Ptr);
264             String_To_Name_Buffer (String_Value_Of (Current_With_Clause));
265
266             declare
267                Original_Path : constant String :=
268                                  Name_Buffer (1 .. Name_Len);
269
270                Imported_Path_Name : constant String :=
271                                       Project_Path_Name_Of
272                                         (Original_Path,
273                                          Project_Directory_Path);
274
275                Withed_Project : Project_Node_Id := Empty_Node;
276
277             begin
278                if Imported_Path_Name = "" then
279
280                   --  The project file cannot be found
281
282                   Name_Len := Original_Path'Length;
283                   Name_Buffer (1 .. Name_Len) := Original_Path;
284                   Error_Msg_Name_1 := Name_Find;
285
286                   Error_Msg ("unknown project file: {", Token_Ptr);
287
288                else
289                   --  Parse the imported project
290
291                   Parse_Single_Project
292                     (Project   => Withed_Project,
293                      Path_Name => Imported_Path_Name,
294                      Modified  => False);
295
296                   if Withed_Project /= Empty_Node then
297
298                      --  If parsing was successful, record project name
299                      --  and path name in with clause
300
301                      Set_Project_Node_Of (Current_With_Clause, Withed_Project);
302                      Set_Name_Of (Current_With_Clause,
303                                   Name_Of (Withed_Project));
304                      Name_Len := Imported_Path_Name'Length;
305                      Name_Buffer (1 .. Name_Len) := Imported_Path_Name;
306                      Set_Path_Name_Of (Current_With_Clause, Name_Find);
307                   end if;
308                end if;
309             end;
310
311             Scan;
312             if Token = Tok_Semicolon then
313
314                --  End of (possibly multiple) with clause;
315
316                Scan; -- scan past the semicolon.
317                exit Comma_Loop;
318
319             elsif Token /= Tok_Comma then
320                Error_Msg ("expected comma or semi colon", Token_Ptr);
321                exit Comma_Loop;
322             end if;
323          end loop Comma_Loop;
324       end loop With_Loop;
325
326    end Parse_Context_Clause;
327
328    --------------------------
329    -- Parse_Single_Project --
330    --------------------------
331
332    procedure Parse_Single_Project
333      (Project         : out Project_Node_Id;
334       Path_Name       : String;
335       Modified        : Boolean)
336    is
337       Canonical_Path_Name : Name_Id;
338       Project_Directory   : Name_Id;
339       Project_Scan_State  : Saved_Project_Scan_State;
340       Source_Index        : Source_File_Index;
341
342       Modified_Project    : Project_Node_Id := Empty_Node;
343
344       A_Project_Name_And_Node : Tree_Private_Part.Project_Name_And_Node :=
345         Tree_Private_Part.Projects_Htable.Get_First;
346
347       Name_From_Path : constant Name_Id := Project_Name_From (Path_Name);
348
349       use Tree_Private_Part;
350
351    begin
352       Name_Len := Path_Name'Length;
353       Name_Buffer (1 .. Name_Len) := Path_Name;
354       Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
355       Canonical_Path_Name := Name_Find;
356
357       --  Check for a circular dependency
358
359       for Index in 1 .. Project_Stack.Last loop
360          if Canonical_Path_Name = Project_Stack.Table (Index) then
361             Error_Msg ("circular dependency detected", Token_Ptr);
362             Error_Msg_Name_1 := Canonical_Path_Name;
363             Error_Msg ("\  { is imported by", Token_Ptr);
364
365             for Current in reverse 1 .. Project_Stack.Last loop
366                Error_Msg_Name_1 := Project_Stack.Table (Current);
367
368                if Error_Msg_Name_1 /= Canonical_Path_Name then
369                   Error_Msg
370                     ("\  { which itself is imported by", Token_Ptr);
371
372                else
373                   Error_Msg ("\  {", Token_Ptr);
374                   exit;
375                end if;
376             end loop;
377
378             Project := Empty_Node;
379             return;
380          end if;
381       end loop;
382
383       Project_Stack.Increment_Last;
384       Project_Stack.Table (Project_Stack.Last) := Canonical_Path_Name;
385
386       --  Check if the project file has already been parsed.
387
388       while
389         A_Project_Name_And_Node /= Tree_Private_Part.No_Project_Name_And_Node
390       loop
391          if
392            Path_Name_Of (A_Project_Name_And_Node.Node) = Canonical_Path_Name
393          then
394             if Modified then
395
396                if A_Project_Name_And_Node.Modified then
397                   Error_Msg
398                     ("cannot modify the same project file several times",
399                      Token_Ptr);
400
401                else
402                   Error_Msg
403                     ("cannot modify an imported project file",
404                      Token_Ptr);
405                end if;
406
407             elsif A_Project_Name_And_Node.Modified then
408                Error_Msg
409                  ("cannot imported a modified project file",
410                   Token_Ptr);
411             end if;
412
413             Project := A_Project_Name_And_Node.Node;
414             Project_Stack.Decrement_Last;
415             return;
416          end if;
417
418          A_Project_Name_And_Node := Tree_Private_Part.Projects_Htable.Get_Next;
419       end loop;
420
421       --  We never encountered this project file
422       --  Save the scan state, load the project file and start to scan it.
423
424       Save_Project_Scan_State (Project_Scan_State);
425       Source_Index := Load_Project_File (Path_Name);
426
427       --  if we cannot find it, we stop
428
429       if Source_Index = No_Source_File then
430          Project := Empty_Node;
431          Project_Stack.Decrement_Last;
432          return;
433       end if;
434
435       Initialize_Scanner (Types.No_Unit, Source_Index);
436
437       if Name_From_Path = No_Name then
438
439          --  The project file name is not correct (no or bad extension,
440          --  or not following Ada identifier's syntax).
441
442          Error_Msg_Name_1 := Canonical_Path_Name;
443          Error_Msg ("?{ is not a valid path name for a project file",
444                     Token_Ptr);
445       end if;
446
447       if Current_Verbosity >= Medium then
448          Write_Str  ("Parsing """);
449          Write_Str  (Path_Name);
450          Write_Char ('"');
451          Write_Eol;
452       end if;
453
454       Project_Directory := Immediate_Directory_Of (Canonical_Path_Name);
455       Project := Default_Project_Node (Of_Kind => N_Project);
456       Set_Directory_Of (Project, Project_Directory);
457       Set_Name_Of (Project, Simple_File_Name_Of (Canonical_Path_Name));
458       Set_Path_Name_Of (Project, Canonical_Path_Name);
459       Set_Location_Of (Project, Token_Ptr);
460
461       --  Is there any imported project?
462
463       declare
464          First_With_Clause : Project_Node_Id := Empty_Node;
465
466       begin
467          Parse_Context_Clause (Context_Clause    => First_With_Clause,
468                                Project_Directory => Project_Directory);
469          Set_First_With_Clause_Of (Project, First_With_Clause);
470       end;
471
472       Expect (Tok_Project, "project");
473
474       --  Mark location of PROJECT token if present
475
476       if Token = Tok_Project then
477          Set_Location_Of (Project, Token_Ptr);
478          Scan; -- scan past project
479       end if;
480
481       Expect (Tok_Identifier, "identifier");
482
483       if Token = Tok_Identifier then
484          Set_Name_Of (Project, Token_Name);
485
486          Get_Name_String (Token_Name);
487          Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
488
489          declare
490             Expected_Name : constant Name_Id := Name_Find;
491
492          begin
493             if Name_From_Path /= No_Name
494               and then Expected_Name /= Name_From_Path
495             then
496                --  The project name is not the one that was expected from
497                --  the file name. Report a warning.
498
499                Error_Msg_Name_1 := Expected_Name;
500                Error_Msg ("?file name does not match unit name, " &
501                           "should be `{" & Project_File_Extension & "`",
502                           Token_Ptr);
503             end if;
504          end;
505
506          declare
507             Project_Name : Name_Id :=
508                              Tree_Private_Part.Projects_Htable.Get_First.Name;
509
510          begin
511             --  Check if we already have a project with this name
512
513             while Project_Name /= No_Name
514               and then Project_Name /= Token_Name
515             loop
516                Project_Name := Tree_Private_Part.Projects_Htable.Get_Next.Name;
517             end loop;
518
519             if Project_Name /= No_Name then
520                Error_Msg ("duplicate project name", Token_Ptr);
521
522             else
523                Tree_Private_Part.Projects_Htable.Set
524                  (K => Token_Name,
525                   E => (Name     => Token_Name,
526                         Node     => Project,
527                         Modified => Modified));
528             end if;
529          end;
530
531          Scan; -- scan past the project name
532       end if;
533
534       if Token = Tok_Extends then
535
536          --  We are extending another project
537
538          Scan; -- scan past EXTENDS
539          Expect (Tok_String_Literal, "literal string");
540
541          if Token = Tok_String_Literal then
542             Set_Modified_Project_Path_Of (Project, Strval (Token_Node));
543             String_To_Name_Buffer (Modified_Project_Path_Of (Project));
544
545             declare
546                Original_Path_Name : constant String :=
547                                       Name_Buffer (1 .. Name_Len);
548
549                Modified_Project_Path_Name : constant String :=
550                                               Project_Path_Name_Of
551                                                 (Original_Path_Name,
552                                                    Get_Name_String
553                                                      (Project_Directory));
554
555             begin
556                if Modified_Project_Path_Name = "" then
557
558                   --  We could not find the project file to modify
559
560                   Name_Len := Original_Path_Name'Length;
561                   Name_Buffer (1 .. Name_Len) := Original_Path_Name;
562                   Error_Msg_Name_1 := Name_Find;
563
564                   Error_Msg ("unknown project file: {", Token_Ptr);
565
566                else
567                   Parse_Single_Project
568                     (Project   => Modified_Project,
569                      Path_Name => Modified_Project_Path_Name,
570                      Modified  => True);
571                end if;
572             end;
573
574             Scan; -- scan past the modified project path
575          end if;
576       end if;
577
578       Expect (Tok_Is, "is");
579
580       declare
581          Project_Declaration : Project_Node_Id := Empty_Node;
582
583       begin
584          --  No need to Scan past IS, Prj.Dect.Parse will do it.
585
586          Prj.Dect.Parse
587            (Declarations    => Project_Declaration,
588             Current_Project => Project,
589             Extends         => Modified_Project);
590          Set_Project_Declaration_Of (Project, Project_Declaration);
591       end;
592
593       Expect (Tok_End, "end");
594
595       --  Skip END if present
596
597       if Token = Tok_End then
598          Scan;
599       end if;
600
601       Expect (Tok_Identifier, "identifier");
602
603       if Token = Tok_Identifier then
604
605          --  We check if this is the project name
606
607          if To_Lower (Get_Name_String (Token_Name)) /=
608             Get_Name_String (Name_Of (Project))
609          then
610             Error_Msg ("Expected """ &
611                        Get_Name_String (Name_Of (Project)) & """",
612                        Token_Ptr);
613          end if;
614       end if;
615
616       if Token /= Tok_Semicolon then
617          Scan;
618       end if;
619
620       Expect (Tok_Semicolon, ";");
621
622       --  Restore the scan state, in case we are not the main project
623
624       Restore_Project_Scan_State (Project_Scan_State);
625
626       Project_Stack.Decrement_Last;
627    end Parse_Single_Project;
628
629    ------------------
630    -- Path_Name_Of --
631    ------------------
632
633    function Path_Name_Of
634      (File_Name : String;
635       Directory : String)
636       return      String
637    is
638       Result : String_Access;
639
640    begin
641       Result := Locate_Regular_File (File_Name => File_Name,
642                                      Path      => Directory);
643
644       if Result = null then
645          return "";
646
647       else
648          Canonical_Case_File_Name (Result.all);
649          return Result.all;
650       end if;
651    end Path_Name_Of;
652
653    -----------------------
654    -- Project_Name_From --
655    -----------------------
656
657    function Project_Name_From (Path_Name : String) return Name_Id is
658       Canonical : String (1 .. Path_Name'Length) := Path_Name;
659       First : Natural  := Canonical'Last;
660       Last  : Positive := First;
661
662    begin
663       if First = 0 then
664          return No_Name;
665       end if;
666
667       Canonical_Case_File_Name (Canonical);
668
669       while First > 0
670         and then
671         Canonical (First) /= '.'
672       loop
673          First := First - 1;
674       end loop;
675
676       if Canonical (First) = '.' then
677          if Canonical (First .. Last) = Project_File_Extension
678            and then First /= 1
679          then
680             First := First - 1;
681             Last := First;
682
683             while First > 0
684               and then Canonical (First) /= '/'
685               and then Canonical (First) /= Dir_Sep
686             loop
687                First := First - 1;
688             end loop;
689
690          else
691             return No_Name;
692          end if;
693
694       else
695          return No_Name;
696       end if;
697
698       if Canonical (First) = '/'
699         or else Canonical (First) = Dir_Sep
700       then
701          First := First + 1;
702       end if;
703
704       Name_Len := Last - First + 1;
705       Name_Buffer (1 .. Name_Len) := To_Lower (Canonical (First .. Last));
706
707       if not Is_Letter (Name_Buffer (1)) then
708          return No_Name;
709
710       else
711          for Index in 2 .. Name_Len - 1 loop
712             if Name_Buffer (Index) = '_' then
713                if Name_Buffer (Index + 1) = '_' then
714                   return No_Name;
715                end if;
716
717             elsif not Is_Alphanumeric (Name_Buffer (Index)) then
718                return No_Name;
719             end if;
720
721          end loop;
722
723          if not Is_Alphanumeric (Name_Buffer (Name_Len)) then
724             return No_Name;
725
726          else
727             return Name_Find;
728          end if;
729
730       end if;
731    end Project_Name_From;
732
733    --------------------------
734    -- Project_Path_Name_Of --
735    --------------------------
736
737    function Project_Path_Name_Of
738      (Project_File_Name : String;
739       Directory         : String)
740       return              String
741    is
742       Result : String_Access;
743
744    begin
745       --  First we try <file_name>.<extension>
746
747       if Current_Verbosity = High then
748          Write_Str  ("Project_Path_Name_Of (""");
749          Write_Str  (Project_File_Name);
750          Write_Str  (""", """);
751          Write_Str  (Directory);
752          Write_Line (""");");
753          Write_Str  ("   Trying ");
754          Write_Str (Project_File_Name);
755          Write_Line (Project_File_Extension);
756       end if;
757
758       Result :=
759         Locate_Regular_File
760           (File_Name => Project_File_Name & Project_File_Extension,
761            Path      => Project_Path.all);
762
763       --  Then we try <file_name>
764
765       if Result = null then
766          if Current_Verbosity = High then
767             Write_Str  ("   Trying ");
768             Write_Line  (Project_File_Name);
769          end if;
770
771          Result :=
772            Locate_Regular_File
773            (File_Name => Project_File_Name,
774             Path      => Project_Path.all);
775
776          --  The we try <directory>/<file_name>.<extension>
777
778          if Result = null then
779             if Current_Verbosity = High then
780                Write_Str  ("   Trying ");
781                Write_Str  (Directory);
782                Write_Str (Project_File_Name);
783                Write_Line (Project_File_Extension);
784             end if;
785
786             Result :=
787               Locate_Regular_File
788               (File_Name => Directory & Project_File_Name &
789                             Project_File_Extension,
790                Path      => Project_Path.all);
791
792             --  Then we try <directory>/<file_name>
793
794             if Result = null then
795                if Current_Verbosity = High then
796                   Write_Str  ("   Trying ");
797                   Write_Str  (Directory);
798                   Write_Line  (Project_File_Name);
799                end if;
800
801                Result :=
802                  Locate_Regular_File
803                  (File_Name => Directory & Project_File_Name,
804                   Path      => Project_Path.all);
805             end if;
806          end if;
807       end if;
808
809       --  If we cannot find the project file, we return an empty string
810
811       if Result = null then
812          return "";
813
814       else
815          declare
816             Final_Result : String
817               := GNAT.OS_Lib.Normalize_Pathname (Result.all);
818          begin
819             Free (Result);
820             Canonical_Case_File_Name (Final_Result);
821             return Final_Result;
822          end;
823
824       end if;
825
826    end Project_Path_Name_Of;
827
828    -------------------------
829    -- Simple_File_Name_Of --
830    -------------------------
831
832    function Simple_File_Name_Of (Path_Name : Name_Id) return Name_Id is
833    begin
834       Get_Name_String (Path_Name);
835
836       for Index in reverse 1 .. Name_Len loop
837          if Name_Buffer (Index) = '/'
838            or else Name_Buffer (Index) = Dir_Sep
839          then
840             exit when Index = Name_Len;
841             Name_Buffer (1 .. Name_Len - Index) :=
842               Name_Buffer (Index + 1 .. Name_Len);
843             Name_Len := Name_Len - Index;
844             return Name_Find;
845          end if;
846       end loop;
847
848       return No_Name;
849
850    end Simple_File_Name_Of;
851
852 begin
853    Canonical_Case_File_Name (Project_File_Extension);
854
855    if Prj_Path.all = "" then
856       Project_Path := new String'(".");
857
858    else
859       Project_Path := new String'("." & Path_Separator & Prj_Path.all);
860    end if;
861
862 end Prj.Part;