OSDN Git Service

Add Fariborz to my last change.
[pf3gnuchains/gcc-fork.git] / gcc / ada / gnatls.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                               G N A T L S                                --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --           Copyright (C) 1992-2004 Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, USA.                                                      --
21 --                                                                          --
22 -- GNAT was originally developed  by the GNAT team at  New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
24 --                                                                          --
25 ------------------------------------------------------------------------------
26
27 with ALI;         use ALI;
28 with ALI.Util;    use ALI.Util;
29 with Binderr;     use Binderr;
30 with Butil;       use Butil;
31 with Csets;       use Csets;
32 with Fname;       use Fname;
33 with Gnatvsn;     use Gnatvsn;
34 with GNAT.OS_Lib; use GNAT.OS_Lib;
35 with Namet;       use Namet;
36 with Opt;         use Opt;
37 with Osint;       use Osint;
38 with Osint.L;     use Osint.L;
39 with Output;      use Output;
40 with Rident;      use Rident;
41 with Snames;
42 with Targparm;    use Targparm;
43 with Types;       use Types;
44
45 with GNAT.Case_Util; use GNAT.Case_Util;
46
47 procedure Gnatls is
48    pragma Ident (Gnat_Static_Version_String);
49
50    Max_Column : constant := 80;
51
52    No_Obj : aliased String := "<no_obj>";
53
54    type File_Status is (
55      OK,                  --  matching timestamp
56      Checksum_OK,         --  only matching checksum
57      Not_Found,           --  file not found on source PATH
58      Not_Same,            --  neither checksum nor timestamp matching
59      Not_First_On_PATH);  --  matching file hidden by Not_Same file on path
60
61    type Dir_Data;
62    type Dir_Ref is access Dir_Data;
63
64    type Dir_Data is record
65       Value : String_Access;
66       Next  : Dir_Ref;
67    end record;
68    --  ??? comment needed
69
70    First_Source_Dir : Dir_Ref;
71    Last_Source_Dir  : Dir_Ref;
72    --  The list of source directories from the command line.
73    --  These directories are added using Osint.Add_Src_Search_Dir
74    --  after those of the GNAT Project File, if any.
75
76    First_Lib_Dir : Dir_Ref;
77    Last_Lib_Dir  : Dir_Ref;
78    --  The list of object directories from the command line.
79    --  These directories are added using Osint.Add_Lib_Search_Dir
80    --  after those of the GNAT Project File, if any.
81
82    Main_File : File_Name_Type;
83    Ali_File  : File_Name_Type;
84    Text      : Text_Buffer_Ptr;
85    Next_Arg  : Positive;
86
87    Too_Long : Boolean := False;
88    --  When True, lines are too long for multi-column output and each
89    --  item of information is on a different line.
90
91    Selective_Output : Boolean := False;
92    Print_Usage      : Boolean := False;
93    Print_Unit       : Boolean := True;
94    Print_Source     : Boolean := True;
95    Print_Object     : Boolean := True;
96    --  Flags controlling the form of the output
97
98    Dependable  : Boolean := False;  --  flag -d
99    Also_Predef : Boolean := False;
100
101    Unit_Start   : Integer;
102    Unit_End     : Integer;
103    Source_Start : Integer;
104    Source_End   : Integer;
105    Object_Start : Integer;
106    Object_End   : Integer;
107    --  Various column starts and ends
108
109    Spaces : constant String (1 .. Max_Column) := (others => ' ');
110
111    RTS_Specified : String_Access := null;
112    --  Used to detect multiple use of --RTS= switch
113
114    -----------------------
115    -- Local Subprograms --
116    -----------------------
117
118    procedure Add_Lib_Dir (Dir : String);
119    --  Add an object directory in the list First_Lib_Dir-Last_Lib_Dir
120
121    procedure Add_Source_Dir (Dir : String);
122    --  Add a source directory in the list First_Source_Dir-Last_Source_Dir
123
124    procedure Find_General_Layout;
125    --  Determine the structure of the output (multi columns or not, etc)
126
127    procedure Find_Status
128      (FS       : in out File_Name_Type;
129       Stamp    : Time_Stamp_Type;
130       Checksum : Word;
131       Status   : out File_Status);
132    --  Determine the file status (Status) of the file represented by FS
133    --  with the expected Stamp and checksum given as argument. FS will be
134    --  updated to the full file name if available.
135
136    function Corresponding_Sdep_Entry (A : ALI_Id; U : Unit_Id) return Sdep_Id;
137    --  Give the Sdep entry corresponding to the unit U in ali record A
138
139    procedure Output_Object (O : File_Name_Type);
140    --  Print out the name of the object when requested
141
142    procedure Output_Source (Sdep_I : Sdep_Id);
143    --  Print out the name and status of the source corresponding to this
144    --  sdep entry.
145
146    procedure Output_Status (FS : File_Status; Verbose : Boolean);
147    --  Print out FS either in a coded form if verbose is false or in an
148    --  expanded form otherwise.
149
150    procedure Output_Unit (ALI : ALI_Id; U_Id : Unit_Id);
151    --  Print out information on the unit when requested
152
153    procedure Reset_Print;
154    --  Reset Print flags properly when selective output is chosen
155
156    procedure Scan_Ls_Arg (Argv : String);
157    --  Scan and process lser specific arguments. Argv is a single argument
158
159    procedure Usage;
160    --  Print usage message
161
162    function Image (Restriction : Restriction_Id) return String;
163    --  Returns the capitalized image of Restriction
164
165    -----------------
166    -- Add_Lib_Dir --
167    -----------------
168
169    procedure Add_Lib_Dir (Dir : String) is
170    begin
171       if First_Lib_Dir = null then
172          First_Lib_Dir :=
173            new Dir_Data'
174              (Value => new String'(Dir),
175               Next  => null);
176          Last_Lib_Dir := First_Lib_Dir;
177
178       else
179          Last_Lib_Dir.Next :=
180            new Dir_Data'
181              (Value => new String'(Dir),
182               Next  => null);
183          Last_Lib_Dir := Last_Lib_Dir.Next;
184       end if;
185    end Add_Lib_Dir;
186
187    -- -----------------
188    -- Add_Source_Dir --
189    --------------------
190
191    procedure Add_Source_Dir (Dir : String) is
192    begin
193       if First_Source_Dir = null then
194          First_Source_Dir :=
195            new Dir_Data'
196              (Value => new String'(Dir),
197               Next  => null);
198          Last_Source_Dir := First_Source_Dir;
199
200       else
201          Last_Source_Dir.Next :=
202            new Dir_Data'
203              (Value => new String'(Dir),
204               Next  => null);
205          Last_Source_Dir := Last_Source_Dir.Next;
206       end if;
207    end Add_Source_Dir;
208
209    ------------------------------
210    -- Corresponding_Sdep_Entry --
211    ------------------------------
212
213    function Corresponding_Sdep_Entry
214      (A : ALI_Id;
215       U : Unit_Id) return Sdep_Id
216    is
217    begin
218       for D in ALIs.Table (A).First_Sdep .. ALIs.Table (A).Last_Sdep loop
219          if Sdep.Table (D).Sfile = Units.Table (U).Sfile then
220             return D;
221          end if;
222       end loop;
223
224       Error_Msg_Name_1 := Units.Table (U).Uname;
225       Error_Msg_Name_2 := ALIs.Table (A).Afile;
226       Write_Eol;
227       Error_Msg ("wrong ALI format, can't find dependency line for & in %");
228       Exit_Program (E_Fatal);
229    end Corresponding_Sdep_Entry;
230
231    -------------------------
232    -- Find_General_Layout --
233    -------------------------
234
235    procedure Find_General_Layout is
236       Max_Unit_Length : Integer := 11;
237       Max_Src_Length  : Integer := 11;
238       Max_Obj_Length  : Integer := 11;
239
240       Len : Integer;
241       FS  : File_Name_Type;
242
243    begin
244       --  Compute maximum of each column
245
246       for Id in ALIs.First .. ALIs.Last loop
247          Get_Name_String (Units.Table (ALIs.Table (Id).First_Unit).Uname);
248          if Also_Predef or else not Is_Internal_Unit then
249
250             if Print_Unit then
251                Len := Name_Len - 1;
252                Max_Unit_Length := Integer'Max (Max_Unit_Length, Len);
253             end if;
254
255             if Print_Source then
256                FS := Full_Source_Name (ALIs.Table (Id).Sfile);
257
258                if FS = No_File then
259                   Get_Name_String (ALIs.Table (Id).Sfile);
260                   Name_Len := Name_Len + 13;
261                else
262                   Get_Name_String (FS);
263                end if;
264
265                Max_Src_Length := Integer'Max (Max_Src_Length, Name_Len + 1);
266             end if;
267
268             if Print_Object then
269                if ALIs.Table (Id).No_Object then
270                   Max_Obj_Length :=
271                     Integer'Max (Max_Obj_Length, No_Obj'Length);
272                else
273                   Get_Name_String (ALIs.Table (Id).Ofile_Full_Name);
274                   Max_Obj_Length := Integer'Max (Max_Obj_Length, Name_Len + 1);
275                end if;
276             end if;
277          end if;
278       end loop;
279
280       --  Verify is output is not wider than maximum number of columns
281
282       Too_Long :=
283         Verbose_Mode
284           or else
285             (Max_Unit_Length + Max_Src_Length + Max_Obj_Length) > Max_Column;
286
287       --  Set start and end of columns
288
289       Object_Start := 1;
290       Object_End   := Object_Start - 1;
291
292       if Print_Object then
293          Object_End   := Object_Start + Max_Obj_Length;
294       end if;
295
296       Unit_Start := Object_End + 1;
297       Unit_End   := Unit_Start - 1;
298
299       if Print_Unit then
300          Unit_End   := Unit_Start + Max_Unit_Length;
301       end if;
302
303       Source_Start := Unit_End + 1;
304
305       if Source_Start > Spaces'Last then
306          Source_Start := Spaces'Last;
307       end if;
308
309       Source_End := Source_Start - 1;
310
311       if Print_Source then
312          Source_End   := Source_Start + Max_Src_Length;
313       end if;
314    end Find_General_Layout;
315
316    -----------------
317    -- Find_Status --
318    -----------------
319
320    procedure Find_Status
321      (FS       : in out File_Name_Type;
322       Stamp    : Time_Stamp_Type;
323       Checksum : Word;
324       Status   : out File_Status)
325    is
326       Tmp1 : File_Name_Type;
327       Tmp2 : File_Name_Type;
328
329    begin
330       Tmp1 := Full_Source_Name (FS);
331
332       if Tmp1 = No_File then
333          Status := Not_Found;
334
335       elsif File_Stamp (Tmp1) = Stamp then
336          FS     := Tmp1;
337          Status := OK;
338
339       elsif Checksums_Match (Get_File_Checksum (FS), Checksum) then
340          FS := Tmp1;
341          Status := Checksum_OK;
342
343       else
344          Tmp2 := Matching_Full_Source_Name (FS, Stamp);
345
346          if Tmp2 = No_File then
347             Status := Not_Same;
348             FS     := Tmp1;
349
350          else
351             Status := Not_First_On_PATH;
352             FS := Tmp2;
353          end if;
354       end if;
355    end Find_Status;
356
357    -----------
358    -- Image --
359    -----------
360
361    function Image (Restriction : Restriction_Id) return String is
362       Result : String := Restriction'Img;
363       Skip   : Boolean := True;
364
365    begin
366       for J in Result'Range loop
367          if Skip then
368             Skip := False;
369             Result (J) := To_Upper (Result (J));
370
371          elsif Result (J) = '_' then
372             Skip := True;
373
374          else
375             Result (J) := To_Lower (Result (J));
376          end if;
377       end loop;
378
379       return Result;
380    end Image;
381
382    -------------------
383    -- Output_Object --
384    -------------------
385
386    procedure Output_Object (O : File_Name_Type) is
387       Object_Name : String_Access;
388
389    begin
390       if Print_Object then
391          if O /= No_File then
392             Get_Name_String (O);
393             Object_Name := To_Host_File_Spec (Name_Buffer (1 .. Name_Len));
394          else
395             Object_Name := No_Obj'Unchecked_Access;
396          end if;
397
398          Write_Str (Object_Name.all);
399
400          if Print_Source or else Print_Unit then
401             if Too_Long then
402                Write_Eol;
403                Write_Str ("   ");
404             else
405                Write_Str (Spaces
406                 (Object_Start + Object_Name'Length .. Object_End));
407             end if;
408          end if;
409       end if;
410    end Output_Object;
411
412    -------------------
413    -- Output_Source --
414    -------------------
415
416    procedure Output_Source (Sdep_I : Sdep_Id) is
417       Stamp       : constant Time_Stamp_Type := Sdep.Table (Sdep_I).Stamp;
418       Checksum    : constant Word            := Sdep.Table (Sdep_I).Checksum;
419       FS          : File_Name_Type           := Sdep.Table (Sdep_I).Sfile;
420       Status      : File_Status;
421       Object_Name : String_Access;
422
423    begin
424       if Print_Source then
425          Find_Status (FS, Stamp, Checksum, Status);
426          Get_Name_String (FS);
427
428          Object_Name := To_Host_File_Spec (Name_Buffer (1 .. Name_Len));
429
430          if Verbose_Mode then
431             Write_Str ("  Source => ");
432             Write_Str (Object_Name.all);
433
434             if not Too_Long then
435                Write_Str
436                  (Spaces (Source_Start + Object_Name'Length .. Source_End));
437             end if;
438
439             Output_Status (Status, Verbose => True);
440             Write_Eol;
441             Write_Str ("   ");
442
443          else
444             if not Selective_Output then
445                Output_Status (Status, Verbose => False);
446             end if;
447
448             Write_Str (Object_Name.all);
449          end if;
450       end if;
451    end Output_Source;
452
453    -------------------
454    -- Output_Status --
455    -------------------
456
457    procedure Output_Status (FS : File_Status; Verbose : Boolean) is
458    begin
459       if Verbose then
460          case FS is
461             when OK =>
462                Write_Str (" unchanged");
463
464             when Checksum_OK =>
465                Write_Str (" slightly modified");
466
467             when Not_Found =>
468                Write_Str (" file not found");
469
470             when Not_Same =>
471                Write_Str (" modified");
472
473             when Not_First_On_PATH =>
474                Write_Str (" unchanged version not first on PATH");
475          end case;
476
477       else
478          case FS is
479             when OK =>
480                Write_Str ("  OK ");
481
482             when Checksum_OK =>
483                Write_Str (" MOK ");
484
485             when Not_Found =>
486                Write_Str (" ??? ");
487
488             when Not_Same =>
489                Write_Str (" DIF ");
490
491             when Not_First_On_PATH =>
492                Write_Str (" HID ");
493          end case;
494       end if;
495    end Output_Status;
496
497    -----------------
498    -- Output_Unit --
499    -----------------
500
501    procedure Output_Unit (ALI : ALI_Id; U_Id : Unit_Id) is
502       Kind : Character;
503       U    : Unit_Record renames Units.Table (U_Id);
504
505    begin
506       if Print_Unit then
507          Get_Name_String (U.Uname);
508          Kind := Name_Buffer (Name_Len);
509          Name_Len := Name_Len - 2;
510
511          if not Verbose_Mode then
512             Write_Str (Name_Buffer (1 .. Name_Len));
513
514          else
515             Write_Str ("Unit => ");
516             Write_Eol; Write_Str ("     Name   => ");
517             Write_Str (Name_Buffer (1 .. Name_Len));
518             Write_Eol; Write_Str ("     Kind   => ");
519
520             if Units.Table (U_Id).Unit_Kind = 'p' then
521                Write_Str ("package ");
522             else
523                Write_Str ("subprogram ");
524             end if;
525
526             if Kind = 's' then
527                Write_Str ("spec");
528             else
529                Write_Str ("body");
530             end if;
531          end if;
532
533          if Verbose_Mode then
534             if U.Preelab             or
535                U.No_Elab             or
536                U.Pure                or
537                U.Dynamic_Elab        or
538                U.Has_RACW            or
539                U.Remote_Types        or
540                U.Shared_Passive      or
541                U.RCI                 or
542                U.Predefined          or
543                U.Internal            or
544                U.Is_Generic          or
545                U.Init_Scalars        or
546                U.Interface           or
547                U.Body_Needed_For_SAL or
548                U.Elaborate_Body
549             then
550                Write_Eol; Write_Str ("     Flags  =>");
551
552                if U.Preelab then
553                   Write_Str (" Preelaborable");
554                end if;
555
556                if U.No_Elab then
557                   Write_Str (" No_Elab_Code");
558                end if;
559
560                if U.Pure then
561                   Write_Str (" Pure");
562                end if;
563
564                if U.Dynamic_Elab then
565                   Write_Str (" Dynamic_Elab");
566                end if;
567
568                if U.Has_RACW then
569                   Write_Str (" Has_RACW");
570                end if;
571
572                if U.Remote_Types then
573                   Write_Str (" Remote_Types");
574                end if;
575
576                if U.Shared_Passive then
577                   Write_Str (" Shared_Passive");
578                end if;
579
580                if U.RCI then
581                   Write_Str (" RCI");
582                end if;
583
584                if U.Predefined then
585                   Write_Str (" Predefined");
586                end if;
587
588                if U.Internal then
589                   Write_Str (" Internal");
590                end if;
591
592                if U.Is_Generic then
593                   Write_Str (" Is_Generic");
594                end if;
595
596                if U.Init_Scalars then
597                   Write_Str (" Init_Scalars");
598                end if;
599
600                if U.Interface then
601                   Write_Str (" Interface");
602                end if;
603
604                if U.Body_Needed_For_SAL then
605                   Write_Str (" Body_Needed_For_SAL");
606                end if;
607
608                if U.Elaborate_Body then
609                   Write_Str (" Elaborate Body");
610                end if;
611
612                if U.Remote_Types then
613                   Write_Str (" Remote_Types");
614                end if;
615
616                if U.Shared_Passive then
617                   Write_Str (" Shared_Passive");
618                end if;
619
620                if U.Predefined then
621                   Write_Str (" Predefined");
622                end if;
623
624             end if;
625
626             declare
627                Restrictions : constant Restrictions_Info :=
628                                 ALIs.Table (ALI).Restrictions;
629             begin
630                --  If the source was compiled with pragmas Restrictions,
631                --  Display these restrictions.
632
633                if Restrictions.Set /= (All_Restrictions => False) then
634                   Write_Eol; Write_Str ("     Restrictions  =>");
635
636                   --  For boolean restrictions, just display the name of the
637                   --  restriction; for valued restrictions, also display the
638                   --  restriction value.
639
640                   for Restriction in All_Restrictions loop
641                      if Restrictions.Set (Restriction) then
642                         Write_Eol;
643                         Write_Str ("       ");
644                         Write_Str (Image (Restriction));
645
646                         if Restriction in All_Parameter_Restrictions then
647                            Write_Str (" =>");
648                            Write_Str (Restrictions.Value (Restriction)'Img);
649                         end if;
650                      end if;
651                   end loop;
652                end if;
653             end;
654          end if;
655
656          if Print_Source then
657             if Too_Long then
658                Write_Eol; Write_Str ("   ");
659             else
660                Write_Str (Spaces (Unit_Start + Name_Len + 1 .. Unit_End));
661             end if;
662          end if;
663       end if;
664    end Output_Unit;
665
666    -----------------
667    -- Reset_Print --
668    -----------------
669
670    procedure Reset_Print is
671    begin
672       if not Selective_Output then
673          Selective_Output := True;
674          Print_Source := False;
675          Print_Object := False;
676          Print_Unit   := False;
677       end if;
678    end Reset_Print;
679
680    -------------------
681    -- Scan_Ls_Arg --
682    -------------------
683
684    procedure Scan_Ls_Arg (Argv : String) is
685       FD  : File_Descriptor;
686       Len : Integer;
687    begin
688       pragma Assert (Argv'First = 1);
689
690       if Argv'Length = 0 then
691          return;
692       end if;
693
694       if Argv (1) = '-' then
695
696          if Argv'Length = 1 then
697             Fail ("switch character cannot be followed by a blank");
698
699          --  Processing for -I-
700
701          elsif Argv (2 .. Argv'Last) = "I-" then
702             Opt.Look_In_Primary_Dir := False;
703
704          --  Forbid -?- or -??- where ? is any character
705
706          elsif (Argv'Length = 3 and then Argv (3) = '-')
707            or else (Argv'Length = 4 and then Argv (4) = '-')
708          then
709             Fail ("Trailing ""-"" at the end of ", Argv, " forbidden.");
710
711          --  Processing for -Idir
712
713          elsif Argv (2) = 'I' then
714             Add_Source_Dir (Argv (3 .. Argv'Last));
715             Add_Lib_Dir (Argv (3 .. Argv'Last));
716
717          --  Processing for -aIdir (to gcc this is like a -I switch)
718
719          elsif Argv'Length >= 3 and then Argv (2 .. 3) = "aI" then
720             Add_Source_Dir (Argv (4 .. Argv'Last));
721
722          --  Processing for -aOdir
723
724          elsif Argv'Length >= 3 and then Argv (2 .. 3) = "aO" then
725             Add_Lib_Dir (Argv (4 .. Argv'Last));
726
727          --  Processing for -aLdir (to gnatbind this is like a -aO switch)
728
729          elsif Argv'Length >= 3 and then Argv (2 .. 3) = "aL" then
730             Add_Lib_Dir (Argv (4 .. Argv'Last));
731
732          --  Processing for -nostdinc
733
734          elsif Argv (2 .. Argv'Last) = "nostdinc" then
735             Opt.No_Stdinc := True;
736
737          --  Processing for one character switches
738
739          elsif Argv'Length = 2 then
740             case Argv (2) is
741                when 'a' => Also_Predef               := True;
742                when 'h' => Print_Usage               := True;
743                when 'u' => Reset_Print; Print_Unit   := True;
744                when 's' => Reset_Print; Print_Source := True;
745                when 'o' => Reset_Print; Print_Object := True;
746                when 'v' => Verbose_Mode              := True;
747                when 'd' => Dependable                := True;
748
749                when others => null;
750             end case;
751
752          --  Processing for -files=file
753
754          elsif Argv'Length > 7 and then Argv (1 .. 7) = "-files=" then
755             FD := Open_Read (Argv (8 .. Argv'Last), GNAT.OS_Lib.Text);
756
757             if FD = Invalid_FD then
758                Osint.Fail ("could not find text file """ &
759                            Argv (8 .. Argv'Last) & '"');
760             end if;
761
762             Len := Integer (File_Length (FD));
763
764             declare
765                Buffer : String (1 .. Len + 1);
766                Index  : Positive := 1;
767                Last   : Positive;
768
769             begin
770                --  Read the file
771
772                Len := Read (FD, Buffer (1)'Address, Len);
773                Buffer (Buffer'Last) := ASCII.NUL;
774                Close (FD);
775
776                --  Scan the file line by line
777
778                while Index < Buffer'Last loop
779                   --  Find the end of line
780
781                   Last := Index;
782
783                   while Last <= Buffer'Last
784                     and then Buffer (Last) /= ASCII.LF
785                     and then Buffer (Last) /= ASCII.CR
786                   loop
787                      Last := Last + 1;
788                   end loop;
789
790                   --  Ignore empty lines
791
792                   if Last > Index then
793                      Add_File (Buffer (Index .. Last - 1));
794                   end if;
795
796                   Index := Last;
797
798                   --  Find the beginning of the next line
799
800                   while Buffer (Index) = ASCII.CR or else
801                         Buffer (Index) = ASCII.LF
802                   loop
803                      Index := Index + 1;
804                   end loop;
805                end loop;
806             end;
807
808          --  Processing for --RTS=path
809
810          elsif Argv'Length >= 5 and then Argv (1 .. 5) = "--RTS" then
811             if Argv'Length <= 6 or else Argv (6) /= '='then
812                Osint.Fail ("missing path for --RTS");
813
814             else
815                --  Check that it is the first time we see this switch or, if
816                --  it is not the first time, the same path is specified.
817
818                if RTS_Specified = null then
819                   RTS_Specified := new String'(Argv (7 .. Argv'Last));
820
821                elsif RTS_Specified.all /= Argv (7 .. Argv'Last) then
822                   Osint.Fail ("--RTS cannot be specified multiple times");
823                end if;
824
825                --  Valid --RTS switch
826
827                Opt.No_Stdinc := True;
828                Opt.RTS_Switch := True;
829
830                declare
831                   Src_Path_Name : constant String_Ptr :=
832                                     String_Ptr
833                                       (Get_RTS_Search_Dir
834                                         (Argv (7 .. Argv'Last), Include));
835                   Lib_Path_Name : constant String_Ptr :=
836                                     String_Ptr
837                                       (Get_RTS_Search_Dir
838                                         (Argv (7 .. Argv'Last), Objects));
839
840                begin
841                   if Src_Path_Name /= null
842                     and then Lib_Path_Name /= null
843                   then
844                      Add_Search_Dirs (Src_Path_Name, Include);
845                      Add_Search_Dirs (Lib_Path_Name, Objects);
846
847                   elsif Src_Path_Name = null
848                     and then Lib_Path_Name = null
849                   then
850                      Osint.Fail ("RTS path not valid: missing " &
851                                  "adainclude and adalib directories");
852
853                   elsif Src_Path_Name = null then
854                      Osint.Fail ("RTS path not valid: missing " &
855                                  "adainclude directory");
856
857                   elsif Lib_Path_Name = null then
858                      Osint.Fail ("RTS path not valid: missing " &
859                                  "adalib directory");
860                   end if;
861                end;
862             end if;
863          end if;
864
865       --  If not a switch, it must be a file name
866
867       else
868          Add_File (Argv);
869       end if;
870    end Scan_Ls_Arg;
871
872    -----------
873    -- Usage --
874    -----------
875
876    procedure Usage is
877
878    --  Start of processing for Usage
879
880    begin
881       --  Usage line
882
883       Write_Str ("Usage: ");
884       Osint.Write_Program_Name;
885       Write_Str ("  switches  [list of object files]");
886       Write_Eol;
887       Write_Eol;
888
889       --  GNATLS switches
890
891       Write_Str ("switches:");
892       Write_Eol;
893
894       --  Line for -a
895
896       Write_Str ("  -a         also output relevant predefined units");
897       Write_Eol;
898
899       --  Line for -u
900
901       Write_Str ("  -u         output only relevant unit names");
902       Write_Eol;
903
904       --  Line for -h
905
906       Write_Str ("  -h         output this help message");
907       Write_Eol;
908
909       --  Line for -s
910
911       Write_Str ("  -s         output only relevant source names");
912       Write_Eol;
913
914       --  Line for -o
915
916       Write_Str ("  -o         output only relevant object names");
917       Write_Eol;
918
919       --  Line for -d
920
921       Write_Str ("  -d         output sources on which specified units " &
922                                "depend");
923       Write_Eol;
924
925       --  Line for -v
926
927       Write_Str ("  -v         verbose output, full path and unit " &
928                                "information");
929       Write_Eol;
930       Write_Eol;
931
932       --  Line for -files=
933
934       Write_Str ("  -files=fil files are listed in text file 'fil'");
935       Write_Eol;
936
937       --  Line for -aI switch
938
939       Write_Str ("  -aIdir     specify source files search path");
940       Write_Eol;
941
942       --  Line for -aO switch
943
944       Write_Str ("  -aOdir     specify object files search path");
945       Write_Eol;
946
947       --  Line for -I switch
948
949       Write_Str ("  -Idir      like -aIdir -aOdir");
950       Write_Eol;
951
952       --  Line for -I- switch
953
954       Write_Str ("  -I-        do not look for sources & object files");
955       Write_Str (" in the default directory");
956       Write_Eol;
957
958       --  Line for -nostdinc
959
960       Write_Str ("  -nostdinc  do not look for source files");
961       Write_Str (" in the system default directory");
962       Write_Eol;
963
964       --  Line for --RTS
965
966       Write_Str ("  --RTS=dir  specify the default source and object search"
967                  & " path");
968       Write_Eol;
969
970       --  File Status explanation
971
972       Write_Eol;
973       Write_Str (" file status can be:");
974       Write_Eol;
975
976       for ST in File_Status loop
977          Write_Str ("   ");
978          Output_Status (ST, Verbose => False);
979          Write_Str (" ==> ");
980          Output_Status (ST, Verbose => True);
981          Write_Eol;
982       end loop;
983
984    end Usage;
985
986    --   Start of processing for Gnatls
987
988 begin
989    --  Initialize standard packages
990
991    Namet.Initialize;
992    Csets.Initialize;
993    Snames.Initialize;
994
995    --  Loop to scan out arguments
996
997    Next_Arg := 1;
998    Scan_Args : while Next_Arg < Arg_Count loop
999       declare
1000          Next_Argv : String (1 .. Len_Arg (Next_Arg));
1001       begin
1002          Fill_Arg (Next_Argv'Address, Next_Arg);
1003          Scan_Ls_Arg (Next_Argv);
1004       end;
1005
1006       Next_Arg := Next_Arg + 1;
1007    end loop Scan_Args;
1008
1009    --  Add the source and object directories specified on the
1010    --  command line, if any, to the searched directories.
1011
1012    while First_Source_Dir /= null loop
1013       Add_Src_Search_Dir (First_Source_Dir.Value.all);
1014       First_Source_Dir := First_Source_Dir.Next;
1015    end loop;
1016
1017    while First_Lib_Dir /= null loop
1018       Add_Lib_Search_Dir (First_Lib_Dir.Value.all);
1019       First_Lib_Dir := First_Lib_Dir.Next;
1020    end loop;
1021
1022    --  Finally, add the default directories and obtain target parameters
1023
1024    Osint.Add_Default_Search_Dirs;
1025
1026    if Verbose_Mode then
1027       Targparm.Get_Target_Parameters;
1028
1029       --  WARNING: the output of gnatls -v is used during the compilation
1030       --  and installation of GLADE to recreate sdefault.adb and locate
1031       --  the libgnat.a to use. Any change in the output of gnatls -v must
1032       --  be synchronized with the GLADE Dist/config.sdefault shell script.
1033
1034       Write_Eol;
1035       Write_Str ("GNATLS ");
1036       Write_Str (Gnat_Version_String);
1037       Write_Str (" Copyright 1997-2004 Free Software Foundation, Inc.");
1038       Write_Eol;
1039       Write_Eol;
1040       Write_Str ("Source Search Path:");
1041       Write_Eol;
1042
1043       for J in 1 .. Nb_Dir_In_Src_Search_Path loop
1044          Write_Str ("   ");
1045
1046          if Dir_In_Src_Search_Path (J)'Length = 0 then
1047             Write_Str ("<Current_Directory>");
1048          else
1049             Write_Str (To_Host_Dir_Spec
1050               (Dir_In_Src_Search_Path (J).all, True).all);
1051          end if;
1052
1053          Write_Eol;
1054       end loop;
1055
1056       Write_Eol;
1057       Write_Eol;
1058       Write_Str ("Object Search Path:");
1059       Write_Eol;
1060
1061       for J in 1 .. Nb_Dir_In_Obj_Search_Path loop
1062          Write_Str ("   ");
1063
1064          if Dir_In_Obj_Search_Path (J)'Length = 0 then
1065             Write_Str ("<Current_Directory>");
1066          else
1067             Write_Str (To_Host_Dir_Spec
1068               (Dir_In_Obj_Search_Path (J).all, True).all);
1069          end if;
1070
1071          Write_Eol;
1072       end loop;
1073
1074       Write_Eol;
1075    end if;
1076
1077    --  Output usage information when requested
1078
1079    if Print_Usage then
1080       Usage;
1081    end if;
1082
1083    if not More_Lib_Files then
1084       if not Print_Usage and then not Verbose_Mode then
1085          Usage;
1086       end if;
1087
1088       Exit_Program (E_Fatal);
1089    end if;
1090
1091    Initialize_ALI;
1092    Initialize_ALI_Source;
1093
1094    --  Print out all library for which no ALI files can be located
1095
1096    while More_Lib_Files loop
1097       Main_File := Next_Main_Lib_File;
1098       Ali_File := Full_Lib_File_Name (Lib_File_Name (Main_File));
1099
1100       if Ali_File = No_File then
1101          Write_Str ("Can't find library info for ");
1102          Get_Name_String (Main_File);
1103          Write_Char ('"');
1104          Write_Str (Name_Buffer (1 .. Name_Len));
1105          Write_Char ('"');
1106          Write_Eol;
1107
1108       else
1109          Ali_File := Strip_Directory (Ali_File);
1110
1111          if Get_Name_Table_Info (Ali_File) = 0 then
1112             Text := Read_Library_Info (Ali_File, True);
1113
1114             declare
1115                Discard : ALI_Id;
1116                pragma Unreferenced (Discard);
1117             begin
1118                Discard :=
1119                  Scan_ALI
1120                    (Ali_File,
1121                     Text,
1122                     Ignore_ED     => False,
1123                     Err           => False,
1124                     Ignore_Errors => True);
1125             end;
1126
1127             Free (Text);
1128          end if;
1129       end if;
1130    end loop;
1131
1132    Find_General_Layout;
1133
1134    for Id in ALIs.First .. ALIs.Last loop
1135       declare
1136          Last_U : Unit_Id;
1137
1138       begin
1139          Get_Name_String (Units.Table (ALIs.Table (Id).First_Unit).Uname);
1140
1141          if Also_Predef or else not Is_Internal_Unit then
1142             if ALIs.Table (Id).No_Object then
1143                Output_Object (No_File);
1144             else
1145                Output_Object (ALIs.Table (Id).Ofile_Full_Name);
1146             end if;
1147
1148             --  In verbose mode print all main units in the ALI file, otherwise
1149             --  just print the first one to ease columnwise printout
1150
1151             if Verbose_Mode then
1152                Last_U := ALIs.Table (Id).Last_Unit;
1153             else
1154                Last_U := ALIs.Table (Id).First_Unit;
1155             end if;
1156
1157             for U in ALIs.Table (Id).First_Unit .. Last_U loop
1158                if U /= ALIs.Table (Id).First_Unit
1159                  and then Selective_Output
1160                  and then Print_Unit
1161                then
1162                   Write_Eol;
1163                end if;
1164
1165                Output_Unit (Id, U);
1166
1167                --  Output source now, unless if it will be done as part of
1168                --  outputing dependencies.
1169
1170                if not (Dependable and then Print_Source) then
1171                   Output_Source (Corresponding_Sdep_Entry (Id, U));
1172                end if;
1173             end loop;
1174
1175             --  Print out list of units on which this unit depends (D lines)
1176
1177             if Dependable and then Print_Source then
1178                if Verbose_Mode then
1179                   Write_Str ("depends upon");
1180                   Write_Eol;
1181                   Write_Str ("   ");
1182
1183                else
1184                   Write_Eol;
1185                end if;
1186
1187                for D in
1188                  ALIs.Table (Id).First_Sdep .. ALIs.Table (Id).Last_Sdep
1189                loop
1190                   if Also_Predef
1191                     or else not Is_Internal_File_Name (Sdep.Table (D).Sfile)
1192                   then
1193                      if Verbose_Mode then
1194                         Write_Str ("   ");
1195                         Output_Source (D);
1196
1197                      elsif Too_Long then
1198                         Write_Str ("   ");
1199                         Output_Source (D);
1200                         Write_Eol;
1201
1202                      else
1203                         Write_Str (Spaces (1 .. Source_Start - 2));
1204                         Output_Source (D);
1205                         Write_Eol;
1206                      end if;
1207                   end if;
1208                end loop;
1209             end if;
1210
1211             Write_Eol;
1212          end if;
1213       end;
1214    end loop;
1215
1216    --  All done. Set proper exit status
1217
1218    Namet.Finalize;
1219    Exit_Program (E_Success);
1220 end Gnatls;