OSDN Git Service

2007-01-26 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / prj-makr.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                             P R J . M A K R                              --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2001-2006, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- GNAT was originally developed  by the GNAT team at  New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
24 --                                                                          --
25 ------------------------------------------------------------------------------
26
27 with Csets;
28 with Namet;    use Namet;
29 with Opt;
30 with Output;
31 with Osint;    use Osint;
32 with Prj;      use Prj;
33 with Prj.Com;
34 with Prj.Part;
35 with Prj.PP;
36 with Prj.Tree; use Prj.Tree;
37 with Prj.Util; use Prj.Util;
38 with Snames;   use Snames;
39 with Table;    use Table;
40
41 with Ada.Characters.Handling;   use Ada.Characters.Handling;
42 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
43 with GNAT.Regexp;               use GNAT.Regexp;
44
45 with System.Case_Util;          use System.Case_Util;
46 with System.CRTL;
47
48 package body Prj.Makr is
49
50    --  Packages of project files where unknown attributes are errors
51
52    --  All the following need comments ??? All global variables and
53    --  subprograms must be fully commented.
54
55    Naming_String : aliased String := "naming";
56
57    Gnatname_Packages : aliased String_List := (1 => Naming_String'Access);
58
59    Packages_To_Check_By_Gnatname : constant String_List_Access :=
60                                      Gnatname_Packages'Access;
61
62    function Dup (Fd : File_Descriptor) return File_Descriptor;
63
64    procedure Dup2 (Old_Fd, New_Fd : File_Descriptor);
65
66    Gcc      : constant String := "gcc";
67    Gcc_Path : String_Access := null;
68
69    Non_Empty_Node : constant Project_Node_Id := 1;
70    --  Used for the With_Clause of the naming project
71
72    type Matched_Type is (True, False, Excluded);
73
74    Naming_File_Suffix      : constant String := "_naming";
75    Source_List_File_Suffix : constant String := "_source_list.txt";
76
77    Output_FD : File_Descriptor;
78    --  To save the project file and its naming project file
79
80    procedure Write_Eol;
81    --  Output an empty line
82
83    procedure Write_A_Char (C : Character);
84    --  Write one character to Output_FD
85
86    procedure Write_A_String (S : String);
87    --  Write a String to Output_FD
88
89    package Processed_Directories is new Table.Table
90      (Table_Component_Type => String_Access,
91       Table_Index_Type     => Natural,
92       Table_Low_Bound      => 0,
93       Table_Initial        => 10,
94       Table_Increment      => 100,
95       Table_Name           => "Prj.Makr.Processed_Directories");
96
97    ---------
98    -- Dup --
99    ---------
100
101    function Dup  (Fd : File_Descriptor) return File_Descriptor is
102    begin
103       return File_Descriptor (System.CRTL.dup (Integer (Fd)));
104    end Dup;
105
106    ----------
107    -- Dup2 --
108    ----------
109
110    procedure Dup2 (Old_Fd, New_Fd : File_Descriptor) is
111       Fd : Integer;
112       pragma Warnings (Off, Fd);
113    begin
114       Fd := System.CRTL.dup2 (Integer (Old_Fd), Integer (New_Fd));
115    end Dup2;
116
117    ----------
118    -- Make --
119    ----------
120
121    procedure Make
122      (File_Path         : String;
123       Project_File      : Boolean;
124       Directories       : Argument_List;
125       Name_Patterns     : Argument_List;
126       Excluded_Patterns : Argument_List;
127       Foreign_Patterns  : Argument_List;
128       Preproc_Switches  : Argument_List;
129       Very_Verbose      : Boolean)
130    is
131       Tree : constant Project_Node_Tree_Ref := new Project_Node_Tree_Data;
132
133       Path_Name : String (1 .. File_Path'Length +
134                             Project_File_Extension'Length);
135       Path_Last : Natural := File_Path'Length;
136
137       Directory_Last    : Natural := 0;
138
139       Output_Name      : String (Path_Name'Range);
140       Output_Name_Last : Natural;
141       Output_Name_Id   : Name_Id;
142
143       Project_Node        : Project_Node_Id := Empty_Node;
144       Project_Declaration : Project_Node_Id := Empty_Node;
145       Source_Dirs_List    : Project_Node_Id := Empty_Node;
146       Current_Source_Dir  : Project_Node_Id := Empty_Node;
147
148       Project_Naming_Node     : Project_Node_Id := Empty_Node;
149       Project_Naming_Decl     : Project_Node_Id := Empty_Node;
150       Naming_Package          : Project_Node_Id := Empty_Node;
151       Naming_Package_Comments : Project_Node_Id := Empty_Node;
152
153       Source_Files_Comments     : Project_Node_Id := Empty_Node;
154       Source_Dirs_Comments      : Project_Node_Id := Empty_Node;
155       Source_List_File_Comments : Project_Node_Id := Empty_Node;
156
157       Project_Naming_File_Name : String (1 .. Output_Name'Length +
158                                            Naming_File_Suffix'Length);
159
160       Project_Naming_Last : Natural;
161       Project_Naming_Id   : Name_Id := No_Name;
162
163       Excluded_Expressions : array (Excluded_Patterns'Range) of Regexp;
164       Regular_Expressions  : array (Name_Patterns'Range) of Regexp;
165       Foreign_Expressions  : array (Foreign_Patterns'Range) of Regexp;
166
167       Source_List_Path : String (1 .. Output_Name'Length +
168                                    Source_List_File_Suffix'Length);
169       Source_List_Last : Natural;
170
171       Source_List_FD : File_Descriptor;
172
173       Args : Argument_List  (1 .. Preproc_Switches'Length + 6);
174
175       type SFN_Pragma is record
176          Unit  : Name_Id;
177          File  : Name_Id;
178          Index : Int := 0;
179          Spec  : Boolean;
180       end record;
181
182       package SFN_Pragmas is new Table.Table
183         (Table_Component_Type => SFN_Pragma,
184          Table_Index_Type     => Natural,
185          Table_Low_Bound      => 0,
186          Table_Initial        => 50,
187          Table_Increment      => 100,
188          Table_Name           => "Prj.Makr.SFN_Pragmas");
189
190       procedure Process_Directory (Dir_Name : String; Recursively : Boolean);
191       --  Look for Ada and foreign sources in a directory, according to the
192       --  patterns. When Recursively is True, after looking for sources in
193       --  Dir_Name, look also in its subdirectories, if any.
194
195       -----------------------
196       -- Process_Directory --
197       -----------------------
198
199       procedure Process_Directory (Dir_Name : String; Recursively : Boolean) is
200          Matched : Matched_Type := False;
201          Str     : String (1 .. 2_000);
202          Canon   : String (1 .. 2_000);
203          Last    : Natural;
204          Dir     : Dir_Type;
205          Process : Boolean := True;
206
207          Temp_File_Name         : String_Access := null;
208          Save_Last_Pragma_Index : Natural := 0;
209          File_Name_Id           : Name_Id := No_Name;
210          SFN_Prag               : SFN_Pragma;
211
212       begin
213          --  Avoid processing the same directory more than once
214
215          for Index in 1 .. Processed_Directories.Last loop
216             if Processed_Directories.Table (Index).all = Dir_Name then
217                Process := False;
218                exit;
219             end if;
220          end loop;
221
222          if Process then
223             if Opt.Verbose_Mode then
224                Output.Write_Str ("Processing directory """);
225                Output.Write_Str (Dir_Name);
226                Output.Write_Line ("""");
227             end if;
228
229             Processed_Directories. Increment_Last;
230             Processed_Directories.Table (Processed_Directories.Last) :=
231               new String'(Dir_Name);
232
233             --  Get the source file names from the directory. Fails if the
234             --  directory does not exist.
235
236             begin
237                Open (Dir, Dir_Name);
238             exception
239                when Directory_Error =>
240                   Prj.Com.Fail ("cannot open directory """, Dir_Name, """");
241             end;
242
243             --  Process each regular file in the directory
244
245             File_Loop : loop
246                Read (Dir, Str, Last);
247                exit File_Loop when Last = 0;
248
249                --  Copy the file name and put it in canonical case to match
250                --  against the patterns that have themselves already been put
251                --  in canonical case.
252
253                Canon (1 .. Last) := Str (1 .. Last);
254                Canonical_Case_File_Name (Canon (1 .. Last));
255
256                if Is_Regular_File
257                  (Dir_Name & Directory_Separator & Str (1 .. Last))
258                then
259                   Matched := True;
260
261                   Name_Len := Last;
262                   Name_Buffer (1 .. Name_Len) := Str (1 .. Last);
263                   File_Name_Id := Name_Find;
264
265                   --  First, check if the file name matches at least one of
266                   --  the excluded expressions;
267
268                   for Index in Excluded_Expressions'Range loop
269                      if
270                        Match (Canon (1 .. Last), Excluded_Expressions (Index))
271                      then
272                         Matched := Excluded;
273                         exit;
274                      end if;
275                   end loop;
276
277                   --  If it does not match any of the excluded expressions,
278                   --  check if the file name matches at least one of the
279                   --  regular expressions.
280
281                   if Matched = True then
282                      Matched := False;
283
284                      for Index in Regular_Expressions'Range loop
285                         if
286                           Match
287                             (Canon (1 .. Last), Regular_Expressions (Index))
288                         then
289                            Matched := True;
290                            exit;
291                         end if;
292                      end loop;
293                   end if;
294
295                   if Very_Verbose
296                     or else (Matched = True and then Opt.Verbose_Mode)
297                   then
298                      Output.Write_Str ("   Checking """);
299                      Output.Write_Str (Str (1 .. Last));
300                      Output.Write_Line (""": ");
301                   end if;
302
303                   --  If the file name matches one of the regular expressions,
304                   --  parse it to get its unit name.
305
306                   if Matched = True then
307                      declare
308                         FD : File_Descriptor;
309                         Success : Boolean;
310                         Saved_Output : File_Descriptor;
311                         Saved_Error  : File_Descriptor;
312
313                      begin
314                         --  If we don't have the path of the compiler yet,
315                         --  get it now. The compiler name may have a prefix,
316                         --  so we get the potentially prefixed name.
317
318                         if Gcc_Path = null then
319                            declare
320                               Prefix_Gcc : String_Access :=
321                                              Program_Name (Gcc);
322                            begin
323                               Gcc_Path :=
324                                 Locate_Exec_On_Path (Prefix_Gcc.all);
325                               Free (Prefix_Gcc);
326                            end;
327
328                            if Gcc_Path = null then
329                               Prj.Com.Fail ("could not locate " & Gcc);
330                            end if;
331                         end if;
332
333                         --  If we don't have yet the file name of the
334                         --  temporary file, get it now.
335
336                         if Temp_File_Name = null then
337                            Create_Temp_File (FD, Temp_File_Name);
338
339                            if FD = Invalid_FD then
340                               Prj.Com.Fail
341                                 ("could not create temporary file");
342                            end if;
343
344                            Close (FD);
345                            Delete_File (Temp_File_Name.all, Success);
346                         end if;
347
348                         Args (Args'Last) := new String'
349                           (Dir_Name &
350                            Directory_Separator &
351                            Str (1 .. Last));
352
353                         --  Create the temporary file
354
355                         FD := Create_Output_Text_File
356                           (Name => Temp_File_Name.all);
357
358                         if FD = Invalid_FD then
359                            Prj.Com.Fail
360                              ("could not create temporary file");
361                         end if;
362
363                         --  Save the standard output and error
364
365                         Saved_Output := Dup (Standout);
366                         Saved_Error  := Dup (Standerr);
367
368                         --  Set standard output and error to the temporary file
369
370                         Dup2 (FD, Standout);
371                         Dup2 (FD, Standerr);
372
373                         --  And spawn the compiler
374
375                         Spawn (Gcc_Path.all, Args, Success);
376
377                         --  Restore the standard output and error
378
379                         Dup2 (Saved_Output, Standout);
380                         Dup2 (Saved_Error, Standerr);
381
382                         --  Close the temporary file
383
384                         Close (FD);
385
386                         --  And close the saved standard output and error to
387                         --  avoid too many file descriptors.
388
389                         Close (Saved_Output);
390                         Close (Saved_Error);
391
392                         --  Now that standard output is restored, check if
393                         --  the compiler ran correctly.
394
395                         --  Read the lines of the temporary file:
396                         --  they should contain the kind and name of the unit.
397
398                         declare
399                            File      : Text_File;
400                            Text_Line : String (1 .. 1_000);
401                            Text_Last : Natural;
402
403                         begin
404                            Open (File, Temp_File_Name.all);
405
406                            if not Is_Valid (File) then
407                               Prj.Com.Fail
408                                 ("could not read temporary file");
409                            end if;
410
411                            Save_Last_Pragma_Index := SFN_Pragmas.Last;
412
413                            if End_Of_File (File) then
414                               if Opt.Verbose_Mode then
415                                  if not Success then
416                                     Output.Write_Str ("      (process died) ");
417                                  end if;
418                               end if;
419
420                            else
421                               Line_Loop : while not End_Of_File (File) loop
422                                  Get_Line (File, Text_Line, Text_Last);
423
424                                  --  Find the first closing parenthesis
425
426                                  Char_Loop : for J in 1 .. Text_Last loop
427                                     if Text_Line (J) = ')' then
428                                        if J >= 13 and then
429                                          Text_Line (1 .. 4) = "Unit"
430                                        then
431                                           --  Add entry to SFN_Pragmas table
432
433                                           Name_Len := J - 12;
434                                           Name_Buffer (1 .. Name_Len) :=
435                                             Text_Line (6 .. J - 7);
436                                           SFN_Prag :=
437                                             (Unit  => Name_Find,
438                                              File  => File_Name_Id,
439                                              Index => 0,
440                                              Spec  => Text_Line (J - 5 .. J) =
441                                                         "(spec)");
442
443                                           SFN_Pragmas.Increment_Last;
444                                           SFN_Pragmas.Table
445                                             (SFN_Pragmas.Last) := SFN_Prag;
446                                        end if;
447                                        exit Char_Loop;
448                                     end if;
449                                  end loop Char_Loop;
450                               end loop Line_Loop;
451                            end if;
452
453                            if Save_Last_Pragma_Index = SFN_Pragmas.Last then
454                               if Opt.Verbose_Mode then
455                                  Output.Write_Line ("      not a unit");
456                               end if;
457
458                            else
459                               if SFN_Pragmas.Last >
460                                    Save_Last_Pragma_Index + 1
461                               then
462                                  for Index in Save_Last_Pragma_Index + 1 ..
463                                                 SFN_Pragmas.Last
464                                  loop
465                                     SFN_Pragmas.Table (Index).Index :=
466                                       Int (Index - Save_Last_Pragma_Index);
467                                  end loop;
468                               end if;
469
470                               for Index in Save_Last_Pragma_Index + 1 ..
471                                              SFN_Pragmas.Last
472                               loop
473                                  SFN_Prag := SFN_Pragmas.Table (Index);
474
475                                  if Opt.Verbose_Mode then
476                                     if SFN_Prag.Spec then
477                                        Output.Write_Str ("      spec of ");
478
479                                     else
480                                        Output.Write_Str ("      body of ");
481                                     end if;
482
483                                     Output.Write_Line
484                                       (Get_Name_String (SFN_Prag.Unit));
485                                  end if;
486
487                                  if Project_File then
488
489                                     --  Add the corresponding attribute in the
490                                     --  Naming package of the naming project.
491
492                                     declare
493                                        Decl_Item : constant Project_Node_Id :=
494                                          Default_Project_Node
495                                            (Of_Kind =>
496                                                 N_Declarative_Item,
497                                             In_Tree => Tree);
498
499                                        Attribute : constant Project_Node_Id :=
500                                          Default_Project_Node
501                                            (Of_Kind =>
502                                                 N_Attribute_Declaration,
503                                             In_Tree => Tree);
504
505                                        Expression : constant Project_Node_Id :=
506                                          Default_Project_Node
507                                            (Of_Kind => N_Expression,
508                                             And_Expr_Kind => Single,
509                                             In_Tree => Tree);
510
511                                        Term : constant Project_Node_Id :=
512                                          Default_Project_Node
513                                            (Of_Kind => N_Term,
514                                             And_Expr_Kind => Single,
515                                             In_Tree => Tree);
516
517                                        Value : constant Project_Node_Id :=
518                                          Default_Project_Node
519                                            (Of_Kind       => N_Literal_String,
520                                             And_Expr_Kind => Single,
521                                             In_Tree       => Tree);
522
523                                     begin
524                                        Set_Next_Declarative_Item
525                                          (Decl_Item,
526                                           To => First_Declarative_Item_Of
527                                             (Naming_Package, Tree),
528                                           In_Tree => Tree);
529                                        Set_First_Declarative_Item_Of
530                                          (Naming_Package,
531                                           To => Decl_Item,
532                                           In_Tree => Tree);
533                                        Set_Current_Item_Node
534                                          (Decl_Item,
535                                           To => Attribute,
536                                           In_Tree => Tree);
537
538                                        --  Is it a spec or a body?
539
540                                        if SFN_Prag.Spec then
541                                           Set_Name_Of
542                                             (Attribute, Tree,
543                                              To => Name_Spec);
544                                        else
545                                           Set_Name_Of
546                                             (Attribute, Tree,
547                                              To => Name_Body);
548                                        end if;
549
550                                        --  Get the name of the unit
551
552                                        Get_Name_String (SFN_Prag.Unit);
553                                        To_Lower (Name_Buffer (1 .. Name_Len));
554                                        Set_Associative_Array_Index_Of
555                                          (Attribute, Tree, To => Name_Find);
556
557                                        Set_Expression_Of
558                                          (Attribute, Tree, To => Expression);
559                                        Set_First_Term
560                                          (Expression, Tree, To => Term);
561                                        Set_Current_Term
562                                          (Term, Tree, To => Value);
563
564                                        --  And set the name of the file
565
566                                        Set_String_Value_Of
567                                          (Value, Tree, To => File_Name_Id);
568                                        Set_Source_Index_Of
569                                          (Value, Tree, To => SFN_Prag.Index);
570                                     end;
571                                  end if;
572                               end loop;
573
574                               if Project_File then
575                                  --  Add source file name to source list
576                                  --  file.
577
578                                  Last := Last + 1;
579                                  Str (Last) := ASCII.LF;
580
581                                  if Write (Source_List_FD,
582                                            Str (1)'Address,
583                                            Last) /= Last
584                                  then
585                                     Prj.Com.Fail ("disk full");
586                                  end if;
587                               end if;
588                            end if;
589
590                            Close (File);
591
592                            Delete_File (Temp_File_Name.all, Success);
593                         end;
594                      end;
595
596                   --  File name matches none of the regular expressions
597
598                   else
599                      --  If file is not excluded, see if this is foreign source
600
601                      if Matched /= Excluded then
602                         for Index in Foreign_Expressions'Range loop
603                            if Match (Canon (1 .. Last),
604                                      Foreign_Expressions (Index))
605                            then
606                               Matched := True;
607                               exit;
608                            end if;
609                         end loop;
610                      end if;
611
612                      if Very_Verbose then
613                         case Matched is
614                            when False =>
615                               Output.Write_Line ("no match");
616
617                            when Excluded =>
618                               Output.Write_Line ("excluded");
619
620                            when True =>
621                               Output.Write_Line ("foreign source");
622                         end case;
623                      end if;
624
625                      if Project_File and Matched = True then
626
627                         --  Add source file name to source list file
628
629                         Last := Last + 1;
630                         Str (Last) := ASCII.LF;
631
632                         if Write (Source_List_FD,
633                                   Str (1)'Address,
634                                   Last) /= Last
635                         then
636                            Prj.Com.Fail ("disk full");
637                         end if;
638                      end if;
639                   end if;
640                end if;
641             end loop File_Loop;
642
643             Close (Dir);
644          end if;
645
646          --  If Recursively is True, call itself for each subdirectory.
647          --  We do that, even when this directory has already been processed,
648          --  because all of its subdirectories may not have been processed.
649
650          if Recursively then
651             Open (Dir, Dir_Name);
652
653             loop
654                Read (Dir, Str, Last);
655                exit when Last = 0;
656
657                --  Do not call itself for "." or ".."
658
659                if Is_Directory
660                  (Dir_Name & Directory_Separator & Str (1 .. Last))
661                  and then Str (1 .. Last) /= "."
662                  and then Str (1 .. Last) /= ".."
663                then
664                   Process_Directory
665                     (Dir_Name & Directory_Separator & Str (1 .. Last),
666                      Recursively => True);
667                end if;
668             end loop;
669
670             Close (Dir);
671          end if;
672       end Process_Directory;
673
674    --  Start of processing for Make
675
676    begin
677       --  Do some needed initializations
678
679       Csets.Initialize;
680       Namet.Initialize;
681       Snames.Initialize;
682       Prj.Initialize (No_Project_Tree);
683       Prj.Tree.Initialize (Tree);
684
685       SFN_Pragmas.Set_Last (0);
686
687       Processed_Directories.Set_Last (0);
688
689       --  Initialize the compiler switches
690
691       Args (1) := new String'("-c");
692       Args (2) := new String'("-gnats");
693       Args (3) := new String'("-gnatu");
694       Args (4 .. 3 + Preproc_Switches'Length) := Preproc_Switches;
695       Args (4 + Preproc_Switches'Length) := new String'("-x");
696       Args (5 + Preproc_Switches'Length) := new String'("ada");
697
698       --  Get the path and file names
699
700       if File_Names_Case_Sensitive then
701          Path_Name (1 .. Path_Last) := File_Path;
702       else
703          Path_Name (1 .. Path_Last) := To_Lower (File_Path);
704       end if;
705
706       Path_Name (Path_Last + 1 .. Path_Name'Last) :=
707         Project_File_Extension;
708
709       --  Get the end of directory information, if any
710
711       for Index in reverse 1 .. Path_Last loop
712          if Path_Name (Index) = Directory_Separator then
713             Directory_Last := Index;
714             exit;
715          end if;
716       end loop;
717
718       if Project_File then
719          if Path_Last < Project_File_Extension'Length + 1
720            or else Path_Name
721            (Path_Last - Project_File_Extension'Length + 1 .. Path_Last)
722            /= Project_File_Extension
723          then
724             Path_Last := Path_Name'Last;
725          end if;
726
727          Output_Name (1 .. Path_Last) := To_Lower (Path_Name (1 .. Path_Last));
728          Output_Name_Last := Path_Last - Project_File_Extension'Length;
729
730          --  If there is already a project file with the specified name, parse
731          --  it to get the components that are not automatically generated.
732
733          if Is_Regular_File (Output_Name (1 .. Path_Last)) then
734             if Opt.Verbose_Mode then
735                Output.Write_Str ("Parsing already existing project file """);
736                Output.Write_Str (Output_Name (1 .. Output_Name_Last));
737                Output.Write_Line ("""");
738             end if;
739
740             Part.Parse
741               (In_Tree                => Tree,
742                Project                => Project_Node,
743                Project_File_Name      => Output_Name (1 .. Output_Name_Last),
744                Always_Errout_Finalize => False,
745                Store_Comments         => True,
746                Packages_To_Check      => Packages_To_Check_By_Gnatname);
747
748             --  Fail if parsing was not successful
749
750             if Project_Node = Empty_Node then
751                Fail ("parsing of existing project file failed");
752
753             else
754                --  If parsing was successful, remove the components that are
755                --  automatically generated, if any, so that they will be
756                --  unconditionally added later.
757
758                --  Remove the with clause for the naming project file
759
760                declare
761                   With_Clause : Project_Node_Id :=
762                                   First_With_Clause_Of (Project_Node, Tree);
763                   Previous    : Project_Node_Id := Empty_Node;
764
765                begin
766                   while With_Clause /= Empty_Node loop
767                      if Prj.Tree.Name_Of (With_Clause, Tree) =
768                           Project_Naming_Id
769                      then
770                         if Previous = Empty_Node then
771                            Set_First_With_Clause_Of
772                              (Project_Node, Tree,
773                               To => Next_With_Clause_Of (With_Clause, Tree));
774                         else
775                            Set_Next_With_Clause_Of
776                              (Previous, Tree,
777                               To => Next_With_Clause_Of (With_Clause, Tree));
778                         end if;
779
780                         exit;
781                      end if;
782
783                      Previous := With_Clause;
784                      With_Clause := Next_With_Clause_Of (With_Clause, Tree);
785                   end loop;
786                end;
787
788                --  Remove attribute declarations of Source_Files,
789                --  Source_List_File, Source_Dirs, and the declaration of
790                --  package Naming, if they exist, but preserve the comments
791                --  attached to these nodes.
792
793                declare
794                   Declaration  : Project_Node_Id :=
795                                    First_Declarative_Item_Of
796                                      (Project_Declaration_Of
797                                         (Project_Node, Tree),
798                                       Tree);
799                   Previous     : Project_Node_Id := Empty_Node;
800                   Current_Node : Project_Node_Id := Empty_Node;
801
802                   Name         : Name_Id;
803                   Kind_Of_Node : Project_Node_Kind;
804                   Comments     : Project_Node_Id;
805
806                begin
807                   while Declaration /= Empty_Node loop
808                      Current_Node := Current_Item_Node (Declaration, Tree);
809
810                      Kind_Of_Node := Kind_Of (Current_Node, Tree);
811
812                      if Kind_Of_Node = N_Attribute_Declaration or else
813                        Kind_Of_Node = N_Package_Declaration
814                      then
815                         Name := Prj.Tree.Name_Of (Current_Node, Tree);
816
817                         if Name = Name_Source_Files     or else
818                            Name = Name_Source_List_File or else
819                            Name = Name_Source_Dirs      or else
820                            Name = Name_Naming
821                         then
822                            Comments :=
823                              Tree.Project_Nodes.Table (Current_Node).Comments;
824
825                            if Name = Name_Source_Files then
826                               Source_Files_Comments := Comments;
827
828                            elsif Name = Name_Source_List_File then
829                               Source_List_File_Comments := Comments;
830
831                            elsif Name = Name_Source_Dirs then
832                               Source_Dirs_Comments := Comments;
833
834                            elsif Name = Name_Naming then
835                               Naming_Package_Comments := Comments;
836                            end if;
837
838                            if Previous = Empty_Node then
839                               Set_First_Declarative_Item_Of
840                                 (Project_Declaration_Of (Project_Node, Tree),
841                                  Tree,
842                                  To => Next_Declarative_Item
843                                          (Declaration, Tree));
844
845                            else
846                               Set_Next_Declarative_Item
847                                 (Previous, Tree,
848                                  To => Next_Declarative_Item
849                                          (Declaration, Tree));
850                            end if;
851
852                         else
853                            Previous := Declaration;
854                         end if;
855                      end if;
856
857                      Declaration := Next_Declarative_Item (Declaration, Tree);
858                   end loop;
859                end;
860             end if;
861          end if;
862
863          if Directory_Last /= 0 then
864             Output_Name (1 .. Output_Name_Last - Directory_Last) :=
865               Output_Name (Directory_Last + 1 .. Output_Name_Last);
866             Output_Name_Last := Output_Name_Last - Directory_Last;
867          end if;
868
869          --  Get the project name id
870
871          Name_Len := Output_Name_Last;
872          Name_Buffer (1 .. Name_Len) := Output_Name (1 .. Name_Len);
873          Output_Name_Id := Name_Find;
874
875          --  Create the project naming file name
876
877          Project_Naming_Last := Output_Name_Last;
878          Project_Naming_File_Name (1 .. Project_Naming_Last) :=
879            Output_Name (1 .. Project_Naming_Last);
880          Project_Naming_File_Name
881            (Project_Naming_Last + 1 ..
882               Project_Naming_Last + Naming_File_Suffix'Length) :=
883            Naming_File_Suffix;
884          Project_Naming_Last :=
885            Project_Naming_Last + Naming_File_Suffix'Length;
886
887          --  Get the project naming id
888
889          Name_Len := Project_Naming_Last;
890          Name_Buffer (1 .. Name_Len) :=
891            Project_Naming_File_Name (1 .. Name_Len);
892          Project_Naming_Id := Name_Find;
893
894          Project_Naming_File_Name
895            (Project_Naming_Last + 1 ..
896               Project_Naming_Last + Project_File_Extension'Length) :=
897            Project_File_Extension;
898          Project_Naming_Last :=
899            Project_Naming_Last + Project_File_Extension'Length;
900
901          --  Create the source list file name
902
903          Source_List_Last := Output_Name_Last;
904          Source_List_Path (1 .. Source_List_Last) :=
905            Output_Name (1 .. Source_List_Last);
906          Source_List_Path
907            (Source_List_Last + 1 ..
908               Source_List_Last + Source_List_File_Suffix'Length) :=
909            Source_List_File_Suffix;
910          Source_List_Last := Source_List_Last + Source_List_File_Suffix'Length;
911
912          --  Add the project file extension to the project name
913
914          Output_Name
915            (Output_Name_Last + 1 ..
916               Output_Name_Last + Project_File_Extension'Length) :=
917            Project_File_Extension;
918          Output_Name_Last := Output_Name_Last + Project_File_Extension'Length;
919       end if;
920
921       --  Change the current directory to the directory of the project file,
922       --  if any directory information is specified.
923
924       if Directory_Last /= 0 then
925          begin
926             Change_Dir (Path_Name (1 .. Directory_Last));
927          exception
928             when Directory_Error =>
929                Prj.Com.Fail
930                  ("unknown directory """,
931                   Path_Name (1 .. Directory_Last),
932                   """");
933          end;
934       end if;
935
936       if Project_File then
937
938          --  Delete the source list file, if it already exists
939
940          declare
941             Discard : Boolean;
942          begin
943             Delete_File
944               (Source_List_Path (1 .. Source_List_Last),
945                Success => Discard);
946          end;
947
948          --  And create a new source list file.
949          --  Fail if file cannot be created.
950
951          Source_List_FD := Create_New_File
952            (Name  => Source_List_Path (1 .. Source_List_Last),
953             Fmode => Text);
954
955          if Source_List_FD = Invalid_FD then
956             Prj.Com.Fail
957               ("cannot create file """,
958                Source_List_Path (1 .. Source_List_Last),
959                """");
960          end if;
961       end if;
962
963       --  Compile the regular expressions. Fails immediately if any of
964       --  the specified strings is in error.
965
966       for Index in Excluded_Expressions'Range loop
967          if Very_Verbose then
968             Output.Write_Str ("Excluded pattern: """);
969             Output.Write_Str (Excluded_Patterns (Index).all);
970             Output.Write_Line ("""");
971          end if;
972
973          begin
974             Excluded_Expressions (Index) :=
975               Compile (Pattern => Excluded_Patterns (Index).all, Glob => True);
976          exception
977             when Error_In_Regexp =>
978                Prj.Com.Fail
979                  ("invalid regular expression """,
980                   Excluded_Patterns (Index).all,
981                   """");
982          end;
983       end loop;
984
985       for Index in Foreign_Expressions'Range loop
986          if Very_Verbose then
987             Output.Write_Str ("Foreign pattern: """);
988             Output.Write_Str (Foreign_Patterns (Index).all);
989             Output.Write_Line ("""");
990          end if;
991
992          begin
993             Foreign_Expressions (Index) :=
994               Compile (Pattern => Foreign_Patterns (Index).all, Glob => True);
995          exception
996             when Error_In_Regexp =>
997                Prj.Com.Fail
998                  ("invalid regular expression """,
999                   Foreign_Patterns (Index).all,
1000                   """");
1001          end;
1002       end loop;
1003
1004       for Index in Regular_Expressions'Range loop
1005          if Very_Verbose then
1006             Output.Write_Str ("Pattern: """);
1007             Output.Write_Str (Name_Patterns (Index).all);
1008             Output.Write_Line ("""");
1009          end if;
1010
1011          begin
1012             Regular_Expressions (Index) :=
1013               Compile (Pattern => Name_Patterns (Index).all, Glob => True);
1014
1015          exception
1016             when Error_In_Regexp =>
1017                Prj.Com.Fail
1018                  ("invalid regular expression """,
1019                   Name_Patterns (Index).all,
1020                   """");
1021          end;
1022       end loop;
1023
1024       if Project_File then
1025          if Opt.Verbose_Mode then
1026             Output.Write_Str ("Naming project file name is """);
1027             Output.Write_Str
1028               (Project_Naming_File_Name (1 .. Project_Naming_Last));
1029             Output.Write_Line ("""");
1030          end if;
1031
1032          --  If there were no already existing project file, or if the parsing
1033          --  was unsuccessful, create an empty project node with the correct
1034          --  name and its project declaration node.
1035
1036          if Project_Node = Empty_Node then
1037             Project_Node :=
1038               Default_Project_Node (Of_Kind => N_Project, In_Tree => Tree);
1039             Set_Name_Of (Project_Node, Tree, To => Output_Name_Id);
1040             Set_Project_Declaration_Of
1041               (Project_Node, Tree,
1042                To => Default_Project_Node
1043                  (Of_Kind => N_Project_Declaration, In_Tree => Tree));
1044
1045          end if;
1046
1047          --  Create the naming project node, and add an attribute declaration
1048          --  for Source_Files as an empty list, to indicate there are no
1049          --  sources in the naming project.
1050
1051          Project_Naming_Node :=
1052            Default_Project_Node (Of_Kind => N_Project, In_Tree => Tree);
1053          Set_Name_Of (Project_Naming_Node, Tree, To => Project_Naming_Id);
1054          Project_Naming_Decl :=
1055            Default_Project_Node
1056              (Of_Kind => N_Project_Declaration, In_Tree => Tree);
1057          Set_Project_Declaration_Of
1058            (Project_Naming_Node, Tree, Project_Naming_Decl);
1059          Naming_Package :=
1060            Default_Project_Node
1061              (Of_Kind => N_Package_Declaration, In_Tree => Tree);
1062          Set_Name_Of (Naming_Package, Tree, To => Name_Naming);
1063
1064          declare
1065             Decl_Item : constant Project_Node_Id :=
1066                           Default_Project_Node
1067                             (Of_Kind => N_Declarative_Item, In_Tree => Tree);
1068
1069             Attribute : constant Project_Node_Id :=
1070                           Default_Project_Node
1071                             (Of_Kind       => N_Attribute_Declaration,
1072                              In_Tree       => Tree,
1073                              And_Expr_Kind => List);
1074
1075             Expression : constant Project_Node_Id :=
1076                            Default_Project_Node
1077                              (Of_Kind       => N_Expression,
1078                               In_Tree       => Tree,
1079                               And_Expr_Kind => List);
1080
1081             Term      : constant Project_Node_Id :=
1082                           Default_Project_Node
1083                             (Of_Kind       => N_Term,
1084                              In_Tree       => Tree,
1085                              And_Expr_Kind => List);
1086
1087             Empty_List : constant Project_Node_Id :=
1088                            Default_Project_Node
1089                              (Of_Kind => N_Literal_String_List,
1090                               In_Tree => Tree);
1091
1092          begin
1093             Set_First_Declarative_Item_Of
1094               (Project_Naming_Decl, Tree, To => Decl_Item);
1095             Set_Next_Declarative_Item (Decl_Item, Tree, Naming_Package);
1096             Set_Current_Item_Node (Decl_Item, Tree, To => Attribute);
1097             Set_Name_Of (Attribute, Tree, To => Name_Source_Files);
1098             Set_Expression_Of (Attribute, Tree, To => Expression);
1099             Set_First_Term (Expression, Tree, To => Term);
1100             Set_Current_Term (Term, Tree, To => Empty_List);
1101          end;
1102
1103          --  Add a with clause on the naming project in the main project, if
1104          --  there is not already one.
1105
1106          declare
1107             With_Clause : Project_Node_Id :=
1108                                   First_With_Clause_Of (Project_Node, Tree);
1109
1110          begin
1111             while With_Clause /= Empty_Node loop
1112                exit when
1113                  Prj.Tree.Name_Of (With_Clause, Tree) = Project_Naming_Id;
1114                With_Clause := Next_With_Clause_Of (With_Clause, Tree);
1115             end loop;
1116
1117             if With_Clause = Empty_Node then
1118                With_Clause := Default_Project_Node
1119                  (Of_Kind => N_With_Clause, In_Tree => Tree);
1120                Set_Next_With_Clause_Of
1121                  (With_Clause, Tree,
1122                   To => First_With_Clause_Of (Project_Node, Tree));
1123                Set_First_With_Clause_Of
1124                  (Project_Node, Tree, To => With_Clause);
1125                Set_Name_Of (With_Clause, Tree, To => Project_Naming_Id);
1126
1127                --  We set the project node to something different than
1128                --  Empty_Node, so that Prj.PP does not generate a limited
1129                --  with clause.
1130
1131                Set_Project_Node_Of (With_Clause, Tree, Non_Empty_Node);
1132
1133                Name_Len := Project_Naming_Last;
1134                Name_Buffer (1 .. Name_Len) :=
1135                  Project_Naming_File_Name (1 .. Project_Naming_Last);
1136                Set_String_Value_Of (With_Clause, Tree, To => Name_Find);
1137             end if;
1138          end;
1139
1140          Project_Declaration := Project_Declaration_Of (Project_Node, Tree);
1141
1142          --  Add a renaming declaration for package Naming in the main project
1143
1144          declare
1145             Decl_Item  : constant Project_Node_Id :=
1146                            Default_Project_Node
1147                              (Of_Kind => N_Declarative_Item,
1148                               In_Tree => Tree);
1149
1150             Naming : constant Project_Node_Id :=
1151                            Default_Project_Node
1152                              (Of_Kind => N_Package_Declaration,
1153                               In_Tree => Tree);
1154
1155          begin
1156             Set_Next_Declarative_Item
1157               (Decl_Item, Tree,
1158                To => First_Declarative_Item_Of (Project_Declaration, Tree));
1159             Set_First_Declarative_Item_Of
1160               (Project_Declaration, Tree, To => Decl_Item);
1161             Set_Current_Item_Node (Decl_Item, Tree, To => Naming);
1162             Set_Name_Of (Naming, Tree, To => Name_Naming);
1163             Set_Project_Of_Renamed_Package_Of
1164               (Naming, Tree, To => Project_Naming_Node);
1165
1166             --  Attach the comments, if any, that were saved for package
1167             --  Naming.
1168
1169             Tree.Project_Nodes.Table (Naming).Comments :=
1170               Naming_Package_Comments;
1171          end;
1172
1173          --  Add an attribute declaration for Source_Dirs, initialized as an
1174          --  empty list. Directories will be added as they are read from the
1175          --  directory list file.
1176
1177          declare
1178             Decl_Item  : constant Project_Node_Id :=
1179                            Default_Project_Node
1180                              (Of_Kind => N_Declarative_Item,
1181                               In_Tree => Tree);
1182
1183             Attribute : constant Project_Node_Id :=
1184                            Default_Project_Node
1185                              (Of_Kind       => N_Attribute_Declaration,
1186                               In_Tree       => Tree,
1187                               And_Expr_Kind => List);
1188
1189             Expression : constant Project_Node_Id :=
1190                            Default_Project_Node
1191                              (Of_Kind       => N_Expression,
1192                               In_Tree       => Tree,
1193                               And_Expr_Kind => List);
1194
1195             Term  : constant Project_Node_Id :=
1196                            Default_Project_Node
1197                              (Of_Kind       => N_Term, In_Tree => Tree,
1198                               And_Expr_Kind => List);
1199
1200          begin
1201             Set_Next_Declarative_Item
1202               (Decl_Item, Tree,
1203                To => First_Declarative_Item_Of (Project_Declaration, Tree));
1204             Set_First_Declarative_Item_Of
1205               (Project_Declaration, Tree, To => Decl_Item);
1206             Set_Current_Item_Node (Decl_Item, Tree, To => Attribute);
1207             Set_Name_Of (Attribute, Tree, To => Name_Source_Dirs);
1208             Set_Expression_Of (Attribute, Tree, To => Expression);
1209             Set_First_Term (Expression, Tree, To => Term);
1210             Source_Dirs_List :=
1211               Default_Project_Node
1212                 (Of_Kind       => N_Literal_String_List,
1213                  In_Tree       => Tree,
1214                  And_Expr_Kind => List);
1215             Set_Current_Term (Term, Tree, To => Source_Dirs_List);
1216
1217             --  Attach the comments, if any, that were saved for attribute
1218             --  Source_Dirs.
1219
1220             Tree.Project_Nodes.Table (Attribute).Comments :=
1221               Source_Dirs_Comments;
1222          end;
1223
1224          --  Add an attribute declaration for Source_List_File with the
1225          --  source list file name that will be created.
1226
1227          declare
1228             Decl_Item  : constant Project_Node_Id :=
1229                            Default_Project_Node
1230                              (Of_Kind => N_Declarative_Item,
1231                               In_Tree => Tree);
1232
1233             Attribute  : constant Project_Node_Id :=
1234                             Default_Project_Node
1235                               (Of_Kind       => N_Attribute_Declaration,
1236                                In_Tree       => Tree,
1237                                And_Expr_Kind => Single);
1238
1239             Expression : constant Project_Node_Id :=
1240                            Default_Project_Node
1241                              (Of_Kind       => N_Expression,
1242                               In_Tree       => Tree,
1243                               And_Expr_Kind => Single);
1244
1245             Term       : constant Project_Node_Id :=
1246                            Default_Project_Node
1247                              (Of_Kind       => N_Term,
1248                               In_Tree       => Tree,
1249                               And_Expr_Kind => Single);
1250
1251             Value      : constant Project_Node_Id :=
1252                            Default_Project_Node
1253                              (Of_Kind       => N_Literal_String,
1254                               In_Tree       => Tree,
1255                               And_Expr_Kind => Single);
1256
1257          begin
1258             Set_Next_Declarative_Item
1259               (Decl_Item, Tree,
1260                To => First_Declarative_Item_Of (Project_Declaration, Tree));
1261             Set_First_Declarative_Item_Of
1262               (Project_Declaration, Tree, To => Decl_Item);
1263             Set_Current_Item_Node (Decl_Item, Tree, To => Attribute);
1264             Set_Name_Of (Attribute, Tree, To => Name_Source_List_File);
1265             Set_Expression_Of (Attribute, Tree, To => Expression);
1266             Set_First_Term (Expression, Tree, To => Term);
1267             Set_Current_Term (Term, Tree, To => Value);
1268             Name_Len := Source_List_Last;
1269             Name_Buffer (1 .. Name_Len) :=
1270               Source_List_Path (1 .. Source_List_Last);
1271             Set_String_Value_Of (Value, Tree, To => Name_Find);
1272
1273             --  If there was no comments for attribute Source_List_File, put
1274             --  those for Source_Files, if they exist.
1275
1276             if Source_List_File_Comments /= Empty_Node then
1277                Tree.Project_Nodes.Table (Attribute).Comments :=
1278                  Source_List_File_Comments;
1279             else
1280                Tree.Project_Nodes.Table (Attribute).Comments :=
1281                  Source_Files_Comments;
1282             end if;
1283          end;
1284       end if;
1285
1286       --  Process each directory
1287
1288       for Index in Directories'Range  loop
1289
1290          declare
1291             Dir_Name    : constant String := Directories (Index).all;
1292             Last        : Natural := Dir_Name'Last;
1293             Recursively : Boolean := False;
1294
1295          begin
1296             if Dir_Name'Length >= 4
1297               and then (Dir_Name (Last - 2 .. Last) = "/**")
1298             then
1299                Last := Last - 3;
1300                Recursively := True;
1301             end if;
1302
1303             if Project_File then
1304
1305                --  Add the directory in the list for attribute Source_Dirs
1306
1307                declare
1308                   Expression : constant Project_Node_Id :=
1309                                  Default_Project_Node
1310                                    (Of_Kind       => N_Expression,
1311                                     In_Tree       => Tree,
1312                                     And_Expr_Kind => Single);
1313
1314                   Term       : constant Project_Node_Id :=
1315                                  Default_Project_Node
1316                                    (Of_Kind       => N_Term,
1317                                     In_Tree       => Tree,
1318                                     And_Expr_Kind => Single);
1319
1320                   Value      : constant Project_Node_Id :=
1321                                  Default_Project_Node
1322                                    (Of_Kind       => N_Literal_String,
1323                                     In_Tree       => Tree,
1324                                     And_Expr_Kind => Single);
1325
1326                begin
1327                   if Current_Source_Dir = Empty_Node then
1328                      Set_First_Expression_In_List
1329                        (Source_Dirs_List, Tree, To => Expression);
1330                   else
1331                      Set_Next_Expression_In_List
1332                        (Current_Source_Dir, Tree, To => Expression);
1333                   end if;
1334
1335                   Current_Source_Dir := Expression;
1336                   Set_First_Term (Expression, Tree, To => Term);
1337                   Set_Current_Term (Term, Tree, To => Value);
1338                   Name_Len := Dir_Name'Length;
1339                   Name_Buffer (1 .. Name_Len) := Dir_Name;
1340                   Set_String_Value_Of (Value, Tree, To => Name_Find);
1341                end;
1342             end if;
1343
1344             Process_Directory (Dir_Name (Dir_Name'First .. Last), Recursively);
1345          end;
1346
1347       end loop;
1348
1349       if Project_File then
1350          Close (Source_List_FD);
1351       end if;
1352
1353       declare
1354          Discard : Boolean;
1355
1356       begin
1357          --  Delete the file if it already exists
1358
1359          Delete_File
1360            (Path_Name (Directory_Last + 1 .. Path_Last),
1361             Success => Discard);
1362
1363          --  Create a new one
1364
1365          if Opt.Verbose_Mode then
1366             Output.Write_Str ("Creating new file """);
1367             Output.Write_Str (Path_Name (Directory_Last + 1 .. Path_Last));
1368             Output.Write_Line ("""");
1369          end if;
1370
1371          Output_FD := Create_New_File
1372            (Path_Name (Directory_Last + 1 .. Path_Last),
1373             Fmode => Text);
1374
1375          --  Fails if project file cannot be created
1376
1377          if Output_FD = Invalid_FD then
1378             Prj.Com.Fail
1379               ("cannot create new """, Path_Name (1 .. Path_Last), """");
1380          end if;
1381
1382          if Project_File then
1383
1384             --  Output the project file
1385
1386             Prj.PP.Pretty_Print
1387               (Project_Node, Tree,
1388                W_Char => Write_A_Char'Access,
1389                W_Eol  => Write_Eol'Access,
1390                W_Str  => Write_A_String'Access,
1391                Backward_Compatibility => False);
1392             Close (Output_FD);
1393
1394             --  Delete the naming project file if it already exists
1395
1396             Delete_File
1397               (Project_Naming_File_Name (1 .. Project_Naming_Last),
1398                Success => Discard);
1399
1400             --  Create a new one
1401
1402             if Opt.Verbose_Mode then
1403                Output.Write_Str ("Creating new naming project file """);
1404                Output.Write_Str (Project_Naming_File_Name
1405                                    (1 .. Project_Naming_Last));
1406                Output.Write_Line ("""");
1407             end if;
1408
1409             Output_FD := Create_New_File
1410               (Project_Naming_File_Name (1 .. Project_Naming_Last),
1411                Fmode => Text);
1412
1413             --  Fails if naming project file cannot be created
1414
1415             if Output_FD = Invalid_FD then
1416                Prj.Com.Fail
1417                  ("cannot create new """,
1418                   Project_Naming_File_Name (1 .. Project_Naming_Last),
1419                   """");
1420             end if;
1421
1422             --  Output the naming project file
1423
1424             Prj.PP.Pretty_Print
1425               (Project_Naming_Node, Tree,
1426                W_Char => Write_A_Char'Access,
1427                W_Eol  => Write_Eol'Access,
1428                W_Str  => Write_A_String'Access,
1429                Backward_Compatibility => False);
1430             Close (Output_FD);
1431
1432          else
1433             --  Write to the output file each entry in the SFN_Pragmas table
1434             --  as an pragma Source_File_Name.
1435
1436             for Index in 1 .. SFN_Pragmas.Last loop
1437                Write_A_String ("pragma Source_File_Name");
1438                Write_Eol;
1439                Write_A_String ("  (");
1440                Write_A_String
1441                  (Get_Name_String (SFN_Pragmas.Table (Index).Unit));
1442                Write_A_String (",");
1443                Write_Eol;
1444
1445                if SFN_Pragmas.Table (Index).Spec then
1446                   Write_A_String ("   Spec_File_Name => """);
1447
1448                else
1449                   Write_A_String ("   Body_File_Name => """);
1450                end if;
1451
1452                Write_A_String
1453                  (Get_Name_String (SFN_Pragmas.Table (Index).File));
1454
1455                Write_A_String ("""");
1456
1457                if SFN_Pragmas.Table (Index).Index /= 0 then
1458                   Write_A_String (", Index =>");
1459                   Write_A_String (SFN_Pragmas.Table (Index).Index'Img);
1460                end if;
1461
1462                Write_A_String (");");
1463                Write_Eol;
1464             end loop;
1465
1466             Close (Output_FD);
1467          end if;
1468       end;
1469
1470    end Make;
1471
1472    ----------------
1473    -- Write_Char --
1474    ----------------
1475    procedure Write_A_Char (C : Character) is
1476    begin
1477       Write_A_String ((1 => C));
1478    end Write_A_Char;
1479
1480    ---------------
1481    -- Write_Eol --
1482    ---------------
1483
1484    procedure Write_Eol is
1485    begin
1486       Write_A_String ((1 => ASCII.LF));
1487    end Write_Eol;
1488
1489    --------------------
1490    -- Write_A_String --
1491    --------------------
1492
1493    procedure Write_A_String (S : String) is
1494       Str : String (1 .. S'Length);
1495
1496    begin
1497       if S'Length > 0 then
1498          Str := S;
1499
1500          if Write (Output_FD, Str (1)'Address, Str'Length) /= Str'Length then
1501             Prj.Com.Fail ("disk full");
1502          end if;
1503       end if;
1504    end Write_A_String;
1505
1506 end Prj.Makr;